锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

用STM32F401和nRF24L01制作无线调速小车

时间:2023-01-24 09:30:00 pcb多芯连接器8x4电阻器定时器

硬件配置

在做这个小项目之前, 考察过STM32F103C8T6, STM32F401CCU6STC89C52这三个MCU, 实际上跑了一些用例

  • STC89C52在代码上要简单得多, 没有问题ADC功能, 因此不能用于遥控部分, 只能用于小车, 而且PWM输出为软输出, 主循环实现. 带ADC功能的STC单片机型号有STC12C5A系列和STC15F, STC15W系列, 但现在市场价格很贵, 单芯片需要22RMB.
  • STM32F103C8T该项目的功能处理没有问题, 这种类型的代码在网上特别丰富, 问题是现在价格太贵了, 原装芯片最小系统板价格为38RMB, CH版也要25RMB, 与高一代相比,系统板的价格仅为15RMB的STM32F401CCU6没有优势.
  • STM32F401CCU最小系统板价156RMB, 该项目的功能响应没有问题, 其缺点是参考资料少. STM32F4系列在国内使用较少, 网上代码例子少,很多都是针对的F407这些高级型号, 如果用在F401需要额外的调整.

最后的选择是STM32F401CCU6, 代码问题不是问题, 对吗?

遥控器部分

  • 电源: 3.7V 18650锂电
  • 3.3V稳压: 一个1N4148二极管
  • MCU: STM32F401CCU6最小系统板
  • 输入: 双轴摇杆模块
  • 无线: nRF24L01模块

说明硬件部分

  • 1N4148能产生0.6V的压降, 对于3.7V锂电池就够了, 实际测试1865年两端电压约4.0V, 通过1N4148后输出电压为3.2V. STM32F401CCU6, nRF24L01和双轴摇杆的功耗都很小, 1N应付4148没问题.
  • 由于单节18650电池盒输出线为裸多芯软线, 直接连接到模块不方便, 因为这部分有两个模块nRF24L01和双轴摇杆都需要3.3V电压, 所以用万能板做中转, PCB接线端子用于连接电源线, 3V3通过一个1N4148后接到3V3的排针上, 另一个排针是地线.
  • 这个接线端子是从炸掉的L9110s模块上拆的

小车部分

  • 电源: 7.4V (18650锂电x2)
  • 6V稳压: 串联两个IN4007
  • 3.3V稳压: AMS1117 3.3V模块
  • MCU: STM32F401CCU6
  • 无线: nRF24L01模块
  • 电机驱动: L9110双路x2
  • 小车底盘
  • 48:1减速电机x4

说明硬件部分

  • 电机采用普通48:1减速电机, 工作电压为6V, 另外L9110s尽管标称可达12V, 市面上的L9110s大部分都达不到这么高, 安全电压在7V左右, 因此,有必要将电压降低到6V附近, 通过两个1N4007能产生1.2V的压降
  • 运行时每个电机的电流为0.15A, 合计0.6A, STM32F401,nRF24L01的耗电量可以忽略不计, 1N4007的工作电流为1A, 应该是够的
  • STM32需要的3.3V远离电源电压, 直接用AMS1117模块降压。
  • 因为有四个电机, 因此需要两个双通道L9110s模块
  • 电池盒引出裸多芯软线, 直接连接到模块不方便, 所以中间板是用万能板做的, 连接电池盒的接线端子, 正极串联两个1N4007输出正极排针, 还有地线排针, 四组排针L9110s输入(每侧两个通道共用一组PWM)

接线

遥控器部分

MCU接口如下

  • UART: 方便调试
    • PA9 => USB2TTL的RX
    • PA10 => USB2TTL的TX
  • SPI: 连接nRF24L01
    • PA5,PA6,PA7, PB13,PB14,PB15
  • ADC: 两个pin, 连接双轴摇杆
    • PA0 => 摇杆AXIS X
    • PA1 => 摇杆AXIS Y
  • VCC
  • GND

与nRF24L01的接线

STM32 nRF24L01
PA4 SPI1_NSS N/A
PA5 SPI1_SCK SCK
PA6 SPI1_MISO MISO
PA7 SPI1_MOSI MOSI
PB13 IRQ
PB14 CE
PB15 CSN

小车部分

MCU接口如下

  • UART: 方便调试
    • PA9,PA10, 同上
  • SPI: 连接nRF24L01
    • PA5,PA6,PA7, PB13,PB14,PB15
  • PWM: 4个pin, 输出4组PWM, 对应左右两组 L9110
    • PA0,PA2: 左侧电机
    • PA1,PA3: 右侧电机

nRF24L01接线同上.

功能实现

遥控器部分

这一块主要通过两个ADC通道采集摇杆电压, ADC采集使用的DMA的模式, 定时(几十到几百毫秒)读取主循环中的电压, 并转换为[0, FF]区间, 通过nRF24L01发射出去. ADC采集电压时, 每个通道使用4个u16做缓存, 输出值平均为这四个值, 抑制抖动.

涉及的技术术语: UART, ADC, DMA, TIMER, SPI

小车部分

汽车功能有几个部分:

  1. nRF24L01的中断接收. 需要将nRF24L01的接收配置为中断模式, 只有在遥控端发出指令时, 小车才做相应的动作, 与在循环中检测接收信息并调整输出的实现方法相比,更及时、更高效.
  2. PWM输出控制车辆的速度和方向.
  3. X轴将被接收Y轴向量, 映射到两个电机的方向和强度.

涉及的技术术语: UART, TIMER, EXTI, SPI, PWM
具体说明如下

nRF24L01的中断接收

这部分需要在STM32上新增一个EXTI中断源, 映射到nRF24L01的IRQ PIN脚. 中断是低电平触发, 处理中断后注意, 需要清空接收缓冲, 否则下次会读到旧值.
根据接收到的数值调整中断处理方法PWM输出, 实现遥控功能.

还有一个定时器TIM3, 当前设定的固定时间为0.5秒, 定时器将在每次中断处理时初始化, 经过0的定时器.5秒后触发时, 会将PWM输出归零, 电机归零后会停止. 通过这一机制, 遥控器发出指令后,汽车将在当前指令下输出PWM 0.5秒, 如果续收到指令,则继续输出, 若未收到指令, 则在0.5秒后停止输出, 体现在汽车运动上, 小车每次命令都会移动0.5秒.

PWM输出控制速度和方向

PWM频率选择: 48:1减速电机是淘宝上最便宜、最常见的减速电机, 最佳PWM频率是25Hz-50Hz. 这个频率的来源是里, 里面有很详细的说明和实验测试结果. 我把我关心的部分内容翻译了一下, 可以看这里. 我在实际使用中观察到的结果是符合这篇文章的结论的.

这里多说几句. 关于电机的PWM频率选择, 在网上查了很久, 得到的结果大部分是错误的, 很多人文章里写的频率是6-20KHz. 这里需要注意区分一下, 如果你用的是直流有刷电机, 那么用这么高的PWM频率是会出问题的, 建议在几十到几百Hz的范围去测试.

PWM控制速度比较好理解, 但是控制方向的具体实现需要通过两个PWM配合. 尝试过通过1路PWM+1路GPIO进行方向切换, 但是无法正常工作, 最后还是要通过两路PWM. 根据方向, 设置其中一路PWM输出为0. 这里为了避免出现双高电平(网上有很多人提到双高导致L9110s烧毁), 在程序中先设置输出为0的一路PWM, 再输出另一路不为0的PWM.

X轴Y轴向量映射到左右两路电机

这一块花了我一些时间. 在网络上找到的资料看, 实现方式更多是通过Y轴计算出左右电机整体的前进后退占空比, 然后通过X轴计算左右电机占空比差值, 再将这两个结果叠加, 得到最后的左右电机占空比. 这个计算方式的问题是当工作点在Y轴区间两端的时候, 此时叠加的差值会使Y轴的值超出区间, 但是实际上这个数值是不可能的, 所以要么将两个通道的数值都往回拉, 要么就忽略Y轴超出区间的部分, 都不是很合理.

我使用的计算方式, 是先规定摇杆圆周4个方向上对应LR通道的值:

  • 0° => L:FF, R:-FF
  • 90° => L:FF, R:FF
  • 180° => L:-FF, R:FF
  • 270° => L-FF, R:-FF

将摇杆得到的XY轴的值做成向量, 将这个向量投影为圆周上某一点, 再根据圆周上这个点两端的值计算当前点的LR值.

因为摇杆得到的XY轴空间, 实际上是一个正方形, 将其映射到圆上时, 有一个有趣的现象, 当角度位于0°到45°时, 向量的长度等于X轴的值, 而在45°到90°时, 向量长度等于Y轴的值, 这个使得计算简便了许多.

遇到的问题

L9110s发热烧毁

电源为两节18650, 电压为3.7x2=7.4V, 两路pwm输出, 当从0,0 -> 0,全速时, 电机无动作, L9110s发烫然后冒烟烧毁. 这个直接导致两个模块各烧了一片L9110s. 于是上网查相关的资料

相关的讨论

  • Is this the reason for burning my h-bridge? https://www.eevblog.com/forum/beginners/is-this-the-reason-for-burning-my-h-bridge/
  • L9110 IC goes up in smoke https://forum.arduino.cc/t/l9110-ic-goes-up-in-smoke/367873
  • L9110 up in smoke https://forum.arduino.cc/t/l9110-up-in-smoke/381488
  • https://forum.arduino.cc/t/fried-my-mega-and-multiple-dc-motor-control-boards-how-can-i-prevent-this/664303
  • AB全高状态,静态加电时AB=HH没有发热,但是给1kHz脉冲,9110就冒烟.正常驱动A=H,B=L时,B变H感觉有短时间刹车现象,因为如果A=0,电机停得慢,当A=H,B由L变H就快速停.按理AB=HH是可以的,只是实际结果,静态没问题,动态就烧了 https://www.amobbs.com/thread-4986052-1-1.html
  • https://www.zhihu.com/question/52548517
  • https://www.icxbk.com/ask/detail?tid=30203
  • 对直流电机选择最优的PWM频率 https://learn.adafruit.com/improve-brushed-dc-motor-performance?view=all

因为模块已经带了输出电容和上拉电阻, 所以可能的原因是

  1. 电机启动电流过大导致模块烧毁. 电机静态电阻为6.5Ω, 电压7.4V时电流超过1A,
    应对方案: 串联一个5Ω的限流电阻, 可以将电流降到7.4/(6.5+5)=0.64A, 避免超出L9110s的最大电流, 运转中的电机阻抗为40Ω - 45Ω, 此时电阻上的分压不到1V, 影响不大.
  2. L9110s耐压超限. 有人说最高到6.5V.
    应对方案: 在L9110s输入电压前串联2个1N4007, 将电压降到7.4-1.4=6V, 串联2个时,启动电流1A,正向电阻0.7Ω, 空转时0.15A,正向电阻5Ω
  3. PWM频率过高. 过高的PWM频率会导致电机在低占空比时无法启动,
  4. PWM同时输出高电平

最终解决方案

  1. 串联两个1N4007将电压降到6.2V
  2. PWM频率降到100Hz

有些占空比下电机不动

在逐渐增大占空比的过程中, 有些值下电机不转, 能听到吱吱声, 如果手摸着L9110s芯片, 能感觉到此时有一阵发烫, 所以此时电流到位了, 但是没能驱动电机.

这个原因和前一个问题是一样的, 因为PWM频率过高(17.5KHz), 无法驱动电机, 在将频率降到100Hz后这个问题就没再出现.

小车在运行一段时间后中断灯常亮, 失去响应

经过检查, 是因为在处理nRF24L01接收中断时, 加入了一个延时1ms的处理, 会卡在这个延时函数上, 将这个延时处理删除后就未再出现这个情况

参考

  • 直流电机的性能优化 https://learn.adafruit.com/improve-brushed-dc-motor-performance?view=all
锐单商城拥有海量元器件数据手册IC替代型号,打造电子元器件IC百科大全!

相关文章