🎬 秋野酱:《个人主页》
🔥 个人专栏:《Java专栏》《Python专栏》
⛺️心若有所向往,何惧道阻且长
文章目录
- 需求
- 原来的驱动
- 移植操作
- 替换初始化
- 更新Play函数
- 完整代码
需求
通过控制PB9来播放音乐,PB9对应的定时器通道:Timer1 CH1
原来的驱动
#ifndef __BUZZER_H__
#define __BUZZER_H__#include "config.h"// 初始化蜂鸣器
void Buzzer_init();// 按照指定频率播放
void Buzzer_play(u16 hz_val);// 按照指定的音调播放 1,2,3,4,..7
void 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 timer_gpio_config(uint32_t gpio_rcu, uint32_t gpio_port, uint32_t gpio_pin, uint32_t gpio_af){rcu_periph_clock_enable(gpio_rcu); /* 设置gpio模式 */ gpio_mode_set(gpio_port, GPIO_MODE_AF, GPIO_PUPD_NONE, gpio_pin); gpio_output_options_set(gpio_port, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, gpio_pin); gpio_af_set(gpio_port, gpio_af, gpio_pin);
}void timer_init_config(uint32_t timer_periph, uint16_t t_prescaler, uint32_t t_period) {/*初始化参数 */timer_parameter_struct initpara;/* initialize TIMER init parameter struct */timer_struct_para_init(&initpara);/* 根据需要配置值 分频系数 (可以实现更低的timer频率) */initpara.prescaler = t_prescaler - 1;/* 1个周期的计数(period Max: 65535) Freq >= 2564 */initpara.period = t_period - 1;/* initialize TIMER counter */timer_init(timer_periph, &initpara);/* enable a TIMER */timer_enable(timer_periph);
}void timer_channel_config(uint32_t timer_periph, uint16_t channel) {/* TIMER 通道输出配置 */timer_oc_parameter_struct ocpara;/* initialize TIMER channel output parameter struct */timer_channel_output_struct_para_init(&ocpara);ocpara.outputstate = (uint16_t)TIMER_CCX_ENABLE;/* 配置输出参数 configure TIMER channel output function */timer_channel_output_config(timer_periph, channel, &ocpara);/* 配置通道输出输出比较模式 configure TIMER channel output compare mode */timer_channel_output_mode_config(timer_periph, channel, TIMER_OC_MODE_PWM0);
}#define TIMER_RCU RCU_TIMER1
#define TIMER_PERIPH TIMER1
#define TIMER_CHANNEL TIMER_CH_1
#define PRESCALER 10void Buzzer_init() {// PB9 Timer1_CH1 AF2// GPIO ----------------------------------------timer_gpio_config(RCU_GPIOB, GPIOB, GPIO_PIN_9, GPIO_AF_1);// TIMER----------------------------------------rcu_periph_clock_enable(TIMER_RCU);timer_deinit(TIMER_PERIPH);/* 升级频率*/rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL4);// 通道配置 -------------------------------------timer_channel_config(TIMER_PERIPH, TIMER_CHANNEL);
}
将原有的初始化逻辑修改为新的pwm更新
更新Play函数
// C D E F G A B C`
u16 hz[] = { 1047, 1175, 1319, 1397, 1568, 1760, 1976, 2093 };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) {// 根据系统主频和分频系数,计算周期uint16_t period = SystemCoreClock / (hz_val * PRESCALER);// 设置分频系数和周期计数值timer_init_config(TIMER_PERIPH, PRESCALER, period);// 设置输出脉冲值,范围是[0, 周期计数值)timer_channel_output_pulse_value_config(TIMER_PERIPH, TIMER_CHANNEL, (uint32_t)(period * 0.5f));
}void Buzzer_stop() {timer_disable(TIMER_PERIPH);
}
● 分频问题需要解决
● 分频根据hz值来设定
完整代码
#ifndef __BSP_BUZZER_H__
#define __BSP_BUZZER_H__#include "gd32f4xx.h"#ifndef u32
#define u32 uint32_t
#endif#ifndef u16
#define u16 uint16_t
#endif#ifndef u8
#define u8 uint8_t
#endif// 初始化蜂鸣器
void Buzzer_init();// 按照指定频率播放
void Buzzer_play(u16 hz_val);// 按照指定的音调播放 1,2,3,4,..7
void Buzzer_beep(u8 hz_val_index);// 停止播放
void Buzzer_stop();#endif
#include "bsp_buzzer.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 };
// >= 2564
void timer_gpio_config(uint32_t gpio_rcu, uint32_t gpio_port, uint32_t gpio_pin, uint32_t gpio_af){rcu_periph_clock_enable(gpio_rcu); /* 设置gpio模式 */ gpio_mode_set(gpio_port, GPIO_MODE_AF, GPIO_PUPD_NONE, gpio_pin); gpio_output_options_set(gpio_port, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, gpio_pin); gpio_af_set(gpio_port, gpio_af, gpio_pin);
}void timer_init_config(uint32_t timer_periph, uint16_t t_prescaler, uint32_t t_period) {/*初始化参数 */timer_parameter_struct initpara;/* initialize TIMER init parameter struct */timer_struct_para_init(&initpara);/* 根据需要配置值 分频系数 (可以实现更低的timer频率) */initpara.prescaler = t_prescaler - 1;/* 1个周期的计数(period Max: 65535) Freq >= 2564 */initpara.period = t_period - 1;/* initialize TIMER counter */timer_init(timer_periph, &initpara);/* enable a TIMER */timer_enable(timer_periph);
}void timer_channel_config(uint32_t timer_periph, uint16_t channel) {/* TIMER 通道输出配置 */timer_oc_parameter_struct ocpara;/* initialize TIMER channel output parameter struct */timer_channel_output_struct_para_init(&ocpara);ocpara.outputstate = (uint16_t)TIMER_CCX_ENABLE;/* 配置输出参数 configure TIMER channel output function */timer_channel_output_config(timer_periph, channel, &ocpara);/* 配置通道输出输出比较模式 configure TIMER channel output compare mode */timer_channel_output_mode_config(timer_periph, channel, TIMER_OC_MODE_PWM0);
}#define TIMER_RCU RCU_TIMER1
#define TIMER_PERIPH TIMER1
#define TIMER_CHANNEL TIMER_CH_1
#define PRESCALER 10void Buzzer_init() {// PB9 Timer1_CH1 AF2// GPIO ----------------------------------------timer_gpio_config(RCU_GPIOB, GPIOB, GPIO_PIN_9, GPIO_AF_1);// TIMER----------------------------------------rcu_periph_clock_enable(TIMER_RCU);timer_deinit(TIMER_PERIPH);/* 升级频率*/rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL4);// 通道配置 -------------------------------------timer_channel_config(TIMER_PERIPH, TIMER_CHANNEL);
}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) {// 根据系统主频和分频系数,计算周期uint16_t period = SystemCoreClock / (hz_val * PRESCALER);// 设置分频系数和周期计数值timer_init_config(TIMER_PERIPH, PRESCALER, period);// 设置输出脉冲值,范围是[0, 周期计数值)timer_channel_output_pulse_value_config(TIMER_PERIPH, TIMER_CHANNEL, (uint32_t)(period * 0.5f));
}void Buzzer_stop() {timer_disable(TIMER_PERIPH);
}