学习目标

  1. 掌握驱动移植驱动
  2. 掌握动态修改周期

    学习内容

    需求

    图像_2023-08-19_081042121.png
    通过控制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);

  1. ////////// 输出模式配置
  2. // ch2
  3. timer_channel_output_mode_config(timerx, TIMER_CH_2, TIMER_OC_MODE_PWM0);
  4. // 初始化
  5. timer_enable(timerx);

}

  1. ```c
  2. static void PWM_update_ch2(float duty) {
  3. uint32_t timerx = TIMER2;
  4. uint32_t timerx_chn = TIMER_CH_2;
  5. uint32_t pulse = duty * (PERIOD + 1) / 100;
  6. /***************** pwm update *******************/
  7. // 配置输出的占空比
  8. timer_channel_output_pulse_value_config(timerx, timerx_chn, pulse);
  9. }

原来的驱动

  1. #ifndef __BUZZER_H__
  2. #define __BUZZER_H__
  3. #include "config.h"
  4. // 初始化蜂鸣器
  5. void Buzzer_init();
  6. // 按照指定频率播放
  7. void Buzzer_play(u16 hz_val);
  8. // 按照指定的音调播放 1,2,3,4,..7
  9. void Buzzer_beep(u8 hz_val_index);
  10. // 停止播放
  11. void Buzzer_stop();
  12. #endif
  1. #include "Buzzer.h"
  2. #include "GPIO.h"
  3. #include "PWM.h"
  4. // C D E F G A B C`
  5. //u16 hz[] = {523, 587, 659, 698, 784, 880, 988, 1047};
  6. // C D E F G A B C`
  7. u16 hz[] = { 1047, 1175, 1319, 1397, 1568, 1760, 1976, 2093 };
  8. static void GPIO_config(void) {
  9. GPIO_InitTypeDef GPIO_InitStructure; //结构定义
  10. GPIO_InitStructure.Pin = GPIO_Pin_0; //指定要初始化的IO,
  11. GPIO_InitStructure.Mode = GPIO_OUT_PP; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
  12. GPIO_Inilize(GPIO_P0, &GPIO_InitStructure);//初始化
  13. }
  14. void Buzzer_init(){
  15. GPIO_config();
  16. }
  17. void Buzzer_beep(u8 hz_val_index){ // 1,2,3,4 ... 7
  18. u16 hz_val = hz[hz_val_index - 1];
  19. Buzzer_play(hz_val);
  20. }
  21. void Buzzer_play(u16 hz_val){
  22. u16 Period = MAIN_Fosc / hz_val;
  23. PWMx_InitDefine PWMx_InitStructure;
  24. // 总配置
  25. // (MAIN_Fosc / 1000 - 1) 周期计数值
  26. PWMx_InitStructure.PWM_Period = Period - 1; //周期时间, 0~65535
  27. PWMx_InitStructure.PWM_DeadTime = 0; //死区发生器设置, 0~255
  28. PWMx_InitStructure.PWM_EnoSelect = ENO5P; //输出通道选择, ENO1P,ENO1N,ENO2P,ENO2N,ENO3P,ENO3N,ENO4P,ENO4N / ENO5P,ENO6P,ENO7P,ENO8P
  29. PWMx_InitStructure.PWM_PS_SW = PWM5_SW_P00;//切换端口
  30. // 具体PWM端口配置
  31. // pwm5
  32. 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
  33. PWMx_InitStructure.PWM5_Duty = Period / 2; //PWM4占空比时间, 0~Period 声音的大小、响度
  34. // pwm5
  35. PWMx_InitStructure.PWM_CC5Enable = ENABLE; //开启PWM6P输入捕获/比较输出, ENABLE,DISABLE
  36. // PWM启动配置
  37. PWMx_InitStructure.PWM_MainOutEnable= ENABLE; //主输出使能, ENABLE,DISABLE
  38. PWMx_InitStructure.PWM_CEN_Enable = ENABLE; //使能计数器, ENABLE,DISABLE
  39. PWM_Configuration(PWMB, &PWMx_InitStructure); //初始化PWM, PWMA,PWMB
  40. }
  41. void Buzzer_stop(){
  42. PWMx_InitDefine PWMx_InitStructure;
  43. PWMx_InitStructure.PWM_MainOutEnable= DISABLE; //主输出使能, ENABLE,DISABLE
  44. PWMx_InitStructure.PWM_CEN_Enable = DISABLE; //使能计数器, ENABLE,DISABLE
  45. PWM_Configuration(PWMB, &PWMx_InitStructure); //初始化PWM, PWMA,PWMB
  46. }
  1. #include "config.h"
  2. #include "delay.h"
  3. #include "GPIO.h"
  4. #include "Buzzer.h"
  5. // 两只老虎
  6. // 音符
  7. u8 code notes[] = {
  8. 1, 2, 3, 1, 1, 2, 3, 1, 3, 4, 5, 3, 4, 5,
  9. 5, 6, 5, 4, 3, 1, 5, 6, 5, 4, 3, 1, 1, 5, 1, 1, 5, 1,
  10. };
  11. // 延时时长
  12. u8 code durations[] = {
  13. 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 4, 4, 8,
  14. 3, 1, 3, 1, 4, 4, 3, 1, 3, 1, 4, 4, 4, 4, 8, 4, 4, 8,
  15. };
  16. int main() {
  17. u8 i = 0;
  18. u8 len = 0;
  19. u16 delay = 0;
  20. Buzzer_init();
  21. len = sizeof(notes) / sizeof(u8);
  22. while(1) {
  23. for(i = 0; i < len; i++){
  24. Buzzer_beep(notes[i]);
  25. delay = durations[i] * 100;
  26. // 声响延时
  27. delay_X_ms(delay);
  28. // stop
  29. Buzzer_stop();
  30. delay_ms(20);
  31. }
  32. // stop
  33. Buzzer_stop();
  34. delay_ms(250);
  35. delay_ms(250);
  36. delay_ms(250);
  37. delay_ms(250);
  38. }
  39. }

移植操作

替换初始化

  1. void Buzzer_init(){
  2. PWM_config();
  3. }

将原有的初始化逻辑修改为新的pwm更新

更新Play函数

  1. void Buzzer_play(uint16_t hz_val){
  2. period = SystemCoreClock / hz_val / 10 - 1;
  3. uint32_t timerx = TIMER2;
  4. // 初始化定时器
  5. timer_parameter_struct tps;
  6. timer_struct_para_init(&tps);
  7. tps.prescaler = 10 - 1; // 分频计数
  8. tps.period = period; // 周期计数
  9. timer_init(timerx, &tps);
  10. PWM_update_ch2(50);
  11. }
  • 分频问题需要解决
  • 分频根据hz值来设定

    完整代码

    ```c

    ifndef BSP_BUZZER_H

    define BSP_BUZZER_H

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

  1. ```c
  2. #include "bsp_buzzer.h"
  3. #define PRESCALER (10 - 1)
  4. #define PERIOD (SystemCoreClock / 100000 - 1)
  5. uint16_t period;
  6. // C D E F G A B C`
  7. //u16 hz[] = {523, 587, 659, 698, 784, 880, 988, 1047};
  8. // C D E F G A B C`
  9. uint16_t hz[] = { 1047, 1175, 1319, 1397, 1568, 1760, 1976, 2093 };
  10. static void PWM_config() {
  11. uint32_t timerx = TIMER2;
  12. uint32_t timerx_rcu = RCU_TIMER2;
  13. uint32_t timerx_psc = RCU_TIMER_PSC_MUL4;
  14. uint32_t timerx_prescaler = PRESCALER; // 分频计数
  15. uint32_t timerx_period = PERIOD; // 周期计数
  16. // ch2
  17. uint32_t timerx_ch2_port = GPIOB;
  18. uint32_t timerx_ch2_port_rcu = RCU_GPIOB;
  19. uint32_t timerx_ch2_pin = GPIO_PIN_0;
  20. uint32_t timerx_ch2_af = GPIO_AF_2;
  21. /*************** GPIO config **************/
  22. //// ch2
  23. //// p
  24. // 配置时钟
  25. rcu_periph_clock_enable(timerx_ch2_port_rcu);
  26. // 配置GPIO模式
  27. gpio_mode_set(timerx_ch2_port, GPIO_MODE_AF, GPIO_PUPD_NONE, timerx_ch2_pin);
  28. // 配置GPIO输出
  29. gpio_output_options_set(timerx_ch2_port, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, timerx_ch2_pin);
  30. // 配置复用功能
  31. gpio_af_set(timerx_ch2_port, timerx_ch2_af, timerx_ch2_pin);
  32. /*************** Timer config *************/
  33. // 时钟配置
  34. rcu_periph_clock_enable(timerx_rcu);
  35. // 复位定时器
  36. timer_deinit(timerx);
  37. // 倍频配置
  38. rcu_timer_clock_prescaler_config(timerx_psc);
  39. // 初始化定时器
  40. timer_parameter_struct tps;
  41. timer_struct_para_init(&tps);
  42. tps.prescaler = timerx_prescaler; // 分频计数
  43. tps.period = timerx_period; // 周期计数
  44. timer_init(timerx, &tps);
  45. ////////// 配置输出通道
  46. timer_oc_parameter_struct tops;
  47. ///// ch2
  48. timer_channel_output_struct_para_init(&tops);
  49. // p config
  50. tops.outputstate = TIMER_CCX_ENABLE;
  51. timer_channel_output_config(timerx, TIMER_CH_2, &tops);
  52. ////////// 输出模式配置
  53. // ch2
  54. timer_channel_output_mode_config(timerx, TIMER_CH_2, TIMER_OC_MODE_PWM0);
  55. // 初始化
  56. timer_enable(timerx);
  57. }
  58. static void PWM_update_ch2(float duty) {
  59. uint32_t timerx = TIMER2;
  60. uint32_t timerx_chn = TIMER_CH_2;
  61. uint32_t pulse = duty * (period + 1) / 100;
  62. /***************** pwm update *******************/
  63. // 配置输出的占空比
  64. timer_channel_output_pulse_value_config(timerx, timerx_chn, pulse);
  65. }
  66. void Buzzer_init(){
  67. PWM_config();
  68. }
  69. void Buzzer_beep(uint8_t hz_val_index){ // 1,2,3,4 ... 7
  70. uint16_t hz_val = hz[hz_val_index - 1];
  71. Buzzer_play(hz_val);
  72. }
  73. void Buzzer_play(uint16_t hz_val){
  74. period = SystemCoreClock / hz_val / 10 - 1;
  75. uint32_t timerx = TIMER2;
  76. // 初始化定时器
  77. timer_parameter_struct tps;
  78. timer_struct_para_init(&tps);
  79. tps.prescaler = 10 - 1; // 分频计数
  80. tps.period = period; // 周期计数
  81. timer_init(timerx, &tps);
  82. PWM_update_ch2(50);
  83. }
  84. void Buzzer_stop(){
  85. PWM_update_ch2(0);
  86. }

练习题

  1. 实现buzzer播放music
  2. 体会所有Timer的逻辑,尝试封装Timer