电机的基本认识
这里呢,平衡小车最常用到的是直流编码有刷电机,直流的意思是使用直流电,给引脚通的是恒定电流;编码指的是电机自带编码盘,上面有两个相位正交的编码器,可以利用四倍频技术实现对电机位置和转速的精确追踪;有刷指的是电机内部自带换向器,电机转子每旋转180度,线圈中的电流即自动换向,不需要软件或者硬件驱动的控制。
这种电机通常有6个引脚:电源引脚:5V、GND,PWM输入引脚:IN1、IN2,编码器输出引脚:OUT1、OUT2。
PCB走线时要注意只有编码器引脚是信号线,可以走细一些,其他线建议走粗一些(30mil以上)。
电机驱动:TB6612
由于STM32的引脚只能提供3.3V电压,且功率输出能力很弱,因此需要功率放大器件对电机进行控制,并且为了保持控制的实时性,以及精准性,需要高速的功率控制器件,这就需要一款专用的电机驱动芯片。
这里使用体积较小,同时有较大驱动能力的TB6612驱动芯片,可以同时驱动两路电机,利用其内部的高速H桥,向电机输出PWM波,控制其正传,反转,制动,自由转动(不加动力也不加阻尼力),以及转速的调节。
驱动芯片除了电源引脚以及使能引脚之外,还有各两组,两种功能的引脚:
来自MCU的3个引脚:1个PWM输入引脚,用于控制转速,2个控制引脚,用于控制正反,制动,空挡(不施加力)。
输出给电机的2个引脚:OUT1,OUT2,通过输出PWM波控制电机的全部功能,搭载较大电流。
驱动编写
通过对电机以及电机驱动的功能分析,我们知道了控制1个电机,需要3个引脚,1个输出PWM波用于控制速度,2个高速推挽输出,通过切换高低电平,即可实现对电机的驱动状态控制。
平衡车有2个电机需要控制,因此用于驱动电机的引脚有6个,2个是定时器的PWM功能映射的引脚。
这里我为了节省定时器资源,使用一个定时器TIM1,该定时器的1、4通道(分别对应PA8,PA11引脚),来输出两路频率相同,但是占空比互不影响,独立可调的PWM信号,然后另外找4个普通IO口,用于对电机状态进行控制。
电机驱动
MOTOR.h
#ifndef __MOTOR_H
#define __MOTOR_H
#include #define PWMA TIM1->CCR1 //用于控制A电机的PWM占空比调节 #define AIN2 PBout(15) #define AIN1 PBout(14) #define PWMB TIM1->CCR4 //用于控制B电机的PWM占空比调节 #define BIN1 PBout(13) #define BIN2 PBout(12) void MiniBalance_PWM_Init(u16 arr,u16 psc); void MiniBalance_Motor_Init(void); #endif 这里干了几件事: 电机控制引脚宏定义 PWM占空比改变宏定义 两个初始化函数宏定义 MOTOR.c 首先是对4个控制引脚的初始化,高速下拉推挽输出: #include "MOTOR.h" TIM_HandleTypeDef TIM1_Handler = {0}; //定时器1句柄 TIM_OC_InitTypeDef TIM1_CH14Handler = {0}; //定时器1通道14句柄 void MiniBalance_Motor_Init(void) //完成4个控制引脚的初始化 { GPIO_InitTypeDef GPIO_Initure = {0}; //声明初始化结构体 __HAL_RCC_GPIOB_CLK_ENABLE(); //开启GPIOB时钟 GPIO_Initure.Pin = GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15; //端口配置 GPIO_Initure.Pull = GPIO_NOPULL; GPIO_Initure.Mode = GPIO_MODE_OUTPUT_PP; //推挽输出 GPIO_Initure.Speed = GPIO_SPEED_FREQ_HIGH; //50M HAL_GPIO_Init(GPIOB, &GPIO_Initure); //根据设定参数初始化GPIOB } 然后是对PWM外设的初始化,这里用定时器1的1、4通道,映射到PA8和PA11两个引脚用来控制两个电机的转速: //TIM1 PWM初始化 //arr:自动重装值。 //psc:时钟预分频数 //定时器溢出时间计算方法:Tout=((arr+1)*(psc+1))/Ft us. //Ft=定时器工作频率,单位:Mhz void MiniBalance_PWM_Init(u16 arr,u16 psc) //完成两个PWM输出引脚的初始化 { TIM1_Handler.Instance=TIM1; //定时器1 TIM1_Handler.Init.Prescaler=psc; //定时器分频 TIM1_Handler.Init.CounterMode=TIM_COUNTERMODE_UP; //向上计数模式 TIM1_Handler.Init.Period=arr; //自动重装载值 TIM1_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1; HAL_TIM_PWM_Init(&TIM1_Handler); //初始化PWM TIM1_CH14Handler.OCMode=TIM_OCMODE_PWM1; //模式选择PWM1 TIM1_CH14Handler.Pulse= 0; //设置比较值,初始占空比设为0 TIM1_CH14Handler.OCPolarity=TIM_OCPOLARITY_HIGH; //输出极性 高电平有效 HAL_TIM_PWM_ConfigChannel(&TIM1_Handler,&TIM1_CH14Handler,TIM_CHANNEL_1);//初始化TIM1,PWM通道1、4 HAL_TIM_PWM_ConfigChannel(&TIM1_Handler,&TIM1_CH14Handler,TIM_CHANNEL_4);//初始化TIM1,PWM通道1、4 HAL_TIM_PWM_Start(&TIM1_Handler,TIM_CHANNEL_1); //开启PWM通道1、4 HAL_TIM_PWM_Start(&TIM1_Handler,TIM_CHANNEL_4); //开启PWM通道1、4 } 在HAL_TIM_PWM_Init()中会调用端口初始化MSP函数,需要用户重定义覆盖HAL库的若定义函数: //定时器底层驱动,时钟使能,引脚配置 //此函数会被HAL_TIM_PWM_Init()调用 //htim:定时器句柄 void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim) { GPIO_InitTypeDef GPIO_Initure; if(htim->Instance==TIM1) { __HAL_RCC_TIM1_CLK_ENABLE(); //使能TIM1时钟 __HAL_AFIO_REMAP_TIM1_PARTIAL(); //TIM1通道引脚部分重映射使能 __HAL_RCC_GPIOA_CLK_ENABLE(); //开启GPIOA时钟 GPIO_Initure.Pin=GPIO_PIN_8|GPIO_PIN_11; //PA8 PA11 GPIO_Initure.Mode=GPIO_MODE_AF_PP; //复用推挽输出,用于输出PWM GPIO_Initure.Pull=GPIO_PULLDOWN; //下拉 GPIO_Initure.Speed=GPIO_SPEED_FREQ_HIGH;//高速 HAL_GPIO_Init(GPIOA,&GPIO_Initure); } } 然后是中断服务函数,等等,我们设置了自动重装填,不需要中断控制,OK结束。 如何使用电机:实践 控制集成封装 这里集成了控制小车所需的代码,现在只添加电机控制这一模块 CONTROL.h #ifndef __CONTROL_H #define __CONTROL_H #include "sys.h" void Set_Pwm(int moto1,int moto2); int myabs(int a); //绝对值函数 #endif 两个函数,核心是第一个,设置PWM的重装填阈值,相当于控制了占空比,这样就实现了调速的功能。 CONTROL.c #include "CONTROL.h" /************************************************************************** 函数功能:赋值给PWM寄存器 入口参数:左轮PWM、右轮PWM 返回 值:无 **************************************************************************/ void Set_Pwm(int moto1,int moto2) { int siqu=500;//死区补偿,防止数值过小无法驱动 if(moto1<0) BIN2=0, BIN1=1; //正转 else BIN2=1, BIN1=0; //反转 PWMB=myabs(moto1)+siqu; if(moto2<0) AIN1=0, AIN2=1; //正转 else AIN1=1, AIN2=0; //反转 PWMA=myabs(moto2)+siqu; } /************************************************************************** 函数功能:绝对值函数 入口参数:int 返回 值:unsigned int **************************************************************************/ int myabs(int a) { int temp; if(a<0) temp=-a; else temp=a; return temp; } 上面这个是实现功能的函数,Set_pwm函数是根据TB6612电机驱动芯片的真值表来计算的,通过直接访问TIM1的CCR寄存器,注意考虑两个电机的中心对称分布,所以写的时候将一个反向,实现输入两个正数,两个电机的转动都使小车向前走即可。 mian函数: //头文件略去 int main(void) { HAL_Init(); Stm32_Clock_Init(RCC_CFGR_PLLMULL9); JTAG_Set(SWD_ENABLE); //uart_init(115200); delay_init(72); KEY_Init(); MiniBalance_Motor_Init(); MiniBalance_PWM_Init(7199,0); //PWM输出,溢出值7200,不分频,10KHz频率,100um周期 while(1) { Set_Pwm(3000, 3000); delay_ms(1000); Set_Pwm(-3000, -3000); delay_ms(1000); } } 这里放了一个最简单的一秒正转,一秒反转,因为还没有研究PID的原理,后面会结合MPU6050触发中断来进行数据处理,反馈给电机,来进行最基本的控制。网上找不到HAL库的历程,就搞来FW3.5标准库来研究,慢慢摸索终于把这电机弄转起来了,实现了多轮运动嘿嘿。
上一篇:stm32和电机开发(开篇)
下一篇:STM32嵌入式显示器:首款搭载 STM32H7 的高清屏幕
推荐阅读最新更新时间:2024-11-12 23:54
设计资源 培训 开发板 精华推荐
- AKD4118A-A,AK4118 数字音频收发器评估板
- AM6TW-4818DZ ±18V 6 瓦单输出 DC-DC 转换器的典型应用
- TB62726N 16位恒流LED驱动器典型应用,工作电压为3.3V
- LT3957EUHE、5V 至 16V 输入、-12V 输出反相转换器的典型应用电路
- KIT10XS3425EVBE,具有 MC10XS3425 四通道高边开关的评估板
- 用于 SMPS 电源的 L6566B 多模式控制器的典型锁存关断电源过压应用
- DS51220C,使用 MCP3004 的演示板,12 位,100-KSPS,4CH/8CH 模数转换器子板
- KIT908-5643EVM: 面向MPC5643L和MC33908 SBC的评估系统
- 使用 NXP Semiconductors 的 PCAL6416A 的参考设计
- 使用 TC7116A 模数转换器实现二极管或电阻器限制封装功耗的典型应用
- 劳动节归来,EEWORLD社区4月明星人物出台喽!
- jameswangsynnex带你进入智能电网世界
- 有奖直播:ADI在中国能源互联网应用中的技术及产品 1月8日上午10:00-11:30 准时开启!
- 答题赢好礼|以人为本、生命无价 ADI 楼宇烟雾探测技术
- 有奖直播报名:TI DLP®技术在汽车行业的创新应用——增强型抬头显示
- 有奖直播:安世半导体先进 SiC MOSFET 助力提升 EV-Charger 和 OBC 应用能效
- 有奖直播报名:ADI 语音交互系统方案
- 有奖直播:TI DLP® 产品赋能工业光控领域与创新
- 挑战极限,你敢看吗?下载文档+观看视频,了解航空和政府应用解决方案
- 为“ADI实验室电路”寻建议!