STM32: 利用高级定时器产生6路互补PWM波形输出在BLDC中H-PWM-L-ON驱动方式下驱动无刷电机

原文网址:http://jingyan.eeboard.com/article/73847#/prettyPhoto%5Bpp_gal%5D/6/

http://jingyan.eeboard.com/article/73852


STM32的MCU产品自带定时器资源十分丰富,既有专门用于电机控制的高级定时器(TIMER1/TIMER8),又有仅定时用的基本定时器(TIMER6/TIMER7) 和通用定时器(TIMER2/3/4/5/14/15/16/17) ,还有2个看门狗定时器和一个Systick定时器,真是十分强大哈。

这一篇文章就来讲解一下利用高级定时器TIMER1产生6路互补PWM波形输出。第一部分讲解用到的定时器基本内容和定时器库函数介绍;第二部分,讲解6路互补PWM输出的代码实现。

一、PWM和STM32-072RB定时器及库函数内容介绍

脉宽调制(PWM:(Pulse Width Modulation)是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术,广泛应用在从测量、通信到功率控制与变换的许多领域中。简易理解,就是对输出脉冲高低电平宽度的调制!STM32-072RB MCU 有12个定时器,其中有高级定时器、通用定时器和基本定时器及系统定时器。在这其中,有一个高级定时器TIMER1可以产生7路PWM(CH1/CH2/CH3/CH4/CH1N/CH2N/CH3N), 通用定时器TIMER2/TIMER3可以分别产生4路PWM (CH1/CH2/CH3/CH4),通用定时器TIMER15能产生3路 PWM(CH1/CH2/CH1N),通用定时器TIMER14/TIMER16/TIMER17各能产生1路PWM(CH1),这样,总共能产生 21路PWM。

高级定时器TIMER1专为电机控制而生,可以产生3对6路互补PWM输出,还带有死区时间设置和刹车功能。要利用STM32的定时器来产生PWM,需要用到定时器相关的寄存器。这些寄存器在下面内容介绍。对于不同的定时器,所在时钟总线是不同的,高级定时器是APB2时钟总线提供时钟,其它通用定时器是APB1时钟总线提供时钟。

STM32的定时器主要参数跟下面三个定时器有关,学习前要先看一下

TIMx_CCMRx 寄存器:选择PWM模式

TIMx_ARR 寄存器: PWM的周期

TIMx_CCRx 寄存器: PWM占空比

下面看一下定时器详细库函数资源介绍:

1、定时器结构体成员变量

产生PWM,要用到三个结构体,分别是

TIM_TimeBaseInitTypeDef基本定时结构体

TIM_OCInitTypeDef输出比较结构体

TIM_BDTRInitTypeDef刹车和死区配置结构体

利用三个库函数来实现将结构体赋值到STM32内部寄存器中

TIM_TimeBaseInit (); TIM_OCInit () TIM_BDTRConfig()

下面分别看一下三个结构体的定义:

这三个结构体具体内容看一下stm32f0xx_tim.h文件。下面看一下几个常用的定时器库函数

TIM_OCxPreloadConfig ();

TIM_ARRPreloadConfig ();

TIM_Cmd();

TIM_CtrlPWMOutputs();

TIM _ITConfig ();

TIM_ARRPreloadConfig ();

TIM_ForcedOC1Config ();

TIM_GetITStatus ()

TIM_ClearITPendingBit()

TIM_CCPreloadControl();

TIM_SelectOCxM();

TIM_CCxCmd();

TIM_CCxNCmd();

TIM_GenerateEvent();

通过这些库函数来配置出PWM波形。下面看一下在STM32-NUCLEO-072开发平台上PWM输出引脚的配置。

2、PWM引脚配置

在STM32F072RBT6上采用了TIMER1高级定时器的3对6路引脚(CH1/CH1N,CH2/CH2N,CH3/CH3N)分别是PA8/PA9/PA10 和/PB13/PB14/PB15

在硬件上是这样:

下面看一下具体的代码实现。

二、Keil-mdk工程文件及代码实现

1、Keil-mdk工程模板中加入PWM.C文件,在includes.h文件中加入PWM.H头文件

2、在PWM.H头文件实现宏定义

3、6路PWM引脚端口初始化PWM_GPIO_Init()代码实现

4、高级定时器初始化Timer1_Init()代码实现

这个就是对定时器三个结构体的配置,这里采用了简单的公式,实现PWM周期和占空比的设置。这里显示是8KHZ,三路占空比30%,40%和50%。

这个就是对端口和三个定时器相关结构体的配置。

5、主函数代码main.c代码实现

在main.c里面加入定时器初始化代码,上电复位后,就可以输出6路PWM波形了。下面的图片是利用示波器的数字通道采集的波形图。





BLDC又称直流永磁电机,或永磁同步电机,采用电机控制器通过电子控制分配方式实现换向!直流无刷电机广泛应用于汽车、工具、工业工控、自动化以及航空 航天等行业!目前BLDC电机应用十分广泛,采用MCU输出6路PWM波形控制三相H桥电路驱动BLDC是一种十分重要的技术应用。在带HALL的BLDC中,常根据HALL值的变化,采用六步换向法来驱动三相H桥。这里面最常用的PWM控制方式就是H-PWM, L-ON的方式,也就是上桥臂MOS管上输出PWM,下桥臂MOS管保持常ON的方式。这一篇文章就来讲解一下H-PWM-L-ON驱动方式下的6路PWM波形输出,如有对BLDC驱动感兴趣,可以基于STM32-NUCLEO-072RB开发平台做一个扩展板,上面加载三相H桥电路和反馈电路进行深入测试。第一部分内容讲解一下带HALL的BLDC换向表分析。第二部分内容讲解一下代码实现。

一、带HALL的BLDC换向表分析

在带HALL的BLDC中,一般是由霍尔传感器测量转子的位置,然后由其输出的3位二进制编码去控制逆变器中6个功率管的导通实现换相。

下图是一个HALL传感器在电机转动一周的情况下输出值:

HALLA/B/C输出的值并不是安装顺序排列,而是安装0x05、0x04、0x06、0x02、0x03、0x01的方式出现。如果采集到的HALL值是反向顺序,则说明电机是反向转动了。

下面是利用示波器采集到的BLDC的HALL值输出:

下面是常用的三相H桥逆变电路:

根据六步换向原则,每步三个绕组中一个绕组流入电流,一个绕组流出电流,一个绕组不导通。确定通电顺序如下:

1.A+C-2.C+B-3.A+B-4.B+A-5. B+C-6.C+A-

每步磁场旋转60°,每6步磁场旋转一周,每步仅一个绕组被换相。

这样,在电机正转情况下,根据HALL值来确定的导通相和驱动管导通情况如下:

要想实现在HALL值出现时的驱动管导通相,6路PWM引脚必须提前一相配置下一个导通相的状态,并将参数存储在定时器的影子寄存器中,通过COM事件的产生,同步更新定时器各个PWM引脚的配置。下面是针对定时器要实现的预配置通道及导通相配置。

在设置参数中,要利用到STM32的COM事件:

COM事件是专门为电机控制用的,它只出现在高级定时器中!“当在一个通道上需要互补输出时,预装载位有OCxM、CCxE和CCxNE。在发生COM换相事件时,这些预装载位被传送到影子寄存器。这样你就可以预先设置好下一步骤配置,并在同一个时刻同时修改所有通道的配置。COM可以通过设置TIMx_EGR寄存器的COM位由软件产生,或在TRGI上升沿由硬件产生。” COM事件的触发有两种方式,一种是软件触发:利用库函数实现;另一种是硬件触发:利用STM32 定时器霍尔接口实现,由霍尔值改变来产生上升沿触发

下面讲解一下具体的软件实现过程。

二、Keil-mdk工程文件及代码实现

1、Keil-mdk工程模板中加入PWM.C文件,在includes.h文件中加入PWM.H头文件

2、在PWM.H头文件增加宏定义 --霍尔传感器引脚PC6/PC7/PC8

3、霍尔传感器接口 HALL_GPIO_Init()函数代码实现

霍尔传感器电路是一种OC门电路,需要增加上拉电阻才能有输出,在配置引脚端口时,可以内部不增加上拉,浮空即可。

霍尔传感器电路结构和霍尔接口电路

4、高级定时器初始化Timer1_Init()代码实现

配置好定时器,初始化是配置在定时模式,不能输出PWM,否则有容易引起MOS管短路的风险。

5、换向函数实现:BLDC_Hall_Convet()

这个是根据HALL值来进行换向,因为没用硬件H桥电路,这里仅是手动转动电机实现换向,所以COM事件通过软件来产生。

其他霍尔值的配置类似。

6、中断复位函数实现:

在COM事件中断中,进行换向判定:

7、主函数代码main.c代码实现

在main.c里面初始化定时器配置后,就要对电机HALL值进行判断,然后设置不同的PWM输出。

打印输出的HALL值:

实际输出的H-PWM-L-ON波形与STM32技术参考手册波形是一致的


  • 9
    点赞
  • 140
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
以下是一个简单的stm32f1无刷电机BLDC驱动程序: ``` #include "stm32f10x.h" #define A_H GPIO_Pin_0 #define A_L GPIO_Pin_1 #define B_H GPIO_Pin_2 #define B_L GPIO_Pin_3 #define C_H GPIO_Pin_4 #define C_L GPIO_Pin_5 #define TIM_PERIOD 1000 uint16_t pwm_duty = 0; void TIM2_IRQHandler(void) { if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) { TIM_ClearITPendingBit(TIM2, TIM_IT_Update); if (pwm_duty < TIM_PERIOD) { pwm_duty++; } else { pwm_duty = 0; } if (pwm_duty < TIM_PERIOD / 3) { GPIO_SetBits(GPIOA, A_H); GPIO_ResetBits(GPIOA, A_L); GPIO_SetBits(GPIOB, B_H); GPIO_ResetBits(GPIOB, B_L); GPIO_SetBits(GPIOC, C_H); GPIO_ResetBits(GPIOC, C_L); } else if (pwm_duty < TIM_PERIOD * 2 / 3) { GPIO_ResetBits(GPIOA, A_H); GPIO_SetBits(GPIOA, A_L); GPIO_SetBits(GPIOB, B_H); GPIO_ResetBits(GPIOB, B_L); GPIO_SetBits(GPIOC, C_H); GPIO_ResetBits(GPIOC, C_L); } else { GPIO_ResetBits(GPIOA, A_H); GPIO_SetBits(GPIOA, A_L); GPIO_ResetBits(GPIOB, B_H); GPIO_SetBits(GPIOB, B_L); GPIO_SetBits(GPIOC, C_H); GPIO_ResetBits(GPIOC, C_L); } } } int main(void) { // 初始化GPIO口 GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC, ENABLE); GPIO_InitStructure.GPIO_Pin = A_H | A_L; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = B_H | B_L; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = C_H | C_L; GPIO_Init(GPIOC, &GPIO_InitStructure); // 初始化定时器 TIM_TimeBaseInitTypeDef TIM_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); TIM_InitStructure.TIM_Period = TIM_PERIOD - 1; TIM_InitStructure.TIM_Prescaler = 72 - 1; TIM_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_InitStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, &TIM_InitStructure); TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); TIM_Cmd(TIM2, ENABLE); NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); while (1) { } } ``` 该程序使用TIM2定时器断来控制电机的三相电流输出。在断处理函数,使用PWM占空比来控制电机转速。具体来说,当PWM的占空比小于1/3时,A相为正,B相为正,C相为正;当PWM的占空比在1/3和2/3之间时,A相为负,B相为正,C相为正;当PWM的占空比大于2/3时,A相为负,B相为正,C相为负。根据BLDC电机的工作原理,这些输出组合将导致电机的转子按照正确的方向旋转。 需要注意的是,该程序仅提供了非常基本的电机控制方法,并且没有实现任何保护机制。在实际应用,还需要考虑电机过流、过热等问题,并相应地实现保护机制。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值