STM32——遥控小车从设计到实现详细记录

这次边做边写,基本上把做proj的整个步骤记录下来,包括中间的思考过程,也挺有意思的


小车主控板思路

  • 主控板需要完成的功能:
    1.接受传输过来的数据
    2.根据数据控制电机PWM
    3.根据数据控制舵机PWM

  • 控制电机的PWM实现:
    1.一个函数,两个参数:move(dir,speed)
    2.dir控制前后,speed控制pwm.
    3.如果方向改变需要延迟一定时间

  • 控制舵机的pwm实现:
    1.一个函数,两个参数:turn(dir,value)
    2.dir控制左右,value是设定值控制pwm
    3.value需要配合PID算法写好
    两个电机控制需要两个tim的pwm,需要四个管脚输出控制正反转.
    PID算法实现的时候,舵机有反馈线反馈现在所在的角度.反馈用ADC采样读取

PS: 未测试NRF24L01通信模块前自己留一个串口,使用蓝牙调PID


程序步骤

  1. 开启时钟(GPIO,TIM, ADC,USART,AFIO)
  2. 写move函数
  3. 写PID算法
  4. 写turn函数
  5. 配置蓝牙串口
  6. 调试PID

开启时钟

ABP1和APB2对应的外设见下表
这里写图片描述

这里写图片描述


使用TIM生成PWM波

这里使用TIM生成的PWM是为了让PWM更加稳定可靠

  • 原理解释
    通用定时器可以利用GPIO引脚进行脉冲输出,在配置为比较输出、PWM输出功能时,捕获/比较寄存器TIMx_CCR被用作比较功能,下面把它简称为比较寄存器。

    这里直接举例说明定时器的PWM输出工作过程:若配置脉冲计数器TIMx_CNT为向上计数,而重载寄存器TIMx_ARR被配置为N,即TIMx_CNT的当前计数值数值X在TIMxCLK时钟源的驱动下不断累加,当TIMx_CNT的数值X大于N时,会重置TIMx_CNT数值为0重新计数。

    而在TIMxCNT计数的同时,TIMxCNT的计数值X会与比较寄存器TIMx_CCR预先存储了的数值A进行比较,当脉冲计数器TIMx_CNT的数值X小于比较寄存器TIMx_CCR的值A时,输出高电平(或低电平),相反地,当脉冲计数器的数值X大于或等于比较寄存器的值A时,输出低电平(或高电平)。

    如此循环,得到的输出脉冲周期就为重载寄存器TIMx_ARR存储的数值(N+1)乘以触发脉冲的时钟周期,其脉冲宽度则为比较寄存器TIMx_CCR的值A乘以触发脉冲的时钟周期,即输出PWM的占空比为 A/(N+1) 。

  • TIM3复用引脚
    如下图
    TIM3复用功能重映像
    感觉没有引脚冲突的情况下,可以默认没有重映像,TIM3_CH1~4的管脚对应的就是PA6、PA7、PB0、PB1.

    输出模式也好确定,查手册可以看到:输出采用推挽复用输出
    通用定时器的GPIO配置

    Mode值放这方便查看:
    GPIO_MODE

void tim3()                          
{   
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;  //初始化计数配置   
    TIM_OCInitTypeDef  TIM_OCInitStructure;//初始化TIM3的外设
    TIM_TimeBaseStructure. TIM_Period =999;    //计数上限为1000
    TIM_TimeBaseStructure.TIM_Prescaler =71;    //计时器预分频为72/(71+1)=1MHZ   
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;  //不分
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //向上计数
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);     


    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;   //TIM脉冲宽度调制模式1  
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = 10;//设置了待装入捕获比较寄存器的脉冲值  
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //TIM输出比较极性高
    TIM_OC1Init(TIM3, &TIM_OCInitStructure);
    TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);//使能TIM3在CCR1上的预装载寄存器


    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = 10;         
    TIM_OC2Init(TIM3, &TIM_OCInitStructure);          
    TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);//使能TIM3在CCR2上的预装载寄存器
    TIM_Cmd(TIM3,ENABLE);                     
}
  • 注意TIM_OCPolarity的选择和OCMode的PWM两种模式的区别:

    • OCPolarity为高则高电平有效
    • 若TIM_OCInitTypeDef.TIM_OCMode = TIM_OCMode_PWM1时:
      当计时器值小于比较器设定值时则TIMX输出脚此时输出有效
      当计时器值大于或等于比较器设定值时则TIMX输出脚此时输出无效
    • 若TIM_OCInitTypeDef.TIM_OCMode = TIM_OCMode_PWM2时:
      当计时器值小于比较器设定值时则TIMX输出脚此时输出无效
      当计时器值大于或等于比较器设定值时则TIMX输出脚此时输出有效
  • 修改比较寄存器值的函数TIM_SetComparex(TIM_TypeDef* TIMx, u16 Comparex)
    把TIMx的比较寄存器x的值设成Comparex

u16 TIMCompare1 = 0x7FFF;
TIM_SetCompare1(TIM3, TIMCompare1);

试用驱动后的第一次修订

因为采用的大电机的mos驱动很窒息,有一个刹车功能,所以是采用的双路PWM驱动正反转。因此修改之前的TIM生成的PWM配置,采用多个定时器输出多路PWM波.

新的PWM安排如下:

  • TIM2的CH3和TIM3的CH1分别对应PA2和PA6给大电机的两路PWM.
  • TIM4的CH1对应着PB6给舵机的PWM.

新的引脚安排:

  • MOS驱动使能采用PB9.

大坑出现

尝试着正转和反转,但是遇到了大坑.想通过关闭TIM来关闭PWM输出,结果是关闭了TIM之后PWM输出端口就自动高电平无法拉低!.

原因:复用推挽输出下IO口无法控制高低电平,因此拉低只能使用配置占空比的方法.
所以之前配多路TIM是没太大意义的。。关闭PWM只要把占空比调成零就好了!坑啊!


假装调了PID

舵机反馈线就是一个电位器的中间接线引出来的,左右接3.3V,中间接出来一根线连上ADC采样,读取现有值然后写一个PID反馈调节即可。舵机给一个正的PWM或者一个负的PWM即可完成正转和反转,PWM值的高低决定了转向的快慢,如果PWM占空比过小,那么舵机可能无法转动。不能超调过多,也不能调节量太小转动太慢,于是需要控制参数慢慢调节。PID调节经验看了半天,最后发现这个舵机根本就不灵敏,用不着调节I和D,调好P就行了,就是完成了一个负反馈。过程有一点点艰辛,因为用L298N的驱动时,之前没发现驱动不灵敏,导致最小占空比的PWM也是一直处于超调状态。换了MOS驱动很快就调好了,PID调节的内容就不写在这里了,只要看懂了算法很快就能自己写一个,毕竟这里甚至只用写一个P对吧…


NRF24L01通信模块

这一块内容是交给女票做的,第一部分是完成SPI的配置。这个有一大堆教程,如果IO口模式配置正确了,SPI的配置内容没有问题,应该很快就能工作。使用SPI往NRF24L01寄存器里写一个值,然后读出来,如果写进去的和读出来的是一样的,那么SPI就配置完毕了。最后是玄学的通信模块调试。NRF24L01是最便宜的2.4GHz的无线通信模块,由于寄存器太多,女票读了好久文档然后自己写了通信要用的函数,接收发送等等。然后总是GG..调了很久才完成。代码在Git上,现在有一个随时可用的配置了,如果之后要做遥控类的东西通信要调的话就方便很多了。


数据发送接收调节方向,速度,关机开机

遥控器使用两个摇杆电位器做的,用ADC不停采样然后用NRF24L01给车上的主控板不停歇的发送数据,一个控制方向PWM,一个控制驱动电机PWM.前进和后退需要有一定延迟,因为反应太
快而电机又有电感会出现不可逆转的损害。最后是为了防止因为线断了等导致方向或者电机突然失灵,做了一个按钮控制开机关机,就是紧急制动。这些都很好写,源码里直接可以看到。


总结

  • 小车主控板的大坑遇到不多,一个是MOS驱动问题,一开始双PWM控制不太会用,要拉低就是把占空比调到0. 第二个是由于端口太多,ADC,TIM的PWM输出,SPI等引脚可能按默认配置有重复,所以得使用IO口的重映射.
  • 比较大的坑在通信模块,这是和女票一起调了很久才完成的,感觉有点玄学。看看基础配置,通信速率,传输地址,模式等等是不是都配对了。最后的无线通信调试是没有很好的DEBUG方法的,一步一步慢慢来。
  • 小车做出来了还是挺好玩的,比较有成就感. 缺点就是线可能不太稳,如果撞车了有一定概率失去控制。。这个可以再改进一下。
  • 这个小车电机极其强大,可以跑的巨快。。飙车ing

最后成品

这里写图片描述

这里写图片描述

这里写图片描述

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页