600字范文,内容丰富有趣,生活中的好帮手!
600字范文 > STM32驱动直流电机的程序与电路设计(IR2110S自举电路+H桥+高级定时器和死区PWM)

STM32驱动直流电机的程序与电路设计(IR2110S自举电路+H桥+高级定时器和死区PWM)

时间:2023-07-05 04:38:09

相关推荐

STM32驱动直流电机的程序与电路设计(IR2110S自举电路+H桥+高级定时器和死区PWM)

本文介绍如何使用STM32F103单片机,通过官方固件库,设置高级定时器TIM1输出嵌入死区的互补PWM,来驱动直流电机的程序设计与电路设计。硬件电路采用IR2110S芯片作为mos管的驱动,驱动IRF840组成的H桥。IR2110S芯片使用中,有一个比较难理解的点——自举电容,本文对其原理也有涉及。

原理图文件

上图是系统的简化原理图,左侧是单片机。中间是IR2110S芯片,为了方便讲解,把芯片内部结构列出一些。右侧是MOS管组成的H桥。其中M是直流电机,有正反转。其中VCC是15V,MOTOR_VCC是24V,电压可以改变,最大不超过500V。单片机一般是3.3V或5V,无法直接驱动电机。可以借助H桥来实现对直流电机的控制。

H桥由于形似H得名。

VT1,VT4导通,电机正转

VT2,VT3导通,电机翻转

VT1,VT3导通,短路,板子烧坏

VT2,VT4,导通短路。

所以,驱动电机的问题就变成了MOS管导通的问题。

实际电路中我选用了IRF840,这是N沟道的MOS管。N-MOS导通的条件:VGS大于一定值

对于IRF840,VGS>10V

所以MOS管导通的问题就变成了VGS>10V的问题

如果,VT1与VT3都独立配置一个电源,独立配置一套驱动,导通问题就变得简单了。但是,电路设计会变得复杂。

我们使用1个驱动芯片IR2110S,一路驱动电源。

简单介绍下IR2110S芯片

IR2110是独立一桥臂双通道,栅极驱动,高压,高速单片机专用功率器件集成驱动电路。2片IR2110就能构成H桥驱动电路。

IR2110S是3.3V版本

感兴趣的可以自己来做个阅读理解。

简单来说,IR2110是个3.3V控制10-20V的一个驱动。开关速度也很快,120ns

内部结构

右上角的两个MOS管,中间是非门连接,不会同时导通。

中间一系列怎么变化,我也不是很清楚。

HIN是1,VM1导通,VM2截止。VB与HO连在一起

HIN是0,VM1截止,VM2导通。VS与HO连在一起

LIN是1,VM3导通,VM4截止。VCC与LO连在一起

LIN是0,VM3截止,VM4导通。LO与COM连在一起

先看下桥臂。左侧下桥臂导通,很简单:

LIN为高,VM3导通,VCC接在LO上(暂时忽略二极管压降),VGS= VCC,导通

上桥臂导通的情况,先假设没有电容。

VM1导通时,VCC接在HO上,为G极提供了接近15V的电压。但是,VS的电压是多少?不知道。

如果,VT3导通,VS就是0,VT1也导通了,烧坏。

如果VT4导通,VS通过电机接地(电机内部可以先等效为电阻)。但是VT1导通以后,VS接近24V,HO只有15V,VT1又截止了。电机还是不能工作。

我们面临的问题是,上桥臂没有地。怎么办?

这个时候,就需要自举电容。

VT4导通,VS接地。电容一端是地,一端是15V,所以VCC通过D给C充电。

又因为VM1导通,所以C横跨在GS上。所以,C可以作为电压源,为GS供电。这是一个悬浮的电压源。

VT1导通后,VS接近24V,不再是地。所以VCC15无法为G提供足够的电压。

自举电容可以放电维持VT1工作,电容存有15V的电,可以保持MOS管的导通。由于电容两极的压差不能突变,而电容下边变成了对地24V(暂不考虑MOS管压降),所以这一瞬间,电容上边的电压是对地39V。这时,VCC无法为电容充电。由于二极管的存在,电容的电不会倒灌给VCC。

电容电量又是有限的,放电会导致电容的电压降低。等到两级压差不到10V的时候,VT1又不工作了。并且,此时IR2110芯片内部的欠压检测逻辑就会工作,把HO拉到VS,让VGS=0。

所以,自举电容电压小于10V之前,要充电。如果HIN一直是高电平,电容就没有充电的机会,等到自举电容的的电压跌落到某个阈值以下,HO就变为低电平。

此时可以关掉VT1,也就是断开VM1,VB与HO断开,不论是VCC还是电容都不再为G极提供电源。如果此时打开VT3,让VS接地,则电容一边是高电平,一边是低电平,开始充电。然后再断开VT3,打开VM1,VT4保持不变,让电容放电维持VT1导通,就可以循环往复,保持电机运行。

即,VT1的导通要依靠电容放电来维持。HIN不能为持续的高电平,占空比也不能达到100,或低频的PWM(频率低,一个周期内放电时间长)。必须是高频的PWM,保证自举电容有周期性的,足够的充电时间,才能维持较高的悬浮电源电压。

除此之外,还要注意死区问题,由于绝对不可以把同侧桥臂的上下半桥同时打开,而IR2110S,MOS管与电机切换状态都存在延时,导致从程序命令某半桥关断,到实际关断,有一段时间的延迟。例如,在延迟期间,上半桥正在关闭,下半桥暂时还不能打开,直到上半桥完全关闭,下半桥才能打开。中间等待的这段时间,就是死区。死区时间与硬件密切相关。笔者手上就有两个不同型号的电机,一个在3us的死区时可以工作,另一个则不可以。

所以,写程序要注意到上下桥不能同时导通,高频,不能是100的占空比,以及死区这几个问题。接下来尝试用STM32的高级定时器,输出嵌入死区的互补PWM。

以下是定时器1的初始化代码,使用两个通道输出PWM,一个周期是100us,频率是10KHz,3us的死区时间。默认通道一的占空比是50%,通道2的占空比是0%,让电机以47%(占空比减去死区)的速度正转。

通道2输出占空比是0,可以让右侧上半桥总是截止,下半桥总是导通。下半桥没有自举电容。如此一来,只需要左侧上半桥导通,就可以让电机正转。控制左侧桥臂的占空比,就能控制电机的占空比。

定时器1的通道1引脚是PA8PB13,通道2的输出引脚是PA9PB14。

void PWM_Configuration(void){GPIO_InitTypeDef GPIO_InitStructure;TIM_TimeBaseInitTypeDef TIM_BaseInitStructure;TIM_OCInitTypeDef TIM_OCInitStructure;TIM_BDTRInitTypeDef TIM_BDTRInitStructure;NVIC_InitTypeDef NVIC_InitStructure;//开启TIM和相应端口时钟//启动GPIORCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB,ENABLE);//启动AFIORCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);//启动TIM1RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);//GPIO做相应设置,为AF输出 //PA8,PB13一组互补输出 A9,PB14一组互补输出//PA.8/9口设置为TIM1的OC1输出口GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);//PB.13/14口设置为TIM1_CH1N和TIM1_CH2N输出口GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_SetBits(GPIOA, GPIO_Pin_8 | GPIO_Pin_9);GPIO_SetBits(GPIOB, GPIO_Pin_13 | GPIO_Pin_14);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure);//TIM1基本计数器设置(设置PWM频率)10KHz TIM_BaseInitStructure.TIM_Period = 100-1;//10khz 好计算。按照1%的精确度,理论最大72000/100 = 720KHzTIM_BaseInitStructure.TIM_Prescaler = 72-1;TIM_BaseInitStructure.TIM_ClockDivision = 0;TIM_BaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数TIM_BaseInitStructure.TIM_RepetitionCounter = 0;TIM_TimeBaseInit(TIM1, &TIM_BaseInitStructure);//启用ARR的影子寄存器(直到产生更新事件才更改设置)TIM_ARRPreloadConfig(TIM1, ENABLE);//TIM1_OC1模块设置(设置1通道占空比)TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//TIM脉冲宽度调制模式1TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//输出通道使能TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;//互补输出TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;//TIM输出比较极性高//TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;TIM_OCInitStructure.TIM_Pulse = 50;//待装入捕获比较寄存器的脉冲值TIM_OC1Init(TIM1, &TIM_OCInitStructure);//启用CCR1寄存器的影子寄存器(直到产生更新事件才更改设置)TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);//TIM1_OC2模块设置(设置2通道占空比)TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;TIM_OCInitStructure.TIM_Pulse = 0;TIM_OC2Init(TIM1, &TIM_OCInitStructure);//启用CCR2寄存器的影子寄存器(直到产生更新事件才更改设置)TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable);//OCx输出信号与参考信号相同,只是它的上升沿相对参考信号的上升沿有一个延迟//OCxN输出信号与参考信号相同,只是它的上升沿相对参考信号的下降沿有一个延迟//死区设置TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable;TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable;TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_2;//bit7~5 = 111,则deadtime = (32 + (bit4~bit0)* 16*1/fosc)ns = (32+31)*16*1/72000000 = 14usTIM_BDTRInitStructure.TIM_DeadTime = 0xab; //这里调整死区大小0-0xff3usTIM_BDTRInitStructure.TIM_Break = TIM_Break_Disable;TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High;TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure);//TIM1_OC通道输出PWMTIM_CtrlPWMOutputs(TIM1, ENABLE);//TIM1开启TIM_Cmd(TIM1, ENABLE);}

从上图中,可以清楚地看到,单片机输出的上、下桥臂控制信号,不存在同时为高电平的时候,也就是同侧上下桥臂不会同时导通。切换状态时,某半桥臂的控制信号拉低3us以后,另半桥臂的控制信号才能拉高,这就是所谓的带死区的互补PWM。

上图是输出的电机控制电压。可以看出周期是100us,高电平持续时间大约一半。

初始化之后,在程序运行时,可以调用

TIM_SetAutoreload(TIM1,xx);

来设置自动重装值。在初始化的时候把此值设置为了100,如果改为80,效果如下:

可以看出,一个周期变成了80us。

也可以使用函数

TIM_SetCompare1(TIM1,xx);TIM_SetCompare2(TIM1,xx);

来分别为通道1与通道2设置比较值。例如,把比较值设置为80,而自动重装值还是100,那么占空比就是80%了。

下边是用按键控制电机的一个小demo。实现了按键1启停,按键2切换正反转,按键34增减转速的功能。

int main(void){ static u8 motorValue = 50,oldvalue = 50;static u8 startStop = 1,dir = 1;//startStop = 1启动 =0停止 dir =1 正转volatile u8 key = 0;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级LED_Init();KEY_Init();delay_init();PWM_Configuration();Motor_IO_Init();LED1 = LED_ON;while(1) {key = KEY_Scan(0);if(key){switch(key){case KEY1_PRES:startStop = !startStop;break;case KEY2_PRES:dir = !dir;break;case KEY3_PRES:motorValue += 5;break;case KEY4_PRES:motorValue -= 5;break;default:break;}if(motorValue>249)//<0motorValue = 0;else if(motorValue >94)motorValue = 94;if (startStop){if(dir){TIM_SetCompare2(TIM1,0);delay_ms(500);TIM_SetCompare1(TIM1,motorValue);}else{TIM_SetCompare1(TIM1,0);delay_ms(500);TIM_SetCompare2(TIM1,motorValue); }}else{TIM_SetCompare1(TIM1,0);TIM_SetCompare2(TIM1,0);} }}}//S1 启动&停止 S2翻转 S3+5 S4-5

完整的原理图文件在这里

新增了一个用集成芯片的驱动方案链接

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。