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只要把占空比调成零就好了!坑啊!


猜你喜欢

转载自blog.csdn.net/hustcw98/article/details/79938726
今日推荐