ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

STM32驱动TT马达完整指南:PWM调速、驱动模块选型与故障排查

STM32驱动TT马达完整指南:PWM调速、驱动模块选型与故障排查 很多朋友学STM32的过程是这样的流水灯、按键、蜂鸣器都玩明白了下一步就想让东西动起来。最常见的“第一次运动目标”就是桌上那个带着白色小齿轮的TT马达。但我在各种技术群里见过太多人用杜邦线把电机正负极直接怼在STM32开发板的3.3V和GND上结果电机纹丝不动有人还顺带把板子搞到反复复位。其实TT马达这个项目难点不在接线有多复杂而在于很多人没意识到它是一套完整的“功率驱动系统”而不是一个单纯的“IO控制问题”。这篇文章会从驱动一颗最普通的TT马达出发把电机选型逻辑、驱动电路原理、STM32的PWM配置、实测排错以及双电机差速的基础全部过一遍。适合手上有STM32开发板、准备做小车底盘或机械臂关节的读者。哪怕你是刚点完灯的小白跟着一步步走也能把电机转起来如果你已经在做小车后半部分关于供电干扰和闭环调速的内容也值得看。1. 先搞清楚TT马达是什么参数、减速比和选型逻辑1.1 我买的是“减速电机”不是裸电机很多人第一次拿到TT马达都会觉得它有点胖因为里面其实装了两样东西一个永磁直流电机本体加一组塑料减速齿轮箱。TT马达的核心结构基本是“130电机 减速箱”输出轴上还有配套的塑料轮子或联轴器。这个结构直接决定了它的电气参数和行为特性工作电压通常是3V到6V最常用5V或者两节18650串联的7.4V要用DC-DC降到6V以内比较稳妥空载电流一般在150mA到250mA左右带负载会明显上涨堵转电流可以到1A甚至2A以上这是选电源和驱动芯片时最重要的参考值输出转速不取决于电机本身而取决于减速比常见的有1:48、1:75、1:120等。不要小看“堵转电流”这个参数。很多新手把电机卡住之后看到电源指示灯变暗或者开发板重启就是没有算清这个电流。驱动芯片的峰值能力、电池放电能力、导线截面积都要按这个级别去留余量。1.2 减速比怎么选直接决定你车子跑得快还是爬得动电机本体的转速实际上非常高常见微型直流电机空载转速在8000到15000rpm之间扭矩却小得可怜手指轻轻一按就能停。减速箱的作用是把高转速转换成低转速同时把扭矩放大近似关系是输出扭矩≈电机扭矩×减速比×传动效率TT马达减速箱的传动效率大概在50%到80%之间别按理想值算。选减速比不能拍脑袋建议按目标车速反着算一遍。假设你做一台两轮小车轮子直径65mm希望最高车速0.5m/s那么车轮转速r/min速度×60÷π×直径0.5×60÷3.14×0.065≈147rpm如果选1:48减速比电机本体在5V下按空载8000rpm左右算带载后算7000rpm输出轴转速大约是146rpm刚好满足0.5m/s的需求。如果换成1:120输出只有58rpm左右车速连0.2m/s都到不了更适合爬坡或者越障类场景。反过来1:20虽然快但扭矩小平地跑还行上坡会显得没劲。所以买电机之前一定先问自己一句我要它跑得快还是拉得动TT马达虽然便宜但不同减速比的齿轮组不通用买错了只能重新下单。1.3 TT马达的三类变体买的时候别买错市面上常见三类TT马达外观几乎一样但内部反馈方式完全不同普通TT马达只有两根电源线没有反馈控制方式就是开环PWM便宜够用带霍尔编码器的TT马达除了电源线还多出一组信号线通常是AB两相或者单相脉冲能测转速和方向适合做速度闭环带减速比标识的版本商家会在标题写“1:48带编码器”下单前看清楚。如果打算做小车我建议直接买带霍尔编码器的1:48版本可能只贵几块钱但后面做PID闭环、走直线都会省事很多。普通版适合练手但跑到后面大概率会后悔。2. 为什么STM32的GPIO不能直接驱动TT马达2.1 电流不够GPIO本质上是个信号引脚不是电源引脚STM32的GPIO在推挽输出模式下理论上最大源电流和灌电流是25mA左右但实际稳定输出一般按10mA到20mA用。TT马达空载电流就150mA起步启动瞬间可能冲到几百毫安甚至1A差了至少一个数量级。硬接的结果是电流拉不上去电机不转如果电机堵转了芯片引脚内部有可能过流损坏。这就好比你想用家里的网线去给电热水壶供电线不是断的是本身就承载不了这么大的电流结果只能发热甚至烧毁。2.2 感性负载的反电动势会打穿引脚直流电机内部是线圈绕组属于典型的感性负载。感性负载有一个特性电流不能突变。PWM关断的瞬间电机线圈会通过自感产生一个反向高压这就是反电动势。这个电压可能达到几十伏远远超过STM32引脚的耐压范围哪怕只是一瞬间也可能让GPIO内部电路永久损坏。所以驱动电路中一定要有续流路径。如果只用单个MOS管或三极管至少要在电机两端反向并联一个续流二极管最省心的方案是直接使用带H桥续流逻辑的集成功率驱动芯片内部已经把这个问题处理好了。2.3 驱动方案的三个层次新手别跳级从最简单的到最完整的驱动一颗TT马达通常有三条路第一层单个NPN三极管或MOS管加续流二极管只能控制转速不能换向一般用于“只需要转起来”的简单场景。第二层H桥驱动电路四个开关管组成桥式结构可以控制正转、反转、刹车和惰转。这是学习电机控制最经典的结构市面上几乎所有的电机驱动模块都是这个方案的集成版本。第三层集成功率驱动芯片比如TB6612FNG、DRV8833、L298N等。芯片内部已经集成了H桥、续流二极管和保护逻辑你只需要给逻辑电平信号就能控制方向给PWM就能调速。我建议新手直接上第三层也就是买现成的驱动模块。自己用四个MOS管搭H桥不是不行但走线寄生电感、栅极驱动电压、死区控制这些问题处理不好很容易出现诡异故障。先把系统跑通再回头啃硬件细节学习效率高得多。3. 驱动模块选型与接线L298N、TB6612、DRV8833怎么挑3.1 三款常见驱动模块的“脾气”对比市面上驱动TT马达最常见的模块主要有三款参数差异很大选错了会带来一堆莫名其妙的坑。项目L298NTB6612FNGDRV8833MX1508电机供电电压5V-12V推荐7V以上2.7V-13.5VVM2.7V-10.8V3V-8V逻辑电压5V不支持3.3V直连2.7V-5.5V3.3V可用2.7V-5.5V3.3V可用3V-5V3.3V可用单路连续电流约2A约1.2A峰值3.2A约1.5A峰值2A约1.5A导通压降较大约2V0.5Ω导通电阻低导通电阻低导通电阻体积大带散热片小小很小L298N是很多教程里的经典模块但不是TT马达的最佳选择。它的致命问题是导通压降太大如果电机供电只有5V输出到电机上的电压可能只有3V左右转速明显偏低。而且L298N的逻辑部分需要5V供电STM32的3.3V IO口虽然通常能识别但不够舒服。它更适合12V以上的大电机。TB6612FNG是我个人最推荐的一款。逻辑部分可以用3.3V直接驱动VM接电机电源VCC接逻辑电源封装小巧导通电阻低。DRV8833和MX1508也很类似但DRV8833稳定性和保护机制做得更好一点MX1508便宜到几块钱做小车上手非常快。3.2 驱动模块的逻辑引脚怎么控制真值表和PWM不管用哪款驱动模块控制逻辑都差不多以TB6612的一路电机为例AIN1AIN2PWMA电机状态10PWM正转速度由占空比决定01PWM反转速度由占空比决定11任意或高刹车急停00任意惰转惯性自由滑行注意AIN1和AIN2是方向控制电平PWMA是调速PWM。很多同学只设置方向不启动PWM电机当然不转也有同学只给PWM不设置方向模块内部逻辑不识别照样不转。如果你的驱动模块上只有IN1、IN2没有PWM脚那说明它可能把PWM直接绑在了使能端上这时IN1和IN2的输入组合基本就是全速正转或全速反转无法调速。买之前确认一下模块有没有独立的PWM引脚。3.3 接线时最容易被忽略的三个致命细节第一个细节是共地。驱动模块的GND必须和STM32的GND连在一起否则PWM信号和逻辑电平没有公共参考点芯片收不到正确的电平表现为“时转时不转”或者“完全不动”。我之前帮人排查过一个小车所有线都检查了没问题最后发现驱动模块和单片机各用各的电源、地线没连加一根杜邦线就解决了。第二个细节是VM和VCC别搞混。TB6612上面有一个VM电机电源输入、一个VCC逻辑电源输入VM接电池正极VCC接3.3V或5V两个都要接而且GND要统一。很多人只接了VM没接VCC或者反过来结果是模块根本没有正常工作。第三个细节是电机电源不要从STM32开发板上取。STM32开发板的3.3V是给芯片和传感器用的电流能力有限。电机启动电流一冲整板电压被拉低MCU直接复位。正确做法是电机单独用电池供电然后和STM32共地。后文第5章会专门讲这个问题的处理。4. STM32配置PWM输出CubeMX设置、代码编写与参数计算4.1 为什么调速要用PWM频率该选多少STM32的GPIO只能输出高电平或低电平没法直接输出一个稳定的中间电压。PWM的思路是快速地在高和低之间切换通过调整高电平占整个周期的比例占空比来改变平均电压。占空比60%时电机两端的平均电压就是供电电压的60%转速也大致按比例下降。那PWM频率选多少合适这里有个经验区间频率太低比如几十Hz电机会一顿一顿地转噪音也大频率到了几百Hz噪音变成刺耳的“吱吱”声转子输出扭矩波动变小常见直流电机驱动频率在1kHz到20kHz之间超过20kHz进入超声波范围人耳基本听不见噪音但驱动芯片开关损耗会增加而且定时器分辨率会下降。我个人做TT马达小车时习惯选10kHz左右听感可以接受参数计算也方便。下面这个公式是STM32定时器输出PWM频率的核心务必记住PWM频率定时器时钟频率÷预分频值1×自动重载值1在STM32F103上定时器时钟默认是72MHz。如果预分频PSC设为71自动重载ARR设为99那么频率72MHz÷72×10010kHz占空比比较值CCR÷ARR1ARR99意味着比较值可以设0-99刚好对应0%到99%的占空比和“0到100调速”的心智模型完美对应。4.2 CubeMX配置步骤从新建工程到波形输出我用STM32F103C8T6加TB6612举例单片机PA6输出PWM到PWMAPA0和PA1控制AIN1和AIN2。先在STM32CubeMX里做这几件事RCC页打开HSE外部高速时钟选Crystal/Ceramic ResonatorSYS页把Debug选成Serial Wire否则烧录一次之后可能会连不上芯片在Clock Configuration里把系统时钟配到72MHz左侧找到TIM3在Channel1处选择PWM Generation CH1然后在下方的Parameter Settings里设Prescaler为71Counter Period为99Pulse设为0把PA0、PA1配置为GPIO_Output初始电平都设为Low工程设置完成后Generate Code。生成完代码后在main函数用户代码区启动PWM输出。注意只用CubeMX配置不会自动开启PWM必须在代码里调用启动函数。4.3 电机控制代码一个函数搞定方向和速度拿到生成好的工程后在main.c的USER CODE区写下面这套代码。核心就三个动作设置方向、设置速度、启动PWM。/* USER CODE BEGIN 2 */ HAL_TIM_PWM_Start(htim3, TIM_CHANNEL_1); __HAL_TIM_SET_COMPARE(htim3, TIM_CHANNEL_1, 0); /* USER CODE END 2 */方向和速度控制函数我习惯放在main.c外单独维护但演示时可以直接写在用户区#define MOTOR_FORWARD 1 #define MOTOR_BACKWARD 0 void Motor_SetDir(uint8_t dir) { if (dir MOTOR_FORWARD) { HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET); } else { HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET); } } void Motor_SetSpeed(uint8_t speed) // speed范围0~99 { __HAL_TIM_SET_COMPARE(htim3, TIM_CHANNEL_1, speed); }然后主循环里先设方向再设速度while (1) { Motor_SetDir(MOTOR_FORWARD); Motor_SetSpeed(50); // 50%占空比 HAL_Delay(2000); Motor_SetDir(MOTOR_BACKWARD); Motor_SetSpeed(40); HAL_Delay(2000); }注意Motor_SetSpeed的参数不能超过ARR值99如果你在CubeMX里把ARR写成999那参数范围就是0到999代码和配置必须对应起来。这类“配置和代码不一致”的问题很隐蔽排查时经常会怀疑人生。4.4 如果用的是标准库或寄存器核心思路其实一样有不少同学还在用标准库尤其是江科大风格的标准库教程受众很多。其实换库不换思路核心就是三步初始化定时器时基初始化定时器输出比较通道为PWM模式运行时修改比较寄存器值来调速。标准库版本大概是这个样子TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; TIM_TimeBaseStructure.TIM_Prescaler 71; TIM_TimeBaseStructure.TIM_Period 99; TIM_TimeBaseInit(TIM3, TIM_TimeBaseStructure); TIM_OCInitStructure.TIM_OCMode TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState TIM_OutputState_Enable; TIM_OC1Init(TIM3, TIM_OCInitStructure); TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable); TIM_Cmd(TIM3, ENABLE);调速就一行函数调用TIM_SetCompare1(TIM3, 50);方向控制还是GPIO那套高低电平逻辑没什么变化。所以别太纠结HAL库还是标准库把PWM的原理吃透换什么库都只是语法翻译而已。5. 第一次上电实测检查顺序、故障排查与供电抗干扰5.1 上电前按这个顺序检查省得烧板子每次接完新电路我强烈建议不要直接写满占空比让电机全速转。按下面这个顺序来能省掉很多麻烦第一步不接电机先把驱动模块的VM和VCC接好用万用表量一下VM正负极之间的电压是否稳定确认电池有电且接线正确。第二步STM32单独上电用示波器或逻辑分析仪看PA6有没有PWM波形。没有示波器的话可以把占空比固定在一个值然后用万用表量PA6的电压占空比50%时电压应该是3.3V的一半左右也就是1.65V上下。这个检查能快速区分问题是出在单片机配置还是驱动电路。第三步把方向控制引脚PA0和PA1手动拉高拉低观察驱动模块的指示灯变化。多数模块会有电源或状态指示如果逻辑电平有变化但指示灯不反应大概率是共地或逻辑电压问题。第四步接上电机先用20%到30%占空比低速测试。如果低速不转不要立刻怀疑是模块坏了先手动转一下电机轴有些电机因为负载或者齿轮摩擦需要一定的启动电压低速PWM下确实转不起来这是正常的。5.2 常见故障排查表不转、抖动、反转、发热我整理了TT马达项目里最高频的一批故障现象排查顺序也按经验排好了现象可能原因排查与处理电机完全不转共地没接用万用表蜂鸣档测STM32和驱动模块GND是否连通电机完全不转方向引脚没设置确认AIN1和AIN2不是同为0或同为1电机完全不转PWM占空比为0确认调用过HAL_TIM_PWM_Start并设置了非零比较值电机只抖动不转占空比太低低于电机启动电压把占空比提到40%以上试一下电机只抖动不转PWM频率太低频率调到1kHz以上最好10kHz电机能转但反转电机两根线接反交换电机两根线或者改一下方向逻辑电机能转但发热严重负载过大或电压偏高降低供电电压减小占空比检查齿轮箱是否卡滞驱动芯片烫手电流超限或持续堵转立即断电检查电机是否被卡住降低负载STM32上电后重启电机启动瞬间拉低主电源独立供电共地并联电容用软启动速度不受PWM控制使能脚直接接了高电平把EN引脚接到单片机的PWM引脚上其中“只抖动不转”这个现象最有迷惑性。电机抖动说明已经在尝试转了但平均电压低时扭矩撑不住负载。你可以把占空比提高试试如果40%以上能稳定转那说明不是接线问题是软件初始化速度给太低了。5.3 电机启动导致STM32重启的供电问题这个问题几乎每个做小车的人都会遇到一次。现象是电机一转开发板上的电源灯闪一下然后程序从头执行OLED屏幕自己重启或者串口打印又出现了初始化的日志。根本原因是电机和单片机共用了同一个电源路径。TT马达启动电流在几百毫安到1A之间波动瞬间把电源电压拉低STM32的工作电压低于复位阈值就触发了欠压复位。解决办法按优先级排序第一电机用独立电池供电STM32和驱动模块之间只连GND和信号线这是最彻底的方案。第二如果只能用同一个电源在电机供电端并联一个大容量电解电容我建议至少470uF以上放得下一颗23mm直径的电容最好。电容的作用是提供一个瞬时电流的“蓄水池”缓冲电机启动时的大电流冲击。容值太小没效果太大也帮不了电池容量不足的问题。第三在软件上做PWM软启动不要上来就60%占空比。让占空比阶梯式上升电机缓慢加速峰值电流被拉平很多。void Motor_SmoothStart(uint8_t target_speed) { for (uint8_t i 0; i target_speed; i) { __HAL_TIM_SET_COMPARE(htim3, TIM_CHANNEL_1, i); HAL_Delay(1); } }5.4 一个容易被忽略的经验通着电别拆线最后说一个特别接地气的坑。TT马达的接线柱或杜邦线在电机运行时接触电阻大电流波动会让线头发热、氧化、接触不良。表现是测试时偶尔不转用手碰一下又好了时断时续。处理方法是断电状态下把每根线重新插紧电机端最好拧紧螺丝或者直接焊死。电机是运动部件走线会随着车身震动接触不良的故障排查起来比芯片问题难十倍。凡是到这一步直接把所有可疑的杜邦线换掉最有效。6. 从单电机到小车差速控制再到速度闭环6.1 双电机差速控制的基础逻辑单电机转起来之后很多人自然想把它装到车上。两轮差速小车是TT马达最经典的应用场景控制逻辑并不复杂。差速控制的核心思想是左右轮速度不同车身就会向速度慢的一侧转弯速度差越大转弯半径越小如果左右轮速度等大反向小车就能原地旋转。假设你的速度控制范围是-100到100负数为反转那么一组简单的控制函数长这样void Car_SetSpeed(int16_t left_speed, int16_t right_speed) { Motor_SetDir(MOTOR_LEFT, left_speed 0); Motor_SetDir(MOTOR_RIGHT, right_speed 0); Motor_SetSpeed(MOTOR_LEFT, abs(left_speed)); Motor_SetSpeed(MOTOR_RIGHT, abs(right_speed)); }直行就调用Car_SetSpeed(50, 50)右转就Car_SetSpeed(35, 60)左转就Car_SetSpeed(60, 35)。试几次就能找到合适的差速值。这里会有个让新手很头痛的现象明明写了左右轮都是50%占空比车跑出去却是歪的。原因通常是左右两个电机出厂参数不完全一致或者两边减速箱摩擦不同。开环控制很难让两个轮子精确同步这正是下一步闭环要解决的问题。6.2 加编码器做速度闭环要想让车走直线得让两个轮子的实际转速一致而不是“给定占空比”一致。这就需要一个速度反馈元件也就是带霍尔编码器的TT马达。TT马达的编码器通常输出AB两路脉冲信号相位差90度单片机通过判断A相和B相的先后顺序就能同时得到转速和方向。STM32的定时器有编码器模式AB两相接到同一个定时器的两个输入通道硬件直接根据相位自动加减计数完全不需要中断或者外部脉冲计数效率非常高。在CubeMX里把TIM2或TIM3设置为Encoder Mode两个通道分别接编码器A、B相然后通过读取定时器计数寄存器就能获得单位时间内的脉冲数再除以单位时间就是转速。具体PID调参篇幅会很长这里先提一个关键概念先让单轮速度闭环稳定再做双轮同步不要上来就指望小车走直线最后大概率从入门到放弃。6.3 给想继续深入的朋友三个练习方向已经能控制TT马达转起来、小车能跑之后下面几个方向可以考虑依次进阶方向一做小车遥控。用HC-05蓝牙或者ESP8266接收手机或者上位机指令把占空比映射到摇杆数据上这是很多人做“手机遥控小车”的起点。方向二做编码器测速显示。把编码器脉冲读出来在OLED屏上实时显示左右轮速度和里程这一步虽然简单但对理解“开环”和“闭环”的差别特别有帮助。方向三做速度PID闭环。选一个轮子让它稳定在某个目标转速先P后I再加D感受不同参数下转速曲线的变化。做完这一步后面再做循迹、避障、麦克纳姆轮都是同一个套路。最后聊一点我自己的习惯。TT马达属于典型的“便宜量大还皮实”的电机很多项目后面会换成带编码器的版本或者换成N20减速电机但控制逻辑完全一样。我每次调试小车都会固定留一组杜邦线专门把驱动模块的GND和STM32的GND连起来这个习惯帮我少排了很多雷。建议你先从单电机的“PWM方向控制”调起等转速控制稳定了再去做差速和闭环。这东西原理一听就懂但每个环节都要亲手接一遍、测一遍踩过坑才算真会了。
返回列表