目录
Let'sDo第2期任务——《彩屏贪吃蛇》背景音乐及音效-个性化
通过PICO的PWM输出通过数字控制模拟信号,直接驱动扬声器,高效且功耗低。本次通过DECK2插针用来扩展音频,27管脚作为PWM输出接到蜂鸣上。
初始化代码中加入以下代码将27管脚设置为PWM输出,并 设置一个定时触发的中断函数on_pwm_wrap来改变PWM输出频率及幅值。
gpio_set_function(27, GPIO_FUNC_PWM); // Figure out which slice we just connected to the LED pin uint slice_num = pwm_gpio_to_slice_num(27); // Mask our slice's IRQ output into the PWM block's single interrupt line, // and register our interrupt handler pwm_clear_irq(slice_num); pwm_set_irq_enabled(slice_num, true); irq_set_exclusive_handler(PWM_IRQ_WRAP, on_pwm_wrap); irq_set_enabled(PWM_IRQ_WRAP, true); // Get some sensible defaults for the slice configuration. By default, the // counter is allowed to wrap over its maximum range (0 to 2**16-1) pwm_config config = pwm_get_default_config(); // Set divider, reduces counter clock to sysclock/this value pwm_config_set_clkdiv(&config, 1.f); pwm_config_set_wrap(&config, 20000); // Load the configuration into our PWM slice, and set it running. pwm_init(slice_num, &config, true);
在定时中断on_pwm_wrap函数中播放乐曲的音符,乐曲的每一个音符包含的信息有“频率”和“时长”两个信息,我们可以定义一个二维数组,数组的元素表示音符的频率和时长,整个数组表示一段音符,使用for循环即可播放这段音符。定义音符频率:根据音乐理论中的音阶频率表,为每个音符定义其对应的频率值。例如,C4=262Hz, D4=294Hz等。定义音符与频率之间的对应关系:
#define LC 262 #define LD 294 #define LE 330 #define LF 349 #define LG 392 #define LA 440 #define LAP_LBN 466 #define LB 494 #define MC 523 #define MD 587 #define ME 659 #define MEP 740 #define MF 698 #define MG 784 #define MA 880 #define MAP_MBN 932 #define MB 988 #define HC 1046 #define HD 1175 #define HE 1318 #define HF 1397 #define HG 1568 #define HA 1760 #define HB 1976 //定义一首乐曲数组 const unsigned int notes[] = { //音符库,四个八度 ME,ME,ME, ME,MD,MC, MC,LB,LA, LA,MC,ME, MA,MA,MA, MA,MG,MD, MF,ME,MD, MD,ME,MF, ME,MF,ME, MEP,MF,ME, ME,MD,MC, MC,LB,LA, LB,LB,LB, LB,MC,LB, LA,LA,LA, LA, ME,ME,ME, ME,MD,MC, MC,LB,LB, LB,LAP_LBN,LB, MA,MA,MA, MA,MB,MA, MA,MG,MG, MG,MA,MB, HC,HC,HC, HC,MB,MAP_MBN, MA,MA,MA, MA,ME,MD, ME,ME,ME, ME,MF,MD, MC,MC,MC, MC, };
在中断函数中实现乐曲的播放。设置一个全局变量数组sound_state[2],游戏进行时修改sound_state[0]为1,播放背景音乐,其他界面sound_state[0]为0不播放背景音乐。在游戏函数snake_move中吃到食物时设置sound_state[1]为1、过关时sound_state[1]为2,游戏结束时sound_state[1]为2, on_pwm_wrap()函数中根据sound_state变量内容播放不同的效果音效。
void on_pwm_wrap() { static int going_up = 0; static int sound_level; static int sound_f; // Clear the interrupt flag that brought us here pwm_clear_irq(pwm_gpio_to_slice_num(27)); if((sound_state[0])||(sound_state[1])) { going_up++; if(going_up>300) { going_up = 0 ; fade++; if (fade > 90) { fade = 0; } } sound_level = 1000; sound_f = 6000/notes[fade]; if(sound_state[1]==1) { sound_f = 10000; sound_level = 10000; sound_state[1]=0; } else if(sound_state[1]==2) { sound_f = 15000; sound_level = 10000; sound_state[1]--; } else if(sound_state[1]>2) { sound_f = 25000; sound_level = 10000; sound_state[1]--; } } else { going_up=0;fade=0;sound_level=0; } // Square the fade value to make the LED's brightness appear more linear // Note this range matches with the wrap value pwm_set_gpio_level(27, sound_level); // pwm_config config = pwm_get_default_config(); pwm_set_clkdiv(pwm_gpio_to_slice_num(27), sound_f); }
音效可参考视频,蜂鸣器音质太差,凑合听一下,后面有时间再优化。
https://www.bilibili.com/video/BV1GPpyebEko/?share_source=copy_web&vd_source=771c5bc0a24f31639a426bf66cb9e6c1
https://minkai-shi.github.io/