学习目标
| 转动角度 | 高电平时长(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% |
通过串口控制占空比的实现:
#include "gd32f4xx.h"#include "systick.h"#include <stdio.h>#include <stdlib.h>#include "main.h"#include "Usart0.h"void PWM_config() {uint32_t timerx = TIMER1;uint32_t timerx_chn = TIMER_CH_3;uint32_t timerx_rcu = RCU_TIMER1;uint32_t timerx_prescaler = 1000 - 1;// 分频系数uint32_t timerx_period = SystemCoreClock / 50000 - 1; // 周期uint32_t timerx_port_rcu = RCU_GPIOA;uint32_t timerx_port = GPIOA;uint32_t timerx_pin = GPIO_PIN_3;uint32_t timerx_af = GPIO_AF_1;//////////////// GPIO config ///////////////// 配置时钟rcu_periph_clock_enable(timerx_port_rcu);// 配置GPIO模式gpio_mode_set(timerx_port, GPIO_MODE_AF, GPIO_PUPD_NONE, timerx_pin);// 配置GPIO输出gpio_output_options_set(timerx_port, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, timerx_pin);// 配置复用功能gpio_af_set(timerx_port, timerx_af, timerx_pin);/////////////// PWM config /////////////////// 配置时钟rcu_periph_clock_enable(timerx_rcu);// 时钟倍频rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL4);// timer复位timer_deinit(timerx);// 初始化timertimer_parameter_struct tps;timer_struct_para_init(&tps);tps.prescaler = timerx_prescaler; // 分频系数tps.period = timerx_period; // 周期计数timer_init(timerx, &tps);// 配置输出通道timer_oc_parameter_struct tops;tops.ocpolarity = TIMER_OC_POLARITY_HIGH;//电平极性tops.outputstate = TIMER_CCX_ENABLE;// 比较输出模式timer_channel_output_config(timerx, timerx_chn, &tops);// 配置输出的占空比timer_channel_output_pulse_value_config(timerx, timerx_chn, 0);timer_channel_output_mode_config(timerx, timerx_chn, TIMER_OC_MODE_PWM0);// timer_channel_output_shadow_config(timerx, timerx_chn, TIMER_OC_SHADOW_ENABLE);// timer_auto_reload_shadow_enable(timerx);// 使能timertimer_enable(timerx);}void PWM_update(float duty) {uint32_t timerx = TIMER1;uint32_t timerx_chn = TIMER_CH_3;uint32_t timerx_period = SystemCoreClock / 50000 - 1; // 周期// 更新占空比if(duty > 100) duty = 100;uint32_t pulse = duty * timerx_period / 100.0;timer_channel_output_pulse_value_config(timerx, timerx_chn, pulse);}void Usart0_recv(uint8_t *data, uint32_t len) {printf("recv: %s\r\n", data);float duty = atof((const char *)data);printf("duty: %f\r\n", duty);PWM_update(duty);}int main(void){systick_config();Usart0_init();PWM_config();while(1) {}}
角度与占空比之间的关系:
duty = angle * (10 / 180) + 2.5
将串口接收代码改为如下:
void Usart0_recv(uint8_t *data, uint32_t len) {printf("recv: %s\r\n", data);// float duty = atof((const char *)data);// printf("duty: %f\r\n", duty);// PWM_update(duty);float angle = atof((const char *)data);PWM_set_angle(angle);}
驱动封装
定义板级舵机驱动,控制8路舵机
#ifndef __BSP_STEERING_H__#define __BSP_STEERING_H__#include "gd32f4xx.h"#include "systick.h"typedef struct {rcu_periph_enum rcu_gpio;uint32_t port;uint32_t pin;uint32_t af;rcu_periph_enum rcu_timer;uint32_t timer;uint32_t chn;} Steering_t;#define S0 (Steering_t){RCU_GPIOA, GPIOA, GPIO_PIN_3, GPIO_AF_1, RCU_TIMER1, TIMER1, TIMER_CH_3}#define S1 (Steering_t){RCU_GPIOA, GPIOA, GPIO_PIN_2, GPIO_AF_1, RCU_TIMER1, TIMER1, TIMER_CH_2}#define S2 (Steering_t){RCU_GPIOA, GPIOA, GPIO_PIN_0, GPIO_AF_1, RCU_TIMER1, TIMER1, TIMER_CH_0}#define S3 (Steering_t){RCU_GPIOA, GPIOA, GPIO_PIN_1, GPIO_AF_1, RCU_TIMER1, TIMER1, TIMER_CH_1}#define S4 (Steering_t){RCU_GPIOB, GPIOB, GPIO_PIN_4, GPIO_AF_2, RCU_TIMER2, TIMER2, TIMER_CH_0}#define S5 (Steering_t){RCU_GPIOB, GPIOB, GPIO_PIN_5, GPIO_AF_2, RCU_TIMER2, TIMER2, TIMER_CH_1}#define S6 (Steering_t){RCU_GPIOB, GPIOB, GPIO_PIN_0, GPIO_AF_2, RCU_TIMER2, TIMER2, TIMER_CH_2}#define S7 (Steering_t){RCU_GPIOB, GPIOB, GPIO_PIN_1, GPIO_AF_2, RCU_TIMER2, TIMER2, TIMER_CH_3}void Steering_init(Steering_t s);void Steering_turn(Steering_t s, float angle);#endif
#include "bsp_steering.h"#define PRESCALER (100 - 1)#define PERIOD (SystemCoreClock / 5000 - 1)void Steering_init(Steering_t s) {/********* gpio config **********/// 配置时钟rcu_periph_clock_enable(s.rcu_gpio);// 配置GPIO模式gpio_mode_set(s.port, GPIO_MODE_AF, GPIO_PUPD_NONE, s.pin);// 配置GPIO输出gpio_output_options_set(s.port, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, s.pin);// 配置复用功能gpio_af_set(s.port, s.af, s.pin);/******** timer config *********/// 配置时钟rcu_periph_clock_enable(s.rcu_timer);// 时钟倍频rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL4);// // timer复位// timer_deinit(s.timer);// 初始化timertimer_parameter_struct tps;timer_struct_para_init(&tps);// 10s 执行 10000次,也就是1s执行1000stps.prescaler = PRESCALER; // 分频系数tps.period = PERIOD; // 周期计数timer_init(s.timer, &tps);// 配置输出通道timer_oc_parameter_struct tops;tops.ocpolarity = TIMER_OC_POLARITY_HIGH;//电平极性tops.outputstate = TIMER_CCX_ENABLE;// 比较输出模式timer_channel_output_config(s.timer, s.chn, &tops);// 配置输出的占空比timer_channel_output_pulse_value_config(s.timer, s.chn, 0);timer_channel_output_mode_config(s.timer, s.chn, TIMER_OC_MODE_PWM0);// timer_channel_output_shadow_config(TIMER1, TIMER_CH_0, TIMER_OC_SHADOW_ENABLE);// timer_auto_reload_shadow_enable(TIMER1);// 使能timertimer_enable(s.timer);}void Steering_turn(Steering_t s, float angle) {float duty = angle * ( 10.0 / 180.0) + 2.5;uint32_t pulse = duty * PERIOD / 100.0;timer_channel_output_pulse_value_config(s.timer, s.chn, pulse);}
调用方式:
#include "bsp_steering.h"......// 初始化Steering_init(S0);Steering_init(S1);Steering_init(S2);Steering_init(S3);......Steering_init(S7);// 转向Steering_turn(S0, 45);Steering_turn(S1, 45);......Steering_turn(S7, 45);
练习题
- 实现舵机驱动封装



