学习目标
- 掌握驱动移植驱动
-
学习内容
需求

通过控制PB0来播放音乐
PB0,采用Timer2 CH2来实现Timer功能实现
```c static void PWM_config() { uint32_t timerx = TIMER2; uint32_t timerx_rcu = RCU_TIMER2; uint32_t timerx_psc = RCU_TIMER_PSC_MUL4;
uint32_t timerx_prescaler = PRESCALER; // 分频计数 uint32_t timerx_period = PERIOD; // 周期计数
// ch2 uint32_t timerx_ch2_port = GPIOB; uint32_t timerx_ch2_port_rcu = RCU_GPIOB; uint32_t timerx_ch2_pin = GPIO_PIN_0; uint32_t timerx_ch2_af = GPIO_AF_2;
/* GPIO config **/ //// ch2 //// p // 配置时钟 rcu_periph_clock_enable(timerx_ch2_port_rcu); // 配置GPIO模式 gpio_mode_set(timerx_ch2_port, GPIO_MODE_AF, GPIO_PUPD_NONE, timerx_ch2_pin); // 配置GPIO输出 gpio_output_options_set(timerx_ch2_port, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, timerx_ch2_pin); // 配置复用功能 gpio_af_set(timerx_ch2_port, timerx_ch2_af, timerx_ch2_pin);
/* Timer config */ // 时钟配置 rcu_periph_clock_enable(timerx_rcu); // 复位定时器 timer_deinit(timerx); // 倍频配置 rcu_timer_clock_prescaler_config(timerx_psc);
// 初始化定时器 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; ///// ch2 timer_channel_output_struct_para_init(&tops); // p config tops.outputstate = TIMER_CCX_ENABLE; timer_channel_output_config(timerx, TIMER_CH_2, &tops);
////////// 输出模式配置// ch2timer_channel_output_mode_config(timerx, TIMER_CH_2, TIMER_OC_MODE_PWM0);// 初始化timer_enable(timerx);
}
```cstatic void PWM_update_ch2(float duty) {uint32_t timerx = TIMER2;uint32_t timerx_chn = TIMER_CH_2;uint32_t pulse = duty * (PERIOD + 1) / 100;/***************** pwm update *******************/// 配置输出的占空比timer_channel_output_pulse_value_config(timerx, timerx_chn, pulse);}
原来的驱动
#ifndef __BUZZER_H__#define __BUZZER_H__#include "config.h"// 初始化蜂鸣器void Buzzer_init();// 按照指定频率播放void Buzzer_play(u16 hz_val);// 按照指定的音调播放 1,2,3,4,..7void Buzzer_beep(u8 hz_val_index);// 停止播放void Buzzer_stop();#endif
#include "Buzzer.h"#include "GPIO.h"#include "PWM.h"// C D E F G A B C`//u16 hz[] = {523, 587, 659, 698, 784, 880, 988, 1047};// C D E F G A B C`u16 hz[] = { 1047, 1175, 1319, 1397, 1568, 1760, 1976, 2093 };static void GPIO_config(void) {GPIO_InitTypeDef GPIO_InitStructure; //结构定义GPIO_InitStructure.Pin = GPIO_Pin_0; //指定要初始化的IO,GPIO_InitStructure.Mode = GPIO_OUT_PP; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PPGPIO_Inilize(GPIO_P0, &GPIO_InitStructure);//初始化}void Buzzer_init(){GPIO_config();}void Buzzer_beep(u8 hz_val_index){ // 1,2,3,4 ... 7u16 hz_val = hz[hz_val_index - 1];Buzzer_play(hz_val);}void Buzzer_play(u16 hz_val){u16 Period = MAIN_Fosc / hz_val;PWMx_InitDefine PWMx_InitStructure;// 总配置// (MAIN_Fosc / 1000 - 1) 周期计数值PWMx_InitStructure.PWM_Period = Period - 1; //周期时间, 0~65535PWMx_InitStructure.PWM_DeadTime = 0; //死区发生器设置, 0~255PWMx_InitStructure.PWM_EnoSelect = ENO5P; //输出通道选择, ENO1P,ENO1N,ENO2P,ENO2N,ENO3P,ENO3N,ENO4P,ENO4N / ENO5P,ENO6P,ENO7P,ENO8PPWMx_InitStructure.PWM_PS_SW = PWM5_SW_P00;//切换端口// 具体PWM端口配置// pwm5PWMx_InitStructure.PWM5_Mode = CCMRn_PWM_MODE1; //模式, CCMRn_FREEZE,CCMRn_MATCH_VALID,CCMRn_MATCH_INVALID,CCMRn_ROLLOVER,CCMRn_FORCE_INVALID,CCMRn_FORCE_VALID,CCMRn_PWM_MODE1,CCMRn_PWM_MODE2PWMx_InitStructure.PWM5_Duty = Period / 2; //PWM4占空比时间, 0~Period 声音的大小、响度// pwm5PWMx_InitStructure.PWM_CC5Enable = ENABLE; //开启PWM6P输入捕获/比较输出, ENABLE,DISABLE// PWM启动配置PWMx_InitStructure.PWM_MainOutEnable= ENABLE; //主输出使能, ENABLE,DISABLEPWMx_InitStructure.PWM_CEN_Enable = ENABLE; //使能计数器, ENABLE,DISABLEPWM_Configuration(PWMB, &PWMx_InitStructure); //初始化PWM, PWMA,PWMB}void Buzzer_stop(){PWMx_InitDefine PWMx_InitStructure;PWMx_InitStructure.PWM_MainOutEnable= DISABLE; //主输出使能, ENABLE,DISABLEPWMx_InitStructure.PWM_CEN_Enable = DISABLE; //使能计数器, ENABLE,DISABLEPWM_Configuration(PWMB, &PWMx_InitStructure); //初始化PWM, PWMA,PWMB}
#include "config.h"#include "delay.h"#include "GPIO.h"#include "Buzzer.h"// 两只老虎// 音符u8 code notes[] = {1, 2, 3, 1, 1, 2, 3, 1, 3, 4, 5, 3, 4, 5,5, 6, 5, 4, 3, 1, 5, 6, 5, 4, 3, 1, 1, 5, 1, 1, 5, 1,};// 延时时长u8 code durations[] = {4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 4, 4, 8,3, 1, 3, 1, 4, 4, 3, 1, 3, 1, 4, 4, 4, 4, 8, 4, 4, 8,};int main() {u8 i = 0;u8 len = 0;u16 delay = 0;Buzzer_init();len = sizeof(notes) / sizeof(u8);while(1) {for(i = 0; i < len; i++){Buzzer_beep(notes[i]);delay = durations[i] * 100;// 声响延时delay_X_ms(delay);// stopBuzzer_stop();delay_ms(20);}// stopBuzzer_stop();delay_ms(250);delay_ms(250);delay_ms(250);delay_ms(250);}}
移植操作
替换初始化
void Buzzer_init(){PWM_config();}
更新Play函数
void Buzzer_play(uint16_t hz_val){period = SystemCoreClock / hz_val / 10 - 1;uint32_t timerx = TIMER2;// 初始化定时器timer_parameter_struct tps;timer_struct_para_init(&tps);tps.prescaler = 10 - 1; // 分频计数tps.period = period; // 周期计数timer_init(timerx, &tps);PWM_update_ch2(50);}
include “gd32f4xx.h”
// 初始化蜂鸣器 void Buzzer_init();
// 按照指定频率播放 void Buzzer_play(uint16_t hz_val);
// 按照指定的音调播放 1,2,3,4,..7 void Buzzer_beep(uint8_t hz_val_index);
// 停止播放 void Buzzer_stop();
endif
```c#include "bsp_buzzer.h"#define PRESCALER (10 - 1)#define PERIOD (SystemCoreClock / 100000 - 1)uint16_t period;// C D E F G A B C`//u16 hz[] = {523, 587, 659, 698, 784, 880, 988, 1047};// C D E F G A B C`uint16_t hz[] = { 1047, 1175, 1319, 1397, 1568, 1760, 1976, 2093 };static void PWM_config() {uint32_t timerx = TIMER2;uint32_t timerx_rcu = RCU_TIMER2;uint32_t timerx_psc = RCU_TIMER_PSC_MUL4;uint32_t timerx_prescaler = PRESCALER; // 分频计数uint32_t timerx_period = PERIOD; // 周期计数// ch2uint32_t timerx_ch2_port = GPIOB;uint32_t timerx_ch2_port_rcu = RCU_GPIOB;uint32_t timerx_ch2_pin = GPIO_PIN_0;uint32_t timerx_ch2_af = GPIO_AF_2;/*************** GPIO config **************///// ch2//// p// 配置时钟rcu_periph_clock_enable(timerx_ch2_port_rcu);// 配置GPIO模式gpio_mode_set(timerx_ch2_port, GPIO_MODE_AF, GPIO_PUPD_NONE, timerx_ch2_pin);// 配置GPIO输出gpio_output_options_set(timerx_ch2_port, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, timerx_ch2_pin);// 配置复用功能gpio_af_set(timerx_ch2_port, timerx_ch2_af, timerx_ch2_pin);/*************** Timer config *************/// 时钟配置rcu_periph_clock_enable(timerx_rcu);// 复位定时器timer_deinit(timerx);// 倍频配置rcu_timer_clock_prescaler_config(timerx_psc);// 初始化定时器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;///// ch2timer_channel_output_struct_para_init(&tops);// p configtops.outputstate = TIMER_CCX_ENABLE;timer_channel_output_config(timerx, TIMER_CH_2, &tops);////////// 输出模式配置// ch2timer_channel_output_mode_config(timerx, TIMER_CH_2, TIMER_OC_MODE_PWM0);// 初始化timer_enable(timerx);}static void PWM_update_ch2(float duty) {uint32_t timerx = TIMER2;uint32_t timerx_chn = TIMER_CH_2;uint32_t pulse = duty * (period + 1) / 100;/***************** pwm update *******************/// 配置输出的占空比timer_channel_output_pulse_value_config(timerx, timerx_chn, pulse);}void Buzzer_init(){PWM_config();}void Buzzer_beep(uint8_t hz_val_index){ // 1,2,3,4 ... 7uint16_t hz_val = hz[hz_val_index - 1];Buzzer_play(hz_val);}void Buzzer_play(uint16_t hz_val){period = SystemCoreClock / hz_val / 10 - 1;uint32_t timerx = TIMER2;// 初始化定时器timer_parameter_struct tps;timer_struct_para_init(&tps);tps.prescaler = 10 - 1; // 分频计数tps.period = period; // 周期计数timer_init(timerx, &tps);PWM_update_ch2(50);}void Buzzer_stop(){PWM_update_ch2(0);}
练习题
- 实现buzzer播放music
- 体会所有Timer的逻辑,尝试封装Timer
