1. 项目概述:当STM32遇上遥控小车
去年夏天我在整理工作室时,翻出几个闲置的STM32F103C8T6开发板,正好孩子想要个能遥控的小车玩具。这个蓝板子作为电子工程师的"国民MCU",用来做遥控车简直再合适不过。整个项目最有趣的地方在于,我们需要同时实现发射端和接收端的双向通信,还要处理电机控制、信号解码等实际问题。
市面上的玩具遥控车大多采用现成模块,但自己从底层实现能学到更多。STM32F103C8T6凭借其72MHz主频和丰富的外设接口,完全能够胜任这个任务。下面我就把整个开发过程中的关键点梳理出来,包括硬件选型、通信协议设计、电机驱动等核心环节。
2. 硬件架构设计
2.1 核心控制器选型
选择STM32F103C8T6主要基于三点考虑:
- 成本优势:零售价仅10元左右,批量采购更低
- 性能足够:72MHz Cortex-M3内核,20KB RAM完全满足控制需求
- 外设丰富:自带2个SPI、3个USART、2个I2C接口,方便扩展
实际测试中,在同时处理无线通信和电机PWM控制时,CPU占用率始终低于60%,证明选型合理。
2.2 无线模块对比测试
我对比了三种常见方案:
- NRF24L01+:2.4GHz频段,实测空旷地带50米稳定传输
- HC-12:433MHz频段,穿墙能力更强但功耗较高
- ESP8266:WiFi方案,延迟较大不适合实时控制
最终选择NRF24L01+,因其具备:
- 自动应答和重传机制
- 125个可选频道避免干扰
- 仅10mA的工作电流
注意:NRF模块需要3.3V供电,直接接5V会烧毁。建议通过AMS1117稳压芯片供电。
2.3 电机驱动电路
采用L298N双H桥驱动模块,关键参数:
- 驱动电压:5-35V
- 单路持续电流:2A
- 峰值电流:3A
典型接线示例:
c复制// STM32 GPIO配置
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1; // IN1 IN2
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
3. 通信协议设计
3.1 数据包结构
自定义的通信协议包含以下字段:
| 字段 | 长度 | 说明 |
|---|---|---|
| 包头 | 1字节 | 固定0xAA |
| 命令 | 1字节 | 0x01前进/0x02后退等 |
| 速度 | 1字节 | PWM占空比0-100 |
| 校验 | 1字节 | 异或校验 |
示例数据包:
hex复制AA 01 64 3F // 全速前进
3.2 NRF24L01+配置要点
关键初始化代码:
c复制void RF_Init(void) {
nrf24_init();
nrf24_config(2,2); // 设置频道2,传输速率2Mbps
nrf24_tx_address(txAddr); // 设置发送地址
nrf24_rx_address(rxAddr); // 设置接收地址
}
实测发现2Mbps速率下,数据包往返延迟<10ms,完全满足实时控制需求。
4. 电机控制实现
4.1 PWM参数计算
使用TIM3通道1生成PWM:
- 系统时钟:72MHz
- 分频系数:71(得到1MHz计数频率)
- 自动重装载值:999(1kHz频率)
占空比计算公式:
code复制DutyCycle = (CCR / (ARR+1)) * 100%
配置代码:
c复制TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 500; // 初始50%占空比
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC3Init(TIM3, &TIM_OCInitStructure);
4.2 运动控制逻辑
状态机设计:
- 接收端解析到前进命令
- 设置IN1=1, IN2=0
- 调整PWM占空比控制速度
- 收到停止命令时立即刹车(IN1=IN2=1)
5. 电源管理方案
5.1 供电系统设计
采用双电源方案:
- 控制部分:3.3V LDO稳压
- 驱动部分:直接接7.4V锂电池
实测电流消耗:
| 状态 | 发射端 | 接收端 |
|---|---|---|
| 待机 | 15mA | 18mA |
| 工作 | 22mA | 200mA* |
*电机全速运行时峰值电流可达2A,建议电源容量不低于1000mAh
6. 常见问题排查
6.1 通信失败排查步骤
- 检查SPI接线:CLK/MISO/MOSI/CSN/CE必须正确连接
- 验证电源:NRF模块VCC脚电压应为3.3V±0.3V
- 测试天线:焊接不良会导致距离锐减
- 确认地址:收发双方必须使用相同地址
6.2 电机异常处理
现象:电机抖动不转
可能原因:
- H桥使能端未接通
- PWM频率过高(建议1-5kHz)
- 电源功率不足
解决方法:
- 用万用表测量EN引脚电压
- 逐步降低PWM频率测试
- 并联电容改善电源质量
7. 进阶优化方向
7.1 加入陀螺仪反馈
通过MPU6050获取姿态数据,可实现:
- 自动平衡功能
- 运动轨迹记录
- 防跌落检测
数据融合算法示例:
c复制void Kalman_Filter(float angle, float gyro) {
static float Q_angle = 0.001;
static float Q_gyro = 0.003;
static float dt = 0.01; // 10ms采样周期
/* 卡尔曼滤波计算过程 */
...
}
7.2 低功耗优化策略
- 采用中断唤醒机制
- 动态调整发射功率
- 电机空闲时切断驱动电源
实测可使待机电流降至5mA以下,电池续航提升3倍。
8. 项目总结与改进
这个项目最让我意外的是STM32F103的资源利用率——在实现完整遥控功能后,Flash只用了32%,RAM占用不到50%。这意味着还有充足的空间可以添加更多功能,比如加入超声波避障或者蓝牙双模控制。
实际组装时有个小技巧:将NRF模块的天线部分伸出车体外,能显著提升通信距离。我在PCB四角加了3mm高的铜柱作为支架,既保护了电路板又为天线提供了理想位置。