学习目标
- 掌握驱动移植驱动
-
学习内容
需求
通过控制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);
////////// 输出模式配置
// ch2
timer_channel_output_mode_config(timerx, TIMER_CH_2, TIMER_OC_MODE_PWM0);
// 初始化
timer_enable(timerx);
}
```c
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);
}
原来的驱动
#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_PP
GPIO_Inilize(GPIO_P0, &GPIO_InitStructure);//初始化
}
void Buzzer_init(){
GPIO_config();
}
void Buzzer_beep(u8 hz_val_index){ // 1,2,3,4 ... 7
u16 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~65535
PWMx_InitStructure.PWM_DeadTime = 0; //死区发生器设置, 0~255
PWMx_InitStructure.PWM_EnoSelect = ENO5P; //输出通道选择, ENO1P,ENO1N,ENO2P,ENO2N,ENO3P,ENO3N,ENO4P,ENO4N / ENO5P,ENO6P,ENO7P,ENO8P
PWMx_InitStructure.PWM_PS_SW = PWM5_SW_P00;//切换端口
// 具体PWM端口配置
// pwm5
PWMx_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_MODE2
PWMx_InitStructure.PWM5_Duty = Period / 2; //PWM4占空比时间, 0~Period 声音的大小、响度
// pwm5
PWMx_InitStructure.PWM_CC5Enable = ENABLE; //开启PWM6P输入捕获/比较输出, ENABLE,DISABLE
// PWM启动配置
PWMx_InitStructure.PWM_MainOutEnable= ENABLE; //主输出使能, ENABLE,DISABLE
PWMx_InitStructure.PWM_CEN_Enable = ENABLE; //使能计数器, ENABLE,DISABLE
PWM_Configuration(PWMB, &PWMx_InitStructure); //初始化PWM, PWMA,PWMB
}
void Buzzer_stop(){
PWMx_InitDefine PWMx_InitStructure;
PWMx_InitStructure.PWM_MainOutEnable= DISABLE; //主输出使能, ENABLE,DISABLE
PWMx_InitStructure.PWM_CEN_Enable = DISABLE; //使能计数器, ENABLE,DISABLE
PWM_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);
// stop
Buzzer_stop();
delay_ms(20);
}
// stop
Buzzer_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; // 周期计数
// 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);
////////// 输出模式配置
// ch2
timer_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 ... 7
uint16_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