当前位置:   article > 正文

STM32使用PWM控制舵机_stm32输出pwm控制舵机

stm32输出pwm控制舵机

系列文章目录

STM32单片机系列专栏

C语言术语和结构总结专栏


文章目录

1. 舵机简介

2. 硬件连接

3. 代码实现

3.1 PWM.c

3.2 PWM.h

3.3 Servo.c

3.4 Servo.h

3.5 main.c

3.6 完整工程文件


PWM和OC输出详解:

STM32定时器的OC比较和PWM​​​​​​​

1. 舵机简介

舵机是一种位置伺服驱动器器,并且是一种根据输入PWM信号占空比来控制输出角度的装置。通过PWM向伺服器发送一个控制信号时,输出轴就可以转到特定的位置。只在控制信号持续不变,伺服机构就会保持相对的角度位置不变。如果控制信号发生变化,输出轴的位置也会相应发生变化。

图片中的舵机型号为SG90,具有三根输入线:电源线,地线和信号线,PWM就是输入到信号线来控制舵机。控制信号进入内部驱动电路以后,获得直流偏置电压,从而产生周期为20ms,宽度为1.5ms的基准信号,将获得的直流偏置电压与电位器的电压比较,获得电压差输出。电压差的正负输出到电机驱动芯片决定电机的正反转,并且内部有一个电位器,用来检测当前舵机的角度。

输入PWM信号要求为:周期为20ms,高电平宽度为0.5ms - 2.5ms,也就是说周期是20ms,如果高电平时0.5ms,那么舵机输出轴转角为 -90°。

2. 硬件连接

本文是以STM32F103C8T6作为主控芯片,通过PA0端口输出PWM,实现控制180°舵机。

实际应用时,电源线连接5V,GND连接单片机的GND,PWM只是一个通信线,不需要大功率,所以PWM信号线连接单片机的一个引脚。

STM32舵机
5V+5V
GNDGND
PA0PWM

3. 代码实现

这里实现的功能为:按键控制舵机角度,每次按下舵机的角度增加30°,并且通过oled显示。要使用的库函数文件依然为:stm32f10x_tim.h,拖到最下面,在这里可以找到定时器TIM需要使用到的函数。

3.1 PWM.c

  1. #include "stm32f10x.h"
  2. //PWM初始化
  3. void PWM_Init(void)
  4. {
  5. //开启时钟
  6. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //开启TIM2的时钟
  7. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟
  8. //GPIO初始化
  9. GPIO_InitTypeDef GPIO_InitStructure;
  10. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  11. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
  12. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  13. GPIO_Init(GPIOA, &GPIO_InitStructure); //将PA1引脚初始化为复用推挽输出
  14. //受外设控制的引脚,均需要配置为复用模式
  15. //配置时钟源
  16. TIM_InternalClockConfig(TIM2); //选择TIM2为内部时钟,若不调用此函数,TIM默认也为内部时钟
  17. //时基单元初始化
  18. TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; //定义结构体变量
  19. TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能
  20. TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式,选择向上计数
  21. TIM_TimeBaseInitStructure.TIM_Period = 20000 - 1; //计数周期,即ARR的值
  22. TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1; //预分频器,即PSC的值
  23. TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //重复计数器,高级定时器才会用到
  24. TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure); //将结构体变量交给TIM_TimeBaseInit,配置TIM2的时基单元
  25. //输出比较初始化
  26. TIM_OCInitTypeDef TIM_OCInitStructure; //定义结构体变量
  27. TIM_OCStructInit(&TIM_OCInitStructure); //结构体初始化,若结构体没有完整赋值
  28. //则最好执行此函数,给结构体所有成员都赋一个默认值
  29. //避免结构体初值不确定的问题
  30. TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //输出比较模式,选择PWM模式1
  31. TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性,选择为高,若选择极性为低,则输出高低电平取反
  32. TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //输出使能
  33. TIM_OCInitStructure.TIM_Pulse = 0; //初始的CCR值
  34. TIM_OC2Init(TIM2, &TIM_OCInitStructure); //将结构体变量交给TIM_OC2Init,配置TIM2的输出比较通道2
  35. //TIM使能
  36. TIM_Cmd(TIM2, ENABLE); //使能TIM2,定时器开始运行
  37. }
  38. //PWM设置CCR
  39. void PWM_SetCompare2(uint16_t Compare)
  40. {
  41. TIM_SetCompare2(TIM2, Compare); //设置CCR2的值
  42. }

RCC_APB1PeriphClockCmd

  • TIM2 代表定时器2,它是STM32的一个基础硬件定时器。在STM32的某些系列中,TIM2连接到的是APB1总线。
  • ENABLE 是一个宏定义,用来开启某项功能,这里用来开启TIM2的时钟。如果传递 DISABLE 则会关闭外设的时钟。
  • 简单来说,RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); 这行代码的作用是开启连接到APB1总线的定时器2(TIM2)的时钟。只有开启了时钟,程序中关于TIM2的其他功能(如计时、计数、PWM发生等)才能正常工作。

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

  • GPIO的初始化中,选择AF_PP复用推挽输出,因为对于普通的开漏推挽输出,引脚的控制权是来自于输出数据寄存器的,如果想用定时器来控制引脚,就需要使用复用开漏/推挽输出模式。

时基单元中的数值设置:

代入公式为:

  • 频率 = CK_PSC(72M) / (PSC + 1) / (ARR + 1) = 50
  • 占空比 = CCR / (ARR + 1) 
  • 分辨率为 = 1 / (ARR + 1)
  • 因为PSC和ARR的值不固定,所以通过验证得出最适合的值为:ARR = 20000, PSC = 71,这时,ARR的20000代表20ms,如果CCR = 500,就是0.5ms,对应0°(-90),CCR = 2500,就是2.5ms,对应180°(+90)

3.2 PWM.h

接着是PWM.h文件,这部分引用声明一下即可

  1. #ifndef __PWM_H
  2. #define __PWM_H
  3. void PWM_Init(void);
  4. void PWM_SetCompare2(uint16_t Compare);
  5. #endif

 

3.3 Servo.c

这部分是舵机的角度参数设置代码: 

  1. #include "stm32f10x.h" // Device header
  2. #include "PWM.h"
  3. //函 数:舵机初始化
  4. void Servo_Init(void)
  5. {
  6. PWM_Init(); //初始化舵机的底层PWM
  7. }
  8. //舵机设置角度
  9. void Servo_SetAngle(float Angle)
  10. {
  11. PWM_SetCompare2(Angle / 180 * 2000 + 500); //设置占空比
  12. //将角度线性变换,对应到舵机要求的占空比范围上
  13. }

0°代表500,180°代表2500,角度相差180,CCR相差2000,所以角度除以180再乘以2000,加上偏移500。例如角度为180,180/180*2000 + 500 = 2500,对应180°

3.4 Servo.h

同样进行声明

  1. #ifndef __SERVO_H
  2. #define __SERVO_H
  3. void Servo_Init(void);
  4. void Servo_SetAngle(float Angle);
  5. #endif

3.5 main.c

使用刚刚编写的PWM和舵机代码函数来实现功能:

  1. #include "stm32f10x.h" // Device header
  2. #include "Delay.h"
  3. #include "OLED.h"
  4. #include "Servo.h"
  5. #include "Key.h"
  6. uint8_t KeyNum; //定义用于接收键码的变量
  7. float Angle; //定义角度变量
  8. int main(void)
  9. {
  10. //模块初始化
  11. OLED_Init(); //OLED初始化
  12. Servo_Init(); //舵机初始化
  13. Key_Init(); //按键初始化
  14. //显示静态字符串
  15. OLED_ShowString(1, 1, "Angle:"); //11列显示字符串Angle:
  16. while (1)
  17. {
  18. KeyNum = Key_GetNum(); //获取按键键码
  19. if (KeyNum == 1) //按键1按下
  20. {
  21. Angle += 30; //角度变量自增30
  22. if (Angle > 180) //角度变量超过180
  23. {
  24. Angle = 0; //角度变量归零
  25. }
  26. }
  27. Servo_SetAngle(Angle); //设置舵机的角度为角度变量
  28. OLED_ShowNum(1, 7, Angle, 3); //OLED显示角度变量
  29. }
  30. }

3.6 完整工程文件

STM32通过PWM驱动舵机

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/753056
推荐阅读
相关标签
  

闽ICP备14008679号