CubeMX初配置PWM&驱动MG995舵机

CubeMX初配置PWM&驱动MG995舵机

最近在重学STM32,发现大二上整的像s一样

参考博客

[Bonjour STM32] No.6-定时器简单理解与使用 - Emoe-Studio

STM32CubeMX学习笔记1——PWM配置_夏沫不学习的博客-CSDN博客_cubemx配置pwm

HAL库函数之呼吸灯——PWM波 - 简书 (jianshu.com)

(37条消息) MG995舵机工作原理及基于STM32的驱动源代码_斜杠青年/的博客-CSDN博客_mg995舵机

PWM

个人理解:PWM就是方波,具体使用的时候改变这玩意的占空比就行。

配置PWM

要知道 CNT (计数器当前值), ARR (自动重装载值), CCRx (捕获/比较寄存器值)

CNT 小于 CCRx 时,通道输出高电平;

CNT 等于或大于 CCRx 时,通道输出低电平;

因为目前使用 STM32F103C8T6 ,首先设置使用外部时钟,再设置时钟为72Mhz

3

直接输入 72 就行,CubeMX 会自动配置

4

然后贴一段参考博客里的:

确定时钟源频率后,我们就可以设置PSCARR了。按照之前的要求,我们想让定时器的溢出频率为5Hz,则240MHz/5Hz=48M分频。我们知道,一个模值(“容量”)为48M的定时器即可完成此分频,可是我们的CNT寄存器只有16位,也就是说模值最大设置为65535,远远不够呀。这就是预分频器PSC存在的意义了,“时钟源太快了,CNT没有足够的容量来实现较长周期的定时,所以需要预分频器把时钟降慢一些”。所以说,我们把48M拆成2400*20000就可以了。注意实际填入PSCARR都有一个“-1”,这是因为定时器是从0开始计数的,由0计到239正好是240次。总结一个定时器频率公式,就是这样:

$$f_{TIM}=\frac{f_{CLK}}{(PSC+1)\times(ARR+1)}$$

改变占空比只需要改变对应计时器的 CCRx 就行

$$Duty_x=\frac{CCRx}{ARR}$$

因为 MG995 电机需要一个20ms的时基脉冲,所以需要频率50Hz,为我们设置 PSC=7200-1 ARR=200-1

72000000/7200/200=50

所以计数器每次 +1 的时间为 20ms/ARR=20ms/200=0.1ms

在CubeMX配置如下

设置 TIM3 定时器 ,只用一个通道就行,设置为 PWM模式,默认是 GPIOA16 管脚

5

先点个灯

历时108个秒,我做出了苹果手机没有的功能,呼吸灯

呼吸灯的呼吸,就是灯的强弱状态,改变 PWM 的占空比便可调整

具体配置和前面差不多,这里设置为 ARR=500

改变 CRRx 的两种方式

//ld1_duty 为我们设置的CCRx具体数值
//方法一,直接操作
TIM3 -> CCR1 = ld1_duty;

//方法二,使用库函数
__HAL_TIM_SetCompare(&htim3,TIM_CHANNEL_1,ld1_duty);

主要代码为

int main(void)
{
  // 省略一堆初始化函数
  // 记录变强还是变弱
  uint8_t ld1_dir = 0;
  // 相当于CNT
  uint16_t ld1_duty = 0;
  // 初始化,启动 TIM3 通道1的 PWM 模式  
  HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_1); //PA6
  while (1)
  {
    // 变强状态
    if(ld1_dir == 1) {
      ld1_duty += 20;
    }
    // 变弱状态
    if(ld1_dir == 0) {
      ld1_duty -= 20;
    }
    // 由强变弱
    if(ld1_duty >= 500) {
      ld1_dir = 1;
    }
    // 由弱变强
    if(ld1_duty == 0) {
      ld1_dir = 0;
    }
    // 使用库函数改变 TIM3 通道1 PWM 的占空比
    __HAL_TIM_SetCompare(&htim3,TIM_CHANNEL_1,ld1_duty);
    //延时
	HAL_Delay(50);
  }
}

大概效果

1

驱动MG995舵机

这玩意具体参数可以去参考的博客去看

控制原理

舵机的控制一般需要一个20ms的时基脉冲,该脉冲的高电平部分一般为0.5ms~2.5ms范围内的角度控制脉冲部分。以180度角度舵机为例,那么对应的控制关系是这样的:

0.5ms————–0度;
1.0ms————45度;
1.5ms————90度;
2.0ms———–135度;
2.5ms———–180度;

既然前面已经配置好时钟了,可以直接写代码了

调上面的角度转换成对应高电平部分

// 对应角度 0 45 90 135 180
 uint8_t deg[5] = {5,10,15,20,25};

启动 TIM3 通道1的 PWM 模式

HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_1); //PA6

所以主函数为

int main(void)
{
  // 省了略各种初始化函数
  uint8_t deg[5] = {5,10,15,20,25};
  // 初始化,启动 TIM3 通道1的 PWM 模式
  HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_1); //PA6

  while (1)
  {
    // 先正转,再反转
    for(int i = 1; i < 5; ++i) {
      // 更新CCR1值,直接用寄存器操作
      TIM3 -> CCR1 = deg[i];
      // 延时,等舵机转过去
      HAL_Delay(1000);
    }
	for(int i = 3; i >= 0; --i) {
      TIM3 -> CCR1 = deg[i];
      HAL_Delay(1000);
    }
  }
}

转动效果

对了如果发现不转记得检查一下供电,最好插上电源线再测试。

2


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!