基于STM32的直流电机PWM调速控制Word下载.docx
《基于STM32的直流电机PWM调速控制Word下载.docx》由会员分享,可在线阅读,更多相关《基于STM32的直流电机PWM调速控制Word下载.docx(18页珍藏版)》请在冰点文库上搜索。
功率管导通期间,驱动电路提供的基极电流在任何负载情况下都能保证功率管处于饱和导通状态,使功率管的饱和压降较低,以保证低的导通损耗;
关断瞬时,驱动电路应提供足够的反向基极驱动,以迅速抽出基区的剩余载流子,并加反偏截止电压,使集电极电流迅速下降以减少下降时间。
为了增加系统的抗干扰能力,STM32输出的6路PWM信号首先必须经隔离再送到IR2136进行驱动,由于开关速度达到20KHz左右,故设计中选用高速光耦器件HCPL4504,见图3,其最高速度可达1Mbit/s,内部的噪声抑制电路可提供高于15kV/us的共模抑制。
IR2136是IR公司的一款功率MOSFET、IGBT专用栅极驱动集成电路,独有的I-IVIC(Highvoltageintegratedcircuit)技术使得它可用作驱动工作在母线电压高达600V的电路中的功率MOS器件。
其内部采用自举技术,使得功率驱动元件驱动电路仅需输入一个直流电源,使其实现对功率MOSFET和IGBT的最优驱动,并且它还具有完善的保护功能包括欠压保护和过流保护,以便保证系统安全稳定的工作。
故本文选用IR2136作为主功率部分的MOSFET驱动,如图3所示:
图3中经IR2136驱动的6路PwM信号被直接送到由6个MOSFET管组成的主功率电路。
如图所示,该功率驱动采用三相全控电路,电动机的三相绕组为Y型联结。
MOSFET管选用IR公司的IRFZ48,该管导通电阻较低,当连续流过10A电流时,功耗才1.2w,根本不需要散热片就可以稳定工作。
图3功率驱动电路
2.3直流无刷电机的调速
直流无刷电机调速的原理就是在驱动电机转动的基础上,将驱动电流由PWM信号来控制,改变PWM信号的脉冲宽度,即通过调节MOSFET通断的时间来调节提供给电机三相的电流大小,从而对电机进行调速控制。
本方案中MOSFET管的导通是通过STM32的PWM信号来控制的,STM32内部的普通的定时器TIM3和TIM4,每个可以产生四路PWM发生器,这里用TIM3产生4路,TIM4产生两路,共六路可编程的PWM信号,驱动H桥。
直流无刷电机的电子换向是基于转子的位置来控制的,本系统采用3个霍尔传感器对直流无刷电机进行位置测量霍尔传感器安装在电机的内部,将转子的位置转换为三路数字信号直接输出到STM32的GPIO口在本设计中可方便地用于通过检测霍尔位置传感器的信号来实现检测转子的位置,然后据此输出相应的PWM信号控制功率管的导通或关断,从而实现电流的换向,在电机内部产生一个转动的磁场,进而驱动电机旋转。
另外,车把转动的时候会通过一个DA转换,然后得到调速的标志flag的值,从而根据这个flag值来改变PWM波的占空比,从而进行电机的调速。
直流无刷电机旋转时三个霍尔传感器的信号值和输出的PWM信号之间的对应关系如图4所示
图4相位和PWM信号的对应关系
霍尔传感器的位置反馈信号在可以确定转子位置的同时,也可用来测量电机的转速电机每转动一周,每个霍尔传感器即会产生两次换向,三个霍尔传感器共会有6次换相,这六次换相之间的时间差即为电机运转一周所需的时间,继而可计算出电机的转速根据计算出的电机转速,调整PWM信号的脉冲宽度,从而达到调速的目的
3.系统软件设计
本系统编程部分工作在keil4开发环境下完成,采用模块化的设计方法,和各子程序作为实现各部分功能和过程的入口,完成PWM脉宽调速的控制。
STM32F103资源分配如下表:
表1芯片的资源分配
GPIOD4
霍尔传感器输出端
GPIOA6
利用定时器TIM3,TIM4产生的六路PWM输出
GPIOA7
GPIOD5
GPIOB0
GPIOB1
GPIOD6
GPIOB6
GPIOB7
1.PWM产生程序:
本设计中采用STM32F103的定时器TIM3,TIM4两个定时器来产生PWM波形,程序函数如下:
#include"
timer.h"
//通用定时器中断初始化
//这里时钟选择为APB1的2倍,而APB1为36M
//arr:
自动重装值。
//psc:
时钟预分频数
//这里使用的是定时器3
voidTimerx_Init(u16arr,u16psc)
{
RCC->
APB1ENR|=1<
<
1;
//TIM3时钟使能
TIM3->
ARR=arr;
//设定计数器自动重装值//刚好1ms
TIM3->
PSC=psc;
//预分频器7200,得到10Khz的计数时钟
//这两个东东要同时设置才可以使用中断
DIER|=1<
0;
//允许更新中断
6;
//允许触发中断
CR1|=0x01;
//使能定时器3
MY_NVIC_Init(1,3,TIM3_IRQChannel,2);
//抢占1,子优先级3,组2
}
voidPWM1_1_Init(u16arr1,u16psc1)
{
//此部分需手动修改IO口设置
//TIM3时钟使能
GPIOA->
CRL&
=0XF0FFFFFF;
//PA6输出
CRL|=0X0B000000;
//复用功能输出
ODR|=1<
//PA6上拉
ARR=arr1;
//设定计数器自动重装值
PSC=psc1;
//预分频器不分频
CCMR1|=7<
4;
//CH1PWM2模式
CCMR1|=1<
3;
//CH1预装载使能
CCER|=1<
//OC1输出使能
CR1=0x8000;
//ARPE使能
//使能定时器3
}
voidPWM1_2_Init(u16arr2,u16psc2)
=0X0FFFFFFF;
//PA7输出
CRL|=0XB0000000;
7;
//PA7上拉
ARR=arr2;
PSC=psc2;
//预分频器不分频
12;
//CH2PWM2模式
11;
//CH2预装载使能
//OC2输出使能
//使能定时器3
}
voidPWM1_3_Init(u16arr3,u16psc3)
//TIM3时钟使能
GPIOB->
=0XFFFFFFF0;
//PB0输出
CRL|=0X0000000B;
//PB0上拉
ARR=arr3;
PSC=psc3;
CCMR2|=7<
//CH3PWM2模式
CCMR2|=1<
//CH3预装载使能
8;
//OC3输出使能
voidPWM1_4_Init(u16arr4,u16psc4)
//TIM3时钟使能
=0XFFFFFF0F;
//PB1输出
CRL|=0X000000B0;
//PB1上拉
ARR=arr4;
PSC=psc4;
//CH4PWM2模式
//CH4预装载使能
//OC4输出使能
voidPWM2_1_Init(u16arr5,u16psc5)
2;
//TIM4时钟使能
//PB6输出
//PB6上拉
TIM4->
ARR=arr5;
PSC=psc5;
//使能定时器4
voidPWM2_2_Init(u16arr6,u16psc6)
//PB7输出
//PB7上拉
ARR=arr6;
PSC=psc6;
//使能定时器4
2、霍尔传感器部分的程序
huoer.h"
voidhuoer_Init(void)
APB2ENR|=1<
5;
//使能PORTD时钟
GPIOD->
=0XF000FFFF;
//PD4,5,5设置成输入
CRL|=0X08880000;
//PD4上拉
//PD5上拉
//PD6上拉
3、延时程序
#include<
stm32f10x_lib.h>
delay.h"
staticu8fac_us=0;
//us延时倍乘数
staticu16fac_ms=0;
//ms延时倍乘数
//初始化延迟函数
//SYSTICK的时钟固定为HCLK时钟的1/8
//SYSCLK:
系统时钟
voiddelay_init(u8SYSCLK)
SysTick->
CTRL&
=0xfffffffb;
//bit2清空,选择外部时钟HCLK/8
fac_us=SYSCLK/8;
fac_ms=(u16)fac_us*1000;
}
//延时nms
//SysTick->
LOAD为24位寄存器,所以,最大延时为:
//nms<
=0xffffff*8*1000/SYSCLK
//对72M条件下,nms<
=1864
voiddelay_ms(u16nms)
{
u32temp;
LOAD=(u32)nms*fac_ms;
//时间加载(SysTick->
LOAD为24bit)
VAL=0x00;
//清空计数器
CTRL=0x01;
//开始倒数
do
{
temp=SysTick->
CTRL;
}
while(temp&
0x01&
&
!
(temp&
(1<
16)));
//等待时间到达
CTRL=0x00;
//关闭计数器
VAL=0X00;
//清空计数器
//延时nus
//nus为要延时的us数.
voiddelay_us(u32nus)
{
LOAD=nus*fac_us;
//时间加载
VAL=0x00;
//开始倒数
//清空计数器
4、主程序
sys.h"
intmain(void)
u8flag;
//DA转换过来的调速标志
Stm32_Clock_Init(9);
//系统时钟设置
delay_init(72);
//延时初始化
PWM1_1_Init(900,0);
//不分频。
PWM频率=72000/900=8Khz
PWM1_2_Init(900,0);
PWM1_3_Init(900,0);
PWM1_4_Init(900,0);
PWM2_1_Init(900,0);
PWM2_2_Init(900,0);
while
(1)
switch(flag)
{
case0:
PWM1_VAL=900;
PWM2_VAL=900;
PWM3_VAL=900;
PWM4_VAL=900;
PWM5_VAL=900;
PWM6_VAL=900;
break;
case1:
if((huoer1==1)&
(huoer3==0))PWM1_VAL=300;
elsePWM1_VAL=900;
if((huoer1==0)&
(huoer2==1))PWM2_VAL=300;
elsePWM2_VAL=900;
if((huoer2==0)&
(huoer3==1))PWM3_VAL=300;
elsePWM3_VAL=900;
(huoer3==1))PWM4_VAL=300;
elsePWM4_VAL=900;
if((huoer1==1)&
(huoer2==0))PWM5_VAL=300;
elsePWM5_VAL=900;
if((huoer2==1)&
(huoer3==0))PWM6_VAL=300;
elsePWM6_VAL=900;
case2:
(huoer3==0))PWM1_VAL=350;
elsePWM1_VAL=900;
(huoer2==1))PWM2_VAL=350;
(huoer3==1))PWM3_VAL=350;
(huoer3==1))PWM4_VAL=350;
(huoer2==0))PWM5_VAL=350;
(huoer3==0))PWM6_VAL=350;
case3:
(huoer3==0))PWM1_VAL=400;
(huoer2==1))PWM2_VAL=400;
(huoer3==1))PWM3_VAL=400;
(huoer3==1))PWM4_VAL=400;
(huoer2==0))PWM5_VAL=400;
(huoer3==0))PWM6_VAL=400;
case4:
(huoer3==0))PWM1_VAL=450;
(huoer2==1))PWM2_VAL=450;
(huoer3==1))PWM3_VAL=450;
(huoer3==1))PWM4_VAL=450;
(huoer2==0))PWM5_VAL=450;
(huoer3==0))PWM6_VAL=450;
case5:
(huoer3==0))PWM1_VAL=500;
(huoer2==1))PWM2_VAL=500;