学习目标

  1. 实现舵机控制
  2. 实现板级舵机驱动

    学习内容

    原理图

    071.png
    8路PWM来控制舵机转动。

    舵机功能

    072.png
    073.png
    舵机PWM控制
转动角度 高电平时长(ms) 低电平时长(ms) 周期时长(ms) 占空比
0 0.5 19.5 20 2.5%
45 1 19 20 5%
90 1.5 18.5 20 7.5%
135 2 18 20 10%
180 2.5 17.5 20 12.5%

通过串口控制占空比的实现:

  1. #include "gd32f4xx.h"
  2. #include "systick.h"
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include "main.h"
  6. #include "Usart0.h"
  7. void PWM_config() {
  8. uint32_t timerx = TIMER1;
  9. uint32_t timerx_chn = TIMER_CH_3;
  10. uint32_t timerx_rcu = RCU_TIMER1;
  11. uint32_t timerx_prescaler = 1000 - 1;// 分频系数
  12. uint32_t timerx_period = SystemCoreClock / 50000 - 1; // 周期
  13. uint32_t timerx_port_rcu = RCU_GPIOA;
  14. uint32_t timerx_port = GPIOA;
  15. uint32_t timerx_pin = GPIO_PIN_3;
  16. uint32_t timerx_af = GPIO_AF_1;
  17. //////////////// GPIO config ///////////////
  18. // 配置时钟
  19. rcu_periph_clock_enable(timerx_port_rcu);
  20. // 配置GPIO模式
  21. gpio_mode_set(timerx_port, GPIO_MODE_AF, GPIO_PUPD_NONE, timerx_pin);
  22. // 配置GPIO输出
  23. gpio_output_options_set(timerx_port, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, timerx_pin);
  24. // 配置复用功能
  25. gpio_af_set(timerx_port, timerx_af, timerx_pin);
  26. /////////////// PWM config /////////////////
  27. // 配置时钟
  28. rcu_periph_clock_enable(timerx_rcu);
  29. // 时钟倍频
  30. rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL4);
  31. // timer复位
  32. timer_deinit(timerx);
  33. // 初始化timer
  34. timer_parameter_struct tps;
  35. timer_struct_para_init(&tps);
  36. tps.prescaler = timerx_prescaler; // 分频系数
  37. tps.period = timerx_period; // 周期计数
  38. timer_init(timerx, &tps);
  39. // 配置输出通道
  40. timer_oc_parameter_struct tops;
  41. tops.ocpolarity = TIMER_OC_POLARITY_HIGH;//电平极性
  42. tops.outputstate = TIMER_CCX_ENABLE;// 比较输出模式
  43. timer_channel_output_config(timerx, timerx_chn, &tops);
  44. // 配置输出的占空比
  45. timer_channel_output_pulse_value_config(timerx, timerx_chn, 0);
  46. timer_channel_output_mode_config(timerx, timerx_chn, TIMER_OC_MODE_PWM0);
  47. // timer_channel_output_shadow_config(timerx, timerx_chn, TIMER_OC_SHADOW_ENABLE);
  48. // timer_auto_reload_shadow_enable(timerx);
  49. // 使能timer
  50. timer_enable(timerx);
  51. }
  52. void PWM_update(float duty) {
  53. uint32_t timerx = TIMER1;
  54. uint32_t timerx_chn = TIMER_CH_3;
  55. uint32_t timerx_period = SystemCoreClock / 50000 - 1; // 周期
  56. // 更新占空比
  57. if(duty > 100) duty = 100;
  58. uint32_t pulse = duty * timerx_period / 100.0;
  59. timer_channel_output_pulse_value_config(timerx, timerx_chn, pulse);
  60. }
  61. void Usart0_recv(uint8_t *data, uint32_t len) {
  62. printf("recv: %s\r\n", data);
  63. float duty = atof((const char *)data);
  64. printf("duty: %f\r\n", duty);
  65. PWM_update(duty);
  66. }
  67. int main(void)
  68. {
  69. systick_config();
  70. Usart0_init();
  71. PWM_config();
  72. while(1) {
  73. }
  74. }

角度与占空比之间的关系:
duty = angle * (10 / 180) + 2.5
将串口接收代码改为如下:

  1. void Usart0_recv(uint8_t *data, uint32_t len) {
  2. printf("recv: %s\r\n", data);
  3. // float duty = atof((const char *)data);
  4. // printf("duty: %f\r\n", duty);
  5. // PWM_update(duty);
  6. float angle = atof((const char *)data);
  7. PWM_set_angle(angle);
  8. }

驱动封装

定义板级舵机驱动,控制8路舵机

  1. #ifndef __BSP_STEERING_H__
  2. #define __BSP_STEERING_H__
  3. #include "gd32f4xx.h"
  4. #include "systick.h"
  5. typedef struct {
  6. rcu_periph_enum rcu_gpio;
  7. uint32_t port;
  8. uint32_t pin;
  9. uint32_t af;
  10. rcu_periph_enum rcu_timer;
  11. uint32_t timer;
  12. uint32_t chn;
  13. } Steering_t;
  14. #define S0 (Steering_t){RCU_GPIOA, GPIOA, GPIO_PIN_3, GPIO_AF_1, RCU_TIMER1, TIMER1, TIMER_CH_3}
  15. #define S1 (Steering_t){RCU_GPIOA, GPIOA, GPIO_PIN_2, GPIO_AF_1, RCU_TIMER1, TIMER1, TIMER_CH_2}
  16. #define S2 (Steering_t){RCU_GPIOA, GPIOA, GPIO_PIN_0, GPIO_AF_1, RCU_TIMER1, TIMER1, TIMER_CH_0}
  17. #define S3 (Steering_t){RCU_GPIOA, GPIOA, GPIO_PIN_1, GPIO_AF_1, RCU_TIMER1, TIMER1, TIMER_CH_1}
  18. #define S4 (Steering_t){RCU_GPIOB, GPIOB, GPIO_PIN_4, GPIO_AF_2, RCU_TIMER2, TIMER2, TIMER_CH_0}
  19. #define S5 (Steering_t){RCU_GPIOB, GPIOB, GPIO_PIN_5, GPIO_AF_2, RCU_TIMER2, TIMER2, TIMER_CH_1}
  20. #define S6 (Steering_t){RCU_GPIOB, GPIOB, GPIO_PIN_0, GPIO_AF_2, RCU_TIMER2, TIMER2, TIMER_CH_2}
  21. #define S7 (Steering_t){RCU_GPIOB, GPIOB, GPIO_PIN_1, GPIO_AF_2, RCU_TIMER2, TIMER2, TIMER_CH_3}
  22. void Steering_init(Steering_t s);
  23. void Steering_turn(Steering_t s, float angle);
  24. #endif
  1. #include "bsp_steering.h"
  2. #define PRESCALER (100 - 1)
  3. #define PERIOD (SystemCoreClock / 5000 - 1)
  4. void Steering_init(Steering_t s) {
  5. /********* gpio config **********/
  6. // 配置时钟
  7. rcu_periph_clock_enable(s.rcu_gpio);
  8. // 配置GPIO模式
  9. gpio_mode_set(s.port, GPIO_MODE_AF, GPIO_PUPD_NONE, s.pin);
  10. // 配置GPIO输出
  11. gpio_output_options_set(s.port, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, s.pin);
  12. // 配置复用功能
  13. gpio_af_set(s.port, s.af, s.pin);
  14. /******** timer config *********/
  15. // 配置时钟
  16. rcu_periph_clock_enable(s.rcu_timer);
  17. // 时钟倍频
  18. rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL4);
  19. // // timer复位
  20. // timer_deinit(s.timer);
  21. // 初始化timer
  22. timer_parameter_struct tps;
  23. timer_struct_para_init(&tps);
  24. // 10s 执行 10000次,也就是1s执行1000s
  25. tps.prescaler = PRESCALER; // 分频系数
  26. tps.period = PERIOD; // 周期计数
  27. timer_init(s.timer, &tps);
  28. // 配置输出通道
  29. timer_oc_parameter_struct tops;
  30. tops.ocpolarity = TIMER_OC_POLARITY_HIGH;//电平极性
  31. tops.outputstate = TIMER_CCX_ENABLE;// 比较输出模式
  32. timer_channel_output_config(s.timer, s.chn, &tops);
  33. // 配置输出的占空比
  34. timer_channel_output_pulse_value_config(s.timer, s.chn, 0);
  35. timer_channel_output_mode_config(s.timer, s.chn, TIMER_OC_MODE_PWM0);
  36. // timer_channel_output_shadow_config(TIMER1, TIMER_CH_0, TIMER_OC_SHADOW_ENABLE);
  37. // timer_auto_reload_shadow_enable(TIMER1);
  38. // 使能timer
  39. timer_enable(s.timer);
  40. }
  41. void Steering_turn(Steering_t s, float angle) {
  42. float duty = angle * ( 10.0 / 180.0) + 2.5;
  43. uint32_t pulse = duty * PERIOD / 100.0;
  44. timer_channel_output_pulse_value_config(s.timer, s.chn, pulse);
  45. }

调用方式:

  1. #include "bsp_steering.h"
  2. ......
  3. // 初始化
  4. Steering_init(S0);
  5. Steering_init(S1);
  6. Steering_init(S2);
  7. Steering_init(S3);
  8. ......
  9. Steering_init(S7);
  10. // 转向
  11. Steering_turn(S0, 45);
  12. Steering_turn(S1, 45);
  13. ......
  14. Steering_turn(S7, 45);

练习题

  1. 实现舵机驱动封装