资讯详情

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

硬件配置

在做这个小项目之前, 考察过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

标签: pcb多芯连接器8x4电阻器定时器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台