学习目标
转动角度 | 高电平时长(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);
// 初始化timer
timer_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);
// 使能timer
timer_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);
// 初始化timer
timer_parameter_struct tps;
timer_struct_para_init(&tps);
// 10s 执行 10000次,也就是1s执行1000s
tps.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);
// 使能timer
timer_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);
练习题
- 实现舵机驱动封装