STM32CubeMX实战:TB6612双电机驱动与智能循迹小车开发
1. TB6612FNG电机驱动模块详解TB6612FNG是东芝推出的双通道直流电机驱动芯片相比传统的L298N模块它具有更高的效率和更低的发热量。这个小小的模块可以同时驱动两个直流电机每个通道能提供1.2A的持续电流峰值可达3.2A完全能满足我们智能小车项目的需求。模块的控制逻辑其实很简单每个电机需要三个控制信号PWM引脚负责调节电机转速IN1和IN2引脚控制电机转向举个例子当AIN11、AIN20时A电机正转反过来AIN10、AIN21就是反转。如果两个引脚电平相同电机就会刹车或自由停止。我在实际项目中发现PWM频率设置在10kHz左右效果最好既能保证电机运行平稳又不会产生明显的噪音。硬件连接方面建议这样配置PA4 → BIN1右电机方向1PA5 → BIN2右电机方向2PA6 → AIN2左电机方向2PA7 → AIN1左电机方向1TIM2_CH2(PA1) → PWMA左电机PWMTIM2_CH3(PA2) → PWMB右电机PWM注意电机电源最好与单片机电源隔离避免电机启动时的电压波动影响MCU正常工作。我在第一次测试时就因为共用一个电源导致单片机频繁复位。2. STM32CubeMX工程配置实战2.1 基础环境搭建打开STM32CubeMX后首先选择正确的芯片型号比如STM32F103C8T6。在Pinout界面需要配置几个关键部分SYS调试接口建议选择Serial Wire这样可以用ST-Link进行调试RCC时钟开启HSE外部高速时钟选择Crystal/Ceramic Resonator时钟树配置将系统时钟设置为72MHz这是STM32F1系列的常用工作频率时钟配置有个小技巧先在HCLK输入框直接键入72然后按回车软件会自动计算各分频系数。我刚开始手动调整分频器时经常算错导致外设工作不正常。2.2 GPIO与定时器配置根据硬件连接方案我们需要配置以下GPIOPA4、PA5、PA6、PA7设为GPIO_OutputPA8、PA9设为GPIO_Input用于红外传感器定时器配置是重点以TIM2为例选择Channel2和Channel3为PWM Generation CHx模式预分频器(Prescaler)设为7172MHz/721MHz自动重装载值(Counter Period)设为991MHz/10010kHzPWM脉冲宽度初始值设为0这样计算下来PWM频率72MHz/(711)/(991)10kHz占空比分辨率是100级0-99。实际测试发现这个分辨率对小车速度控制来说完全够用。3. 电机驱动代码实现3.1 PWM驱动函数编写在生成的Keil工程中我们需要在main.c的USER CODE BEGIN 0区域添加电机控制函数// 左电机控制函数 void motorControlL(uint8_t direction, uint16_t speed) { HAL_TIM_PWM_Start(htim2, TIM_CHANNEL_3); // 方向控制 HAL_GPIO_WritePin(GPIOA, BIN1_Pin, (direction 0x01)); HAL_GPIO_WritePin(GPIOA, BIN2_Pin, ((direction 0x01) ^ 0x01)); // 速度控制 __HAL_TIM_SET_COMPARE(htim2, TIM_CHANNEL_3, speed); } // 右电机控制函数 void motorControlR(uint8_t direction, uint16_t speed) { HAL_TIM_PWM_Start(htim2, TIM_CHANNEL_2); // 方向控制 HAL_GPIO_WritePin(GPIOA, AIN2_Pin, (direction 0x01)); HAL_GPIO_WritePin(GPIOA, AIN1_Pin, ((direction 0x01) ^ 0x01)); // 速度控制 __HAL_TIM_SET_COMPARE(htim2, TIM_CHANNEL_2, speed); }这里有个细节需要注意HAL库的PWM占空比是通过__HAL_TIM_SET_COMPARE函数设置的这个值不能超过定时器的自动重装载值我们之前设为99。我在调试时曾经不小心设置了超过99的值导致电机转速出现异常波动。3.2 基础运动控制利用上面两个函数我们可以轻松实现小车的基本运动// 前进 motorControlL(1, 300); // 正向转动速度300 motorControlR(1, 300); // 后退 motorControlL(0, 300); // 反向转动 motorControlR(0, 300); // 左转 motorControlL(1, 150); // 左轮慢速 motorControlR(1, 300); // 右轮快速 // 右转 motorControlL(1, 300); motorControlR(1, 150); // 停止 motorControlL(1, 0); motorControlR(1, 0);实际测试时发现由于两个电机特性不可能完全一致即使给相同的PWM值两个轮子的转速也会有差异。这时候需要通过微调PWM值来补偿比如左轮给300时右轮可能需要给280才能走直线。4. 智能循迹功能实现4.1 红外传感器安装与调试常见的红外循迹模块一般有5个传感器但为了简化我们先使用两个传感器实现基础循迹。安装时要注意传感器间距建议3-4cm离地高度约1-1.5cm使用万用板固定时要确保与地面平行传感器输出通常是数字信号遇到黑线输出0白底输出1。调试时可以用以下代码测试while(1) { uint8_t left_sensor HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_8); uint8_t right_sensor HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_9); printf(Left: %d, Right: %d\n, left_sensor, right_sensor); HAL_Delay(200); }在地面铺设黑白相间的轨迹可以用电工胶带观察串口输出的传感器状态变化。如果发现灵敏度不够可以调节传感器上的电位器。4.2 循迹算法实现在main函数的while循环中添加循迹逻辑while (1) { // 两个传感器都在白区直行 if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_8) HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_9)) { motorControlL(1, 300); motorControlR(1, 300); } // 两个传感器都在黑线上停车 else if(!HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_8) !HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_9)) { motorControlL(0, 0); motorControlR(0, 0); } // 只有左侧传感器检测到黑线左转 else if(!HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_8) HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_9)) { motorControlL(1, 180); // 左轮减速 motorControlR(1, 300); // 右轮全速 } // 只有右侧传感器检测到黑线右转 else if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_8) !HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_9)) { motorControlL(1, 300); motorControlR(1, 180); } HAL_Delay(10); }这个算法虽然简单但在实际测试中表现不错。如果想提高循迹精度可以考虑以下几点改进增加PID控制算法使用更多传感器3-5个加入速度渐变控制避免急转弯增加记忆功能记住特殊路径点