尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

STM32驱动TB6612电机驱动模块:从接线到PWM调速全指南

STM32驱动TB6612电机驱动模块:从接线到PWM调速全指南 简介基于STM32F103C8T6与TB6612FNG的电机驱动控制源码包面向嵌入式入门开发者与小车/机器人爱好者解决直流电机PWM调速与正反转控制的工程实现问题。包内共16个文件以H头文件、C源文件为主另有MD说明文档、Makefile、链接脚本及启动文件压缩包仅24KB覆盖定时器PWM配置、GPIO方向控制、电机状态封装等完整代码结构。已有123人学习下载。代码基于标准库编写清晰注释关键函数封装了前进、后退、左转、右转、停止等运动控制接口可直接移植到STM32F103系列最小系统板配合TB6612模块驱动两路直流电机。对于需要快速搭建循迹小车、智能车底盘或验证电机驱动逻辑的开发者具备较高参考价值。 写这篇东西的起因是后台经常有人问我同一个问题“我照着网上教程用 L298N 驱动电机模块烫得能煎鸡蛋是不是我接线接错了” 其实不是接线错是选型从一开始就走偏了。在桌面机器人、智能小车、云台这类轻量电机应用里TB6612 几乎是最平衡的选择体积小、压降低、逻辑电平直连 3.3V配合 STM32 的 PWM 输出就能精确控制电机方向和转速。下面把我从接线到源码再到实测排坑的完整过程整理出来拿走即用。1. 为什么选 TB6612而不是 L298N 和 L293D1.1 三款驱动芯片放在一起看很多教程默认推荐 L298N不是因为它是“标准答案”而是因为历史惯性。L298N 是上世纪 90 年代的设计驱动能力确实强每路最大 2A但它是线性驱动结构饱和压降一般在 2V 以上。什么意思当 12V 电源供电时真正到电机两端的电压可能只有 9V 左右剩下的 2 到 3V 全变成热量烧在芯片上。模块发烫不是接错线是物理规律。TB6612FNG 是东芝出的 MOSFET 全桥驱动芯片这里列一个直观对比参数TB6612FNGL298NL293D每路连续输出电流1.2A2A0.6A峰值输出电流3.2A短暂3A短暂1.2A短暂驱动压降约 0.5V 以内约 2V 以上约 1.5V 以上逻辑电平2.7V ~ 5.5V5V 标准逻辑5V 标准逻辑体积SOIC/模块极小模块体积大模块中等待机功耗有 STBY 引脚可完全关断无待机无待机看第三行你就明白为什么 L298N 做小车的同学总抱怨“电池不耐用”。同样的电机L298N 用 7.4V 供电时电机实际可能只有 5V又因为压差全在芯片上热量大还要加散热片。TB6612 内部是 MOSFET 全桥导通电阻很小压降在 0.5V 以内发热问题大大缓解。对于大多数使用 6V ~ 12V 微型直流减速电机的项目TB6612 的 1.2A 连续电流完全够用峰值 3.2A 也能应付启动瞬间的浪涌。L293D 就更不用提了600mA 的连续电流在现在的主流电机面前有点捉襟见肘除非是极致轻量的小震动马达否则我不建议在 STM32 项目里用它。1.2 TB6612 芯片的引脚逻辑TB6612 是双路 H 桥驱动内部有两组完全独立的全桥可以分别驱动两个直流电机。每组有三个关键控制输入两个方向引脚 IN1、IN2 和一个 PWM 使能引脚 PWMA/PWMB。芯片还有一个 STBY 待机引脚这是很多新手忽略的。看真值表所有控制逻辑一目了然STBYIN1IN2PWMA输出状态0XXX待机输出高阻110PWM正转占空比由 PWM 决定101PWM反转占空比由 PWM 决定111X刹车输出短接100X刹车输出短接注意 IN1、IN2 同时为高和同时为低都会进入刹车状态区别在于内部逻辑略有不同但实际效果都是让电机快速停止。这个特性在做舵机类往复运动时很有用后面写代码时会利用它实现急停。2. 硬件接线先看这张图再通电2.1 最小系统接线8 根线不能错网上很多初学者接线失败十有八九是共地和逻辑电源没搞清楚。TB6612 模块的引脚一般有 VM、VCC、GND、PWMA、PWMB、AIN1、AIN2、BIN1、BIN2、STBY、AO1、AO2、BO1、BO2接线规则如下VM 接电机电源正极即电机那路电源比如 7.4V 锂电池或 12V 电源。VCC 接逻辑电源通常是 STM32 板子的 3.3V 或 5V具体看模块上有没有稳压芯片。TB6612 芯片本身逻辑电压支持 2.7V ~ 5.5VSTM32 的 3.3V 可以直接驱动不需要电平转换。GND 必须和 STM32 的 GND 共地。这一步漏掉电机要么不动要么乱转而且 PWM 信号根本无法形成回路。AO1、AO2 接电机 A 的两根线BO1、BO2 接电机 B 的两根线。直流电机两根线没有正负之分调换就是反转由代码里的 IN1/IN2 决定。AIN1、AIN2、PWMA、STBY 是控制信号接 STM32 的 GPIO。PWMA 一定要接在定时器的 PWM 输出引脚上不能随便接普通 GPIO。STBY 引脚是芯片的总开关接高电平芯片才工作。有些模块已经把 STBY 通过上拉电阻接好甚至引出排针让你自由控制我建议引出到一个 GPIO 上然后用软件控制使能这样出问题时可以直接拉低 STBY 让电机“躺平”。2.2 电源和滤波电容一个容易被忽略的细节驱动电机最忌讳的是一套电源全部串在一起。STM32 板载的 3.3V 稳压输出通常只能提供几十到几百毫安的电流直接拿去驱动电机必然把稳压芯片拉垮轻则电机抖动重则 MCU 重启。正确的做法是电机电源独立供电逻辑部分从 STM32 开发板取电两者只共地。另一个小细节是在 VM 和 GND 之间并一个 100uF 到 470uF 的电解电容。电机是感性负载启动和急停瞬间会产生比较大的电流尖峰和反电动势这个电容能把浪涌吸收掉相当一部分让 VM 电压更稳定。再讲究一点可以在电容两端并联一个 0.1uF 的陶瓷电容滤高频干扰。如果你在面包板上搭电路还要注意接触电阻。电机启动瞬间电流可能到 1A 以上面包板那长条接触金属片的压降会很明显至少用杜邦线从模块飞线到电源不要整个回路都走面包板。3. 软件设计从 CubeMX 到第一路 PWM3.1 定时器与 PWM 通道的选择思路驱动电机本质上是在控制电枢两端的平均电压STM32 通过定时器输出 PWM占空比越高平均电压越高转速越快。这里的关键是选一个合适的定时器和通道。我用的最多的是 STM32F103C8T6 的 TIM3 通道 1 和通道 2引脚是 PA6 和 PA7。为什么选 TIM3因为它是通用定时器带有 4 个独立通道分频灵活生成两路 PWM 正好对应一个 TB6612 的两个电机。如果你有 4 个电机可以用 TIM3 的 4 个通道或者再搭配 TIM2。CubeMX 里 TIM3 的配置参数我的常用组合是Clock Division不分频ModePWM Generation CH1 和 CH2Prescaler8-1 7Counter Period900-1 899Pulse0Auto-Reload PreloadEnable这里算一下 PWM 频率STM32F103 的定时器时钟是 72MHz72MHz 除以PSC1再除以ARR1即 72MHz / 8 / 900 10kHz。这个频率落在人耳可听范围之外所以电机不会发出刺耳的啸叫声同时开关频率又不至于太高导致 MOSFET 驱动损耗过大。3.2 生成工程后的初始化代码CubeMX 生成工程后PWM 初始化函数在tim.c里已经写好了但要在主循环前启动 PWM 输出。这是很多人漏掉的第一件事只配置了定时器却没有启动比较输出GPIO 上永远没有波形。/* main.c 的主函数中在 while(1) 之前 */ HAL_TIM_PWM_Start(htim3, TIM_CHANNEL_1); HAL_TIM_PWM_Start(htim3, TIM_CHANNEL_2);同时把 AIN1、AIN2、BIN1、BIN2、STBY 对应的 GPIO 模式配置为推挽输出初始状态全部输出低电平。GPIO 初始化部分在 CubeMX 里绑定引脚后由代码自动生成不用手写。设置转速的核心代码是修改比较寄存器__HAL_TIM_SET_COMPARE(htim3, TIM_CHANNEL_1, 450); /* 50% 占空比 */ __HAL_TIM_SET_COMPARE(htim3, TIM_CHANNEL_2, 0); /* 0% 占空比 */450 对应 900 级的 50%这个设计让速度控制有 900 个细分档位比用一个简单的HAL_GPIO_WritePin控制高低电平精确得多。4. 源码解析一个可以抄走的电机驱动模块4.1 接口设计面向对象思路的 C 语言实现工程不大但代码结构建议从一开始就理顺。我把电机驱动封装成一个独立模块接口暴露给主逻辑头文件长这样// motor.h #ifndef __MOTOR_H #define __MOTOR_H #include main.h typedef struct { TIM_HandleTypeDef *htim; uint32_t channel; GPIO_TypeDef *in1_port; uint16_t in1_pin; GPIO_TypeDef *in2_port; uint16_t in2_pin; int16_t speed; /* -899 ~ 899负值代表反转 */ } motor_t; void Motor_Init(motor_t *motor); void Motor_SetSpeed(motor_t *motor, int16_t speed); void Motor_Brake(motor_t *motor); void Motor_Stop(motor_t *motor); #endif结构体把每个电机对应的定时器、PWM 通道、方向引脚都绑定到一起这样主逻辑里只需要维护一个motor_t结构体代码可读性和复用性都高。一个 TB6612 接两路电机那就定义两个motor_t分别传入不同参数。4.2 方向控制与调速逻辑的实现Motor_SetSpeed是核心内部实现逻辑是用正负数值表示方向这样主循环里只需要算一个带符号的变量不用单独再传方向标志。#include motor.h void Motor_Init(motor_t *motor) { __HAL_TIM_SET_COMPARE(motor-htim, motor-channel, 0); HAL_TIM_PWM_Start(motor-htim, motor-channel); HAL_GPIO_WritePin(motor-in1_port, motor-in1_pin, GPIO_PIN_RESET); HAL_GPIO_WritePin(motor-in2_port, motor-in2_pin, GPIO_PIN_RESET); } void Motor_SetSpeed(motor_t *motor, int16_t speed) { if (speed 899) speed 899; if (speed -899) speed -899; motor-speed speed; if (speed 0) { HAL_GPIO_WritePin(motor-in1_port, motor-in1_pin, GPIO_PIN_SET); HAL_GPIO_WritePin(motor-in2_port, motor-in2_pin, GPIO_PIN_RESET); __HAL_TIM_SET_COMPARE(motor-htim, motor-channel, speed); } else if (speed 0) { HAL_GPIO_WritePin(motor-in1_port, motor-in1_pin, GPIO_PIN_RESET); HAL_GPIO_WritePin(motor-in2_port, motor-in2_pin, GPIO_PIN_SET); __HAL_TIM_SET_COMPARE(motor-htim, motor-channel, -speed); } else { /* speed 为 0 时走刹车逻辑 */ Motor_Brake(motor); } } void Motor_Brake(motor_t *motor) { HAL_GPIO_WritePin(motor-in1_port, motor-in1_pin, GPIO_PIN_SET); HAL_GPIO_WritePin(motor-in2_port, motor-in2_pin, GPIO_PIN_SET); __HAL_TIM_SET_COMPARE(motor-htim, motor-channel, 0); }这里面有几个细节值得展开。第一speed 0和speed 0时IN1/IN2 的电平状态正好相反对应真值表里的正转和反转。第二可行驶的占空比范围被限制在 899 以内防止超过定时器 ARR 导致波形异常。第三速度归零时不要只把 PWM 设成 0因为 PWM 为 0 等于让电机两端悬空电机会因为惯性继续滑行用刹车逻辑把两个 IN 引脚同时拉高内部全桥短接形成一个电磁制动回路小车能在更短距离内停下来。STBY 的控制放在主逻辑里HAL_GPIO_WritePin(STBY_GPIO_Port, STBY_Pin, GPIO_PIN_SET);做电机使能时把 STBY 拉高。电机正常运行期间保持高电平即可。如果程序跑飞或需要紧急停机拉低 STBY 可以让两个全桥同时释放这个比逐路关 PWM 更可靠。5. 实测中躲不开的四个坑5.1 电机一转 STM32 就复位这是我收到的最多的一个问题。现象是小车一上电电机还没转起来开发板先重启了串口打印乱码。排查思路MCU 复位除了软件复位以外最常见的原因是电源跌落。电机启动瞬间电流可能是额定电流的好几倍如果电机电源不稳定压降会通过共地干扰传导到 STM32 的供电上导致掉电复位。解决方法是给电机独立供电并且把电机电源和逻辑电源的 GND 可靠相连。如果不得不用同一路电源至少保证电源的峰值输出能力足够并在 VM 和 GND 之间放一个 470uF 的电容。还有一个容易被忽略的点电机电源线尽量短且粗内阻越小动态响应越好。5.2 电机没转时滋滋响这个声音本质上是 PWM 的频率落在了人耳听觉范围。20Hz 到 20kHz 之间的开关频率都会被听到表现为一种高频噪声。我默认用 10kHz人耳已经不太敏感但如果你耳朵贴近电机还是能听到轻微的声音。解决办法是把 PWM 频率提到 20kHz 以上比如把 ARR 改为 449PSC 改为 7频率变为 72MHz / 8 / 450 20kHz。注意频率升高后每个 PWM 周期的开关损耗也会增加芯片会稍微热一点但 TB6612 的余量足够。另一种“滋滋声”是 PWM 频率正确但占空比突变时产生的机械噪声。加速时不要瞬间从 0 跳到 899而是用斜坡函数逐级增加比如每隔 10ms 增加 10 或 20这样电机转动更平顺声音也柔和很多。5.3 电机高速抖动刹车刹不住高速抖动一般不是电机本身的问题而是占空比控制时引入了过大噪声。检查一下单片机输出 PWM 的引脚是否与电机线靠得太近电机的换向会产生电磁干扰耦合到 PWM 信号线上导致占空比在单片机端被干扰。把信号线远离电机线或者用双绞线传输 PWM。刹车刹不住的问题很多时候是因为你把 PWM 置 0 就当是刹车了。我在第 4 章已经说过PWM 置 0 是让输出悬空不是刹车。要快速刹停必须把 IN1 和 IN2 同时拉高让全桥内部短接产生反接制动效果。如果你用了急停但速度依然衰减慢检查一下电源电压是不是偏高太多反电动势通过体内二极管回灌到电源这也是一种能量释放路径。5.4 芯片发烫甚至烧毁TB6612 的发热比 L298N 小很多但也不是完全不会烫。异常发烫最常见的原因是 STBY 引脚悬空或接地导致内部逻辑处于不正常状态输出级半导通损耗剧增。检查 STBY 是否确实拉高可以用万用表量一下 STBY 引脚对地电压。另一个原因是电机堵转。堵转时电机电流会远远超过额定值长时间堵转可以烧掉驱动芯片。工程上应加过流保护逻辑通过电流采样电阻监控 VM 电流当电流超过阈值时立刻拉低 STBY。如果项目里没有采样电阻至少要在代码里加入超时保护电机命令持续超过 N 秒没有收到新指令就自动停止。芯片烧毁还有一个隐蔽原因VM 电压过高。TB6612 的绝对最大额定电压是 18V但实际使用建议控制在 12V 以内。超过 15V 哪怕只是瞬间体二极管和 MOSFET 就可能被击穿。如果项目必须用更高的电压要么换驱动芯片要么加一级 DC-DC 降压模块单独给 VM 供电。6. 一点额外经验这套代码和接线方式我在三轮小车、二轮平衡车实验、摄像头云台上都跑过。表面看是“STM32 控制 TB6612 驱动电机”实际上核心是 PWM 调速和 H 桥方向控制两个知识点。把这两块吃透换成别的驱动芯片也只是换一套寄存器配置的事。最后分享一个调试小技巧写调速代码前先用一个简单的平地占空比测试确定电机启动的最小占空比。不同电机的死区和静摩擦不同有的电机 10% 占空比就能转有的要到 20%。把这个值记下来做速度闭环或 PID 调速时把它作为死区补偿加进去低速段控制会舒服很多。本文还有配套的精品资源点击获取
返回列表