当前位置: 首页 > news >正文

STM32电机控制基础知识

1. 前言

        电机控制是嵌入式领域中一个前景广阔的专业方向。然而,面对繁杂的理论与实践,许多初学者常常感到无从下手。因此本篇文章将以STM32的标准库驱动直流有刷电机为例,分享一些电机控制的基础知识,希望可以给大家做一个参考。

2. 电机控制外设--高级定时器

        一般而言,电机控制都是通过定时器输出PWM来进行控制的。而在STM32中,有高级定时器和通用定时器之分,高级定时器相较于普通定时器,多了互补输出和带死区刹车控制等功能,因此电机控制通常用高级定时器来进行控制。接下来先对高级定时器的互补输出、死区、刹车输入等基础知识进行介绍。

2.1 互补输出

        在之前学习的STM32基础定时器知识中,可以通过定时器的某个通道CHX输出PWM波形。而在高级定时器中,每个CHX通道(x取1,2,3,4),存在着对应的CHXN通道,该通道称为互补输出通道,如下图所示:

        红色的波形代表CHX通道,绿色的波形代表CHXN通道。当CHX通道输出高电平时,CHXN输出低电平,这就称为互补输出。

2.2 死区

        带死区控制的互补输出指的是在CHX和CHXN输出的高低电平转换的等待时间,这段时间称为死区时间,只有死区时间过后,才能实现互补输出,如下图:

        那为什么需要这段死区时间呢?答案还需要借助电机H桥来进行说明,带死区控制的互补输出通常用于电机控制的H桥中,H桥的简化示意图如下所示:

        如上图H桥的原理表述为:Q1-Q4都是NPN型三极管。当采用互补输出时,OC1输出高电平期间,OCIN输出低电平。那么OC1输出高电平让Q1和Q4导通(原理看模电知识,此处不过多解释),那么此时电流经VCC流经Q1-->电机-->Q4-->GND,此时电机转动(假设正转);而OC1N输出高电平时,此时OC1输出低电平,此时Q2、Q3导通,Q1和Q4截止,电流方向相反,电机反转。

        但是当没有死区时间时,在OC1和OC1N的高电平--低电平(或者是低电平--高电平)转换期间,三极管由于关断不及时(关断是需要时间的),这就会造成H桥的同一侧三极管同时导通,此时会让VCC直接与GND连接,造成短路!因此,需要在两个通道进行高低电平转换的时候插入死区时间,等待三极管到达稳定状态,再进行互补输出。

        那又出现了新的问题,如何去计算这段死区时间呢?答案就在STM32高级定时器的寄存器中,一般使用CR1的CKD位和BDTR寄存器的UTG位来进行死区时间设置的,如下图所示:

        举个例子:当UTG位的值为250时,250 的二进制数为11111010,即UTG[7:5]为111,所以选择第四条公式:DT=(32+ DTG[4:0]) * Tdtg,其中Tdtg = 16 * TDTS。而TDTS的值为CKD位的选择,如CKD=10时,此时为4分频。

2.3 刹车输入

        刹车的概念即是字面意思,当配置一个IO口为刹车输入时,如果刹车有效,此时CHX和CHXN通道就不会输出PWM信号去驱动电机转动,此时电机就会慢慢停止。这就称为刹车,它也是由BDTR寄存器来进行设置的,如下图:

        可见,当刹车输入有效时,此时MOE位会被硬件清零,此时会禁止OC和OCN输出或强制为空闲状态。

3. 编写互补输出驱动

        在了解上述原理后,接下来使用STM32F103标准库编写驱动函数,代码如下所示:

/*IO初始化函数*/
void io_set(gpioled port,u16 pin,GPIOMode_TypeDef mode)
{GPIO_InitTypeDef  GPIO_InitStructure;if(port==GPIOA) RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); else if(port==GPIOB) RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);else if(port==GPIOC) RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);else if(port==GPIOD) RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);else if(port==GPIOE) RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);else if(port==GPIOF) RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF, ENABLE);else if(port==GPIOG) RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG, ENABLE);GPIO_InitStructure.GPIO_Pin = pin;  GPIO_InitStructure.GPIO_Mode = mode;  		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(port, &GPIO_InitStructure);			//初始化GPIO
}/*
*@breif:带刹车输入的死区互补输出
*@para:u16 arr
*@para:u16 psc
*@para:u16 ccr
*@para:u16 dtg
*@return:none
*/
void TIM1_dead_pwm_init(u16 arr,u16 psc,u16 ccr,u16 dtg)
{TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;TIM_OCInitTypeDef  TIM_OCInitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);	//使能定时器1时钟io_set(GPIOA,GPIO_Pin_8,GPIO_Mode_AF_PP);				//C1io_set(GPIOB,GPIO_Pin_13,GPIO_Mode_AF_PP);				//C1Nio_set(GPIOB,GPIO_Pin_12,GPIO_Mode_IPU);				//刹车输入io初始化,上拉输入//初始化TIM1TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV4; //CKD[1:0] = 10, tDTS = 4 * tCK_INTTIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式1TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCPolarity_High; //互补输出极性:TIM输出比较极性高TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;	//互补输出使能TIM_OCInitStructure.TIM_Pulse = ccr;						//设置占空比TIM_OC1Init(TIM1, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM2 OC1TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);  //使能TIM1在CCR上的预装载寄存器/*设置刹车*/TIM_BDTRStructInit(&TIM_BDTRInitStructure);									//填充BDTR初始默认值,初始化TIM_BDTRInitStructure.TIM_DeadTime=dtg;										//设置死区时间TIM_BDTRInitStructure.TIM_Break = TIM_Break_Enable;							//使能刹车输入TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_Low; 			// BKIN 低电平触发刹车TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;		//使能AOE位,刹车结束后恢复输出TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure);								//BDTR初始化TIM_CtrlPWMOutputs(TIM1, ENABLE);											//使能MOE位TIM_Cmd(TIM1, ENABLE);  													//使能TIM1
}

        驱动编写分为以下几个步骤。首先对定时器时钟使能(此处使用的是高级定时器TIM1);其次对CH1、CH1N以及刹车输入引脚进行初始化;设置定时器自动重装值及psc进行定时器初始化;接下来设置PWM模式,并且设置CH1、CH1N的输出极性及输出使能。

        Note:此处的CH1和CH1N的输出极性都设置成高,不能一个设置成高,另一个设置成低,否则会造成CH1和CH1N同时输出高/低电平。原因是:当CH1设置为高有效,CH1N设置成低有效时,假如在PWM1模式,此时CNT<CCR的时候CH1输出有效电平为1,此时其互补输出CH1N应该为无效电平,但CH1的无效电平还是1,即同时输出高电平(但测试的时候发现都设置成低电平有效时也会出现该问题)。

        最后,设置死区刹车。先设置刹车时间、使能刹车输入,将刹车输入设置成低电平有效;使能AOE位,即当刹车结束后可以恢复互补输出功能;TIM_CtrlPWMOutputs函数设置MOE位为1,此时才能实现互补输出,最后使能TIM1即可。

4. 直流有刷电机

        在了解高级定时器的互补输出使用基础知识之后,接下来看一下如何通过互补输出去驱动直流有刷电机转动。

        直流有刷电机BDC是一种内含电刷装置,可以将直流电能转换成机械能的电动机。 其结构由定子、转子、电刷和换向器组成。其中,定子用于产生固定的磁场,通常由永磁体或电磁绕组制成;转子由一个或多个铜线绕组构成,通电后可以在磁场中受力运动;电刷指的是将外部电流输入到转子绕组上;换向器用于改变转子绕组中电流的流向。了解结构之后来看一下直流有刷电机的工作原理。

4.1 直流有刷电机工作原理

        其原理本质上是通电导线在磁场中受力运动,因此需要通过左手定则来进行判断(是否感觉到死去的高中物理知识在攻击你)。左手定则是判断通电导线处于磁场中时,所受安培力 F (或运动)的方向、磁感应强度B的方向以及通电导体棒的电流I三者方向之间的关系的定律。 左手定则的具体内容:将左手四指并拢伸直,使拇指与其他四指在平面内垂直,手掌方向 代表磁场的方向(从N级到S级),四指代表电流的方向(从正极到负极),那拇指所指的方向就是受力的方向,如下图所示:

        知道左手定则后,来看直流有刷电机的简化示意图,如下所示:

        由图可见,当电流从C端流入,D端流出时;此时根据左手定则可知a1a2线圈往上运动,b2b1线圈往下运动;当整个线圈转动90°后,此时换向器C和D的位置交换,那么此时电流从D端流入,C端流出,导致线圈继续沿着原来的方向受力转动,这就是直流有刷电机基本工作原理。

        那么从上可知,电机想要调节速度时,即调节线圈的受力大小,也就是调节电流大小(即调节电源电压大小);电机想要换向时即调节电流方向。了解直流有刷电机的基本工作原理之后,接下来依然使用H桥电路(见2.2章节)来进行电机驱动。

4.2 直流有刷电机方向及速度控制原理

        H桥电路可方便对电机的正反转方向及速度进行控制,具体原理如下:电机方向控制原理不再过多叙述(见2.2章节);电机调速原理是固定一路输入信号的电平,另一路信号利用PWM波作为输入,这样即可调节驱动板输出到电机的电压,从而实现电机的速度控制。波形如下所示:

        具体来说,比如CH1固定为高电平时,CH1N输出PWM波,当CH1N为低电平周期时,此时电机会转动;这时CH1N转换为高电平周期时,由于CH1和CH1N都输出高电平,那么此时电机就会减速,但由于惯性电机不会立即停止。因此,可通过调节CH1N的PWM占空比来实现速度控制,即占空比越大,高电平周期越长,电机转动的就慢。

        综上,可通过TIM1_CH1(主通道)输出PWM波,TIM1_CH1N(互补通道)固定输出高电平(后续讲如何实现),此时只要调节主通道输出的 PWM 占空比即可调整电机上的电压,进而控制电机的速度。当电机需要换向的时候,我们就让主通道固定输出高电平,互补通道输出PWM即可。

5. 编写直流有刷电机驱动程序

        了解上述直流有刷电机的调速、换向原理之后,接下来先介绍电机调速时如何让某通道固定输出高/低电平。根据直流有刷电机调速原理,需要将一路输出固定电平,另外一路输出PWM波。为了方便同时对方向和速度进行控制,采用高级定时器的互补输出方式。但互补输出是主通道输出PWM方波时,互补通道输出相反的PWM方波。那如何做到在主通道输出PWM方波时,互补通道固定输出一个高电平或者低电平呢?

        答案还是藏在BDTR的寄存器的OSSR位和OSSI位里,如下图:

        上图中OSSR位代表的是当OSSR=1,定时器在运行模式下(计数使能的状态)如果突然关闭了互补输出中的某个通道(CCXE或CCXNE=0),那么此时被关闭通道的CH1或者CH1N将输出无效电平;同理,OSSI位代表的是定时器在空闲模式下(定时器不工作),如果设置为1,关闭对应通道时,对应通道输出空闲电平(具体看CR2寄存器,此处不过多展开)。更加具体来说,手册中表75对OSSR和OSSI的设置状态做了总结,如下图:

        知道如何做到让互补输出的通道输出固定电平之后,接下来介绍驱动程序的编写,代码如下:

*直流有刷电机驱动*/
void TIM1_dead_pwm_init(u16 arr,u16 psc,u16 ccr,u16 dtg)
{TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;TIM_OCInitTypeDef  TIM_OCInitStructure;TIM_BDTRInitTypeDef TIM_BDTRInitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);	//使能定时器1时钟io_set(GPIOA,GPIO_Pin_8,GPIO_Mode_AF_PP);				//C1io_set(GPIOB,GPIO_Pin_13,GPIO_Mode_AF_PP);				//C1Nio_set(GPIOB,GPIO_Pin_12,GPIO_Mode_IPU);				//刹车输入io初始化,上拉输入//初始化TIM1TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV4; //CKD[1:0] = 10, tDTS = 4 * tCK_INTTIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式1TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCPolarity_High; //互补输出极性:TIM输出比较极性高TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;	//互补输出使能TIM_OCInitStructure.TIM_Pulse = ccr;						//设置占空比TIM_OC1Init(TIM1, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM2 OC1TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);  //使能TIM1在CCR上的预装载寄存器/*设置BDTR*/TIM_BDTRStructInit(&TIM_BDTRInitStructure);									//填充BDTR初始默认值,初始化TIM_BDTRInitStructure.TIM_DeadTime=dtg;										//设置死区时间TIM_BDTRInitStructure.TIM_OSSRState=TIM_OSSRState_Enable;					//OSSR位设置为1TIM_BDTRInitStructure.TIM_OSSIState=TIM_OSSIState_Disable;					//OSSI位设置为0TIM_BDTRInitStructure.TIM_Break = TIM_Break_Disable;						//注意在本功能中没有用到刹车TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_Low; 			// BKIN 低电平触发刹车TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;		//使能AOE位,刹车结束后恢复输出TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure);								//BDTR初始化TIM_CtrlPWMOutputs(TIM1, ENABLE);											//使能MOE位TIM_Cmd(TIM1, ENABLE);  													//使能TIM1
}/*电机停止*/
void motor_stop(void)
{TIM_CCxCmd(TIM1,TIM_Channel_1,TIM_CCx_Disable);		//关闭CH1通道PWM输出TIM_CCxNCmd(TIM1,TIM_Channel_1,TIM_CCx_Disable); 	//关闭CH1N通道PWM输出
}/*电机方向设置*/
void motor_dir(u8 para)
{TIM_CCxCmd(TIM1,TIM_Channel_1,TIM_CCx_Disable);		//关闭CH1通道PWM输出TIM_CCxNCmd(TIM1,TIM_Channel_1,TIM_CCx_Disable); 	//关闭CH1N通道PWM输出if (para == 0)                /* 正转 */{TIM_CCxCmd(TIM1,TIM_Channel_1,TIM_CCx_Enable);     //开启主通道输出 } else if (para == 1)           /* 反转 */{TIM_CCxCmd(TIM1,TIM_Channel_1,TIM_CCx_Enable);     //开启互补通道输出}
}/*电机速度调节*/
void motor_speed(u16 ccr)
{if(ccr<1000)	/*限速*/{TIM_SetCompare1(TIM1,ccr);	//调节占空比}
}

        由上可见,初始化函数与定时器的互补输出驱动函数差不多,主要是增加了OSSR、OSSI的设置。此处将OSSR设置为1,OSSI设置为0。

        接下来看电机停止函数,电机停止函数主要是将CH1和CH1N两个通道进行关闭(需要注意本功能没有使用刹车输入实现电机停止),当两个通道关闭后,根据表75可知,OSSR为1,MOE=1(初始化函数中设置了),CCXE=CCXEN=0,此时禁止输出。

        电机方向设置函数:先将两个通道都进行关闭,每次只打开一个通道,关闭一个通道;根据表75可知,此时会让一方输出固定电平,一方输出PWM信号。如此轮换,即可让电机换向。

        最后是电机速度调节函数,调节PWM的占空比即可。

6. 参考文献

        [1] STM32中文参考手册V10;

        [2] DMF407电机控制_V1.0;

        [3] STM32F103开发指南;

        [4] STM32F103C8T6数据手册;

        

http://www.dtcms.com/a/439098.html

相关文章:

  • 算法题(225):樱花
  • 做互联网的网站app客户端网站建设方案
  • 网站描述 关键词上海 有哪些做网站的公司
  • 计算机网络技术电商网站建设与运营方向怎么投放广告
  • 低空经济新纪元:AI驱动的智能无人机技术与应用
  • 专业建站分销商城a wordpress
  • 创建一个顺序栈,并实现基础的“出栈入栈”功能(C++版)
  • 定制手机壳的网站广州冼村旧改最新消息
  • 怎么做淘宝客网站备案网站后台的形成
  • wordpress安装后查看站点失败河北平台网站建设
  • 网站专题页制作网站备案关闭影响排名
  • Python Flask框架深度解析:从入门到高级
  • 网站销售的优势生鲜做的好的网站
  • 中企动力做的网站怎么登陆运城市住房与城乡建设厅网站
  • 香橙派RK3588s部署大模型
  • 【自记】数据开发中分区表、事务表、分区事务表:特性相似处与区别
  • ATMS课程管理系统 - 从零构建的MySQL实战之旅
  • 广东东莞自己建站教程做网站设计的公司叫什么
  • 网站站外引流怎么做西安动力无限网站建设
  • 智能交通顶刊TITS论文分享|一种可以提高车辆轨迹预测精度和稳定性的稀疏时空Transformer模型
  • 福州专业网站设计团队seo排名优化公司
  • 进入WSL2 Ubuntu环境的完整指南
  • 龙岗网站建设公司效果河南建筑官网首页
  • 网站前置审批怎么进网站源码的后台
  • 电商网站建设考试题网站头部优化文字怎么做
  • php做网站有哪些好处界面官方网站
  • perror与stderr:错误处理的“诊断专家“与“急诊通道“
  • 小公司做网站需要什么条件绿茶直播
  • import-route direct 概念及题目
  • K230基础-图像绘制