用龙芯1c库实现无源蜂鸣器唱歌《送别》

xiaoxiao2021-02-28  132

龙芯1c库是把龙芯1c的常用外设的常用功能封装为一个库,可用于裸机编程和实时系统,类似于STM32库。Git地址:http://git.oschina.NET/caogos/OpenLoongsonLib1c

无源蜂鸣器唱歌的原理

基本原理

一般说来,单片机演奏音乐基本都是单音频率,它不包含相应幅度的谐波频率,也就是说不能象电子琴那样能奏出多种音色的声音。因此单片机奏乐只需弄清楚两个概念即可,也就是“音调”和“节拍”。音调表示一个音符唱多高的频率,节拍表示一个音符唱多长的时间。 

音调

音调简介

一个音调对应一个频率。即do re mi fa so la xi。乐谱中有高音,中音和低音,每个都有do re mi fa so la xi。即总共3*7=21个频率。

// do re mi fa so la xi的低音频率(单位hz) #define BUZZER_LOW_DO_1 (262) #define BUZZER_LOW_RE_2 (294) #define BUZZER_LOW_MI_3 (330) #define BUZZER_LOW_FA_4 (349) #define BUZZER_LOW_SO_5 (392) #define BUZZER_LOW_LA_6 (440) #define BUZZER_LOW_XI_7 (494) // 中音 #define BUZZER_MIDDLE_DO_1 (523) #define BUZZER_MIDDLE_RE_2 (587) #define BUZZER_MIDDLE_MI_3 (659) #define BUZZER_MIDDLE_FA_4 (698) #define BUZZER_MIDDLE_SO_5 (784) #define BUZZER_MIDDLE_LA_6 (880) #define BUZZER_MIDDLE_XI_7 (988) // 高音 #define BUZZER_HIGH_DO_1 (1047) #define BUZZER_HIGH_RE_2 (1175) #define BUZZER_HIGH_MI_3 (1319) #define BUZZER_HIGH_FA_4 (1397) #define BUZZER_HIGH_SO_5 (1568) #define BUZZER_HIGH_LA_6 (1760) #define BUZZER_HIGH_XI_7 (1976)

识别乐谱中的高低音

5351中的1是高音,音符1的上方有个小圆点; 615中的1也是高音; 其它的都是中音。 和高音相反,低音是在音符的底下有个小圆点。

无源蜂鸣器和有缘蜂鸣器的区别

注意,这里的“源”不是指电源。而是指震荡源。 无源蜂鸣器的特点是: 1 无源内部不带震荡源,所以如果用直流信号无法令其鸣叫。必须用2K~5K的方波去驱动它 2 声音频率可控,可以做出“多来米发索拉西”的效果。 3 在一些特例中,可以和LED复用一个控制口 有源蜂鸣器的特点是: 1 有源蜂鸣器内部带震荡源,所以只要一通电就会叫 2 程序控制方便,单片机一个高低电平就可以让其发出声音,而无源蜂鸣器却做不到。

音调的软件实现

经过前面介绍,已经知道一个音调对应一个频率,给无源蜂鸣器不同频率的方波可以唱出do re mi fa so la xi。 通常,使用硬件PWM产生占空比为50%的不同频率的方波来实现。 龙芯1c库中已经有现成的PWM接口可供使用,接口中PWM周期的时间单位为ns,即PWM周期T = 1000000000 / freq。另外,目前(2017年7月)龙芯1c库中浮点功能还未完善,所以需要把占空比(浮点数)手动换算为高低电平的时间长度,占空比为50%,即周期T / 2就是一个PWM波形内高低电平的时间长度。虽然,我坚信使用浮点功能早晚会调通的,龙芯1C库中的PWM接口用占空比来表示也更符合人们的习惯,但这里还是需要稍微变通一下。

// 播放指定音高 void buzzer_sound(unsigned int freq) { buzzer_pwm.period_ns = 1000000000 / freq; buzzer_pwm.low_ns = buzzer_pwm.period_ns / 2; pwm_init(&buzzer_pwm); return ; }

节拍

节拍简介

节拍表示一个音符唱多长的时间,即一个频率的PWM波形的持续时间。

识别乐谱中的节拍

参考百度文库的《简谱中常用的音乐记号》

在一张乐谱中,我们经常会看到这样的表达式,如1=C (4/4) 、1=G(3/4) ……  等等,这里1=C (4/4),1=G(3/4) 表示乐谱的曲调,和我们前面所谈的音调有很大的关联,4/4、3/4  就是用来表示节拍的。以3/4 为例加以说明,它表示乐谱中以四分音符为节拍,每一小结有三拍。 

其中1 、2 为一拍,3、4、5为一拍,6为一拍共三拍。1 、2的时长为四分音符的一半,即为八分音符长,3、4的时长为八分音符的一半,即为十六分音符长,5的时长为四分音符的一半,即为八分音符长,6的时长为四分音符长。 一般说来,如果乐曲没有特殊说明,一拍的时长大约为400—500ms。

节拍的软件实现

根据前面介绍已经知道,节拍就是频率持续的时间。并且一拍的时间为四五百ms,这里选择一拍为400ms,那么十六分音符长为400ms / 16 = 25ms,毫秒级的延时用“龙芯1c库”中的函数delay_ms(n)实现是没问题的。

// 测试无源蜂鸣器--依次播放do re mi fa so la xi void buzzer_test(void) { buzzer_init(); buzzer_sound(BUZZER_LOW_DO_1); delay_ms(BUZZER_DELAY_ONE_NOTE); buzzer_sound(BUZZER_LOW_RE_2); delay_ms(BUZZER_DELAY_ONE_NOTE); buzzer_sound(BUZZER_LOW_MI_3); delay_ms(BUZZER_DELAY_ONE_NOTE); buzzer_sound(BUZZER_LOW_FA_4); delay_ms(BUZZER_DELAY_ONE_NOTE); buzzer_sound(BUZZER_LOW_SO_5); delay_ms(BUZZER_DELAY_ONE_NOTE); buzzer_sound(BUZZER_LOW_LA_6); delay_ms(BUZZER_DELAY_ONE_NOTE); buzzer_sound(BUZZER_LOW_XI_7); delay_ms(BUZZER_DELAY_ONE_NOTE); buzzer_stop(); }

歌曲简谱

歌曲《送别》的简谱

将简谱转换为音调和节拍的数组

// 一拍的时间,单位ms #define BUZZER_DELAY_ONE_NOTE (400) // 简谱中一个音符的结构 typedef struct { unsigned int freq; // 音调(频率),单位hz unsigned int time_ms; // 节拍(一个音符持续的时间),单位ms }buzzer_note_t; // <<送别>>的简谱 buzzer_note_t song[] = { // 长亭外 {BUZZER_MIDDLE_SO_5, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_MIDDLE_MI_3, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_SO_5, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_HIGH_DO_1, BUZZER_DELAY_ONE_NOTE*2}, // 古道边 {BUZZER_MIDDLE_LA_6, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_HIGH_DO_1, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_MIDDLE_SO_5, BUZZER_DELAY_ONE_NOTE*2}, // 芳草碧连 {BUZZER_MIDDLE_SO_5, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_MIDDLE_DO_1, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_RE_2, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_MI_3, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_MIDDLE_RE_2, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_DO_1, BUZZER_DELAY_ONE_NOTE/2}, // 天 {BUZZER_MIDDLE_RE_2, BUZZER_DELAY_ONE_NOTE*3}, {0, BUZZER_DELAY_ONE_NOTE*1}, // 晚风拂柳 {BUZZER_MIDDLE_SO_5, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_MIDDLE_MI_3, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_SO_5, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_HIGH_DO_1, BUZZER_DELAY_ONE_NOTE*(1+1/2)}, {BUZZER_MIDDLE_XI_7, BUZZER_DELAY_ONE_NOTE/2}, // 笛声残 {BUZZER_MIDDLE_LA_6, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_HIGH_DO_1, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_MIDDLE_SO_5, BUZZER_DELAY_ONE_NOTE*2}, // 夕阳山外 {BUZZER_MIDDLE_SO_5, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_MIDDLE_RE_2, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_MI_3, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_FA_4, BUZZER_DELAY_ONE_NOTE*(1+1/2)}, {BUZZER_LOW_XI_7, BUZZER_DELAY_ONE_NOTE/2}, // 山 {BUZZER_MIDDLE_DO_1, BUZZER_DELAY_ONE_NOTE*3}, {0, BUZZER_DELAY_ONE_NOTE*1}, // 天之涯 {BUZZER_MIDDLE_LA_6, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_HIGH_DO_1, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_HIGH_DO_1, BUZZER_DELAY_ONE_NOTE*2}, // 地之角 {BUZZER_MIDDLE_XI_7, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_MIDDLE_LA_6, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_XI_7, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_HIGH_DO_1, BUZZER_DELAY_ONE_NOTE*2}, // 知交半零 {BUZZER_MIDDLE_LA_6, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_XI_7, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_HIGH_DO_1, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_XI_7, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_LA_6, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_SO_5, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_MI_3, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_DO_1, BUZZER_DELAY_ONE_NOTE/2}, // 落 {BUZZER_MIDDLE_RE_2, BUZZER_DELAY_ONE_NOTE*3}, {0, BUZZER_DELAY_ONE_NOTE*1}, // 一瓢浊酒 {BUZZER_MIDDLE_SO_5, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_MIDDLE_MI_3, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_SO_5, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_HIGH_DO_1, BUZZER_DELAY_ONE_NOTE*(1+1/2)}, {BUZZER_MIDDLE_XI_7, BUZZER_DELAY_ONE_NOTE/2}, // 尽余欢 {BUZZER_MIDDLE_LA_6, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_HIGH_DO_1, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_MIDDLE_SO_5, BUZZER_DELAY_ONE_NOTE*2}, // 今宵别梦 {BUZZER_MIDDLE_SO_5, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_MIDDLE_RE_2, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_MI_3, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_FA_4, BUZZER_DELAY_ONE_NOTE*(1+1/2)}, {BUZZER_LOW_XI_7, BUZZER_DELAY_ONE_NOTE/2}, // 寒 {BUZZER_MIDDLE_DO_1, BUZZER_DELAY_ONE_NOTE*3}, {0, BUZZER_DELAY_ONE_NOTE*1}, // 长亭外 {BUZZER_MIDDLE_SO_5, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_MIDDLE_MI_3, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_SO_5, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_HIGH_DO_1, BUZZER_DELAY_ONE_NOTE*2}, // 古道边 {BUZZER_MIDDLE_LA_6, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_HIGH_DO_1, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_MIDDLE_SO_5, BUZZER_DELAY_ONE_NOTE*2}, // 芳草碧连 {BUZZER_MIDDLE_SO_5, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_MIDDLE_DO_1, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_RE_2, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_MI_3, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_MIDDLE_RE_2, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_DO_1, BUZZER_DELAY_ONE_NOTE/2}, // 天 {BUZZER_MIDDLE_RE_2, BUZZER_DELAY_ONE_NOTE*3}, {0, BUZZER_DELAY_ONE_NOTE*1}, // 晚风拂柳 {BUZZER_MIDDLE_SO_5, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_MIDDLE_MI_3, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_SO_5, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_HIGH_DO_1, BUZZER_DELAY_ONE_NOTE*(1+1/2)}, {BUZZER_MIDDLE_XI_7, BUZZER_DELAY_ONE_NOTE/2}, // 笛声残 {BUZZER_MIDDLE_LA_6, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_HIGH_DO_1, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_MIDDLE_SO_5, BUZZER_DELAY_ONE_NOTE*2}, // 夕阳山外 {BUZZER_MIDDLE_SO_5, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_MIDDLE_RE_2, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_MI_3, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_FA_4, BUZZER_DELAY_ONE_NOTE*(1+1/2)}, {BUZZER_LOW_XI_7, BUZZER_DELAY_ONE_NOTE/2}, // 山 {BUZZER_MIDDLE_DO_1, BUZZER_DELAY_ONE_NOTE*3}, {0, BUZZER_DELAY_ONE_NOTE*1}, // 结束符 {0, 0} }; 如果想唱其它的歌,只需根据歌曲的简谱重新生成这个数组就行。

实现唱歌

根据前面的介绍,已经知道,使用pwm_init()控制音调的频率,使用delay_ms()控制音符的时长。再加上已经将一首歌的简谱转换为了音调和节拍的数组,那么唱歌就变成了顺序执行音调和节拍的数组。

// 播放指定音高 void buzzer_sound(unsigned int freq) { buzzer_pwm.period_ns = 1000000000 / freq; buzzer_pwm.low_ns = buzzer_pwm.period_ns / 2; pwm_init(&buzzer_pwm); return ; } // 停止播放 void buzzer_stop(void) { pwm_disable(&buzzer_pwm); gpio_init(buzzer_gpio, gpio_mode_output); gpio_set(buzzer_gpio, gpio_level_high); return ; } /* * 休止符 * @time_ms 休止符时间 */ void buzzer_quiet(unsigned int time_ms) { pwm_disable(&buzzer_pwm); delay_ms(time_ms); pwm_enable(&buzzer_pwm); return ; } // 无源蜂鸣器唱歌 void buzzer_play(void) { int i = 0; buzzer_init(); while (1) { // 判断是否结束 if (0 == song[i].time_ms) break; if (0 == song[i].freq) { buzzer_quiet(song[i].time_ms); } else { buzzer_sound(song[i].freq); delay_ms(song[i].time_ms); } i++; } buzzer_stop(); return ; }

实物图

无源蜂鸣器模块 VCC ---------------- 3.3V GND ---------------- GND I/O ---------------- GPIO47

源码清单

pwm

之前(2017年7月)裸机编程时,浮点运算还有点问题,为了避免使用浮点运算,修改了“龙芯1c库”中的pwm的部分代码。

目前(2017年9月)硬浮点功能已调通,可以直接使用浮点数,不用再进行如下修改。

pwm_init()函数的对比照,左边为蜂鸣器唱歌源码,右边为龙芯1c库中的源码。注意,等浮点运算全部调通之后,不需要这样修改,并且龙芯1c库中使用占空比这种方式更符合平常的使用习惯。

Buzzer.h

// 无源蜂鸣器唱歌的头文件 #ifndef __OPENLOONGSON_BUZZER_H #define __OPENLOONGSON_BUZZER_H // 无源蜂鸣器初始化 void buzzer_init(void); // 停止播放 void buzzer_stop(void); // 无源蜂鸣器唱歌 void buzzer_play(void); // 测试无源蜂鸣器--依次播放do re mi fa so la xi void buzzer_test(void); #endif

Buzzer.c

// 无源蜂鸣器唱歌的源文件 #include "../lib/public.h" #include "../lib/pwm.h" #include "../lib/gpio.h" #include "../lib/delay.h" // do re mi fa so la xi的低音频率(单位hz) #define BUZZER_LOW_DO_1 (262) #define BUZZER_LOW_RE_2 (294) #define BUZZER_LOW_MI_3 (330) #define BUZZER_LOW_FA_4 (349) #define BUZZER_LOW_SO_5 (392) #define BUZZER_LOW_LA_6 (440) #define BUZZER_LOW_XI_7 (494) // 中音 #define BUZZER_MIDDLE_DO_1 (523) #define BUZZER_MIDDLE_RE_2 (587) #define BUZZER_MIDDLE_MI_3 (659) #define BUZZER_MIDDLE_FA_4 (698) #define BUZZER_MIDDLE_SO_5 (784) #define BUZZER_MIDDLE_LA_6 (880) #define BUZZER_MIDDLE_XI_7 (988) // 高音 #define BUZZER_HIGH_DO_1 (1047) #define BUZZER_HIGH_RE_2 (1175) #define BUZZER_HIGH_MI_3 (1319) #define BUZZER_HIGH_FA_4 (1397) #define BUZZER_HIGH_SO_5 (1568) #define BUZZER_HIGH_LA_6 (1760) #define BUZZER_HIGH_XI_7 (1976) // 一拍的时间,单位ms #define BUZZER_DELAY_ONE_NOTE (400) // 简谱中一个音符的结构 typedef struct { unsigned int freq; // 音调(频率),单位hz unsigned int time_ms; // 节拍(一个音符持续的时间),单位ms }buzzer_note_t; // <<送别>>的简谱 buzzer_note_t song[] = { // 长亭外 {BUZZER_MIDDLE_SO_5, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_MIDDLE_MI_3, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_SO_5, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_HIGH_DO_1, BUZZER_DELAY_ONE_NOTE*2}, // 古道边 {BUZZER_MIDDLE_LA_6, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_HIGH_DO_1, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_MIDDLE_SO_5, BUZZER_DELAY_ONE_NOTE*2}, // 芳草碧连 {BUZZER_MIDDLE_SO_5, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_MIDDLE_DO_1, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_RE_2, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_MI_3, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_MIDDLE_RE_2, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_DO_1, BUZZER_DELAY_ONE_NOTE/2}, // 天 {BUZZER_MIDDLE_RE_2, BUZZER_DELAY_ONE_NOTE*3}, {0, BUZZER_DELAY_ONE_NOTE*1}, // 晚风拂柳 {BUZZER_MIDDLE_SO_5, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_MIDDLE_MI_3, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_SO_5, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_HIGH_DO_1, BUZZER_DELAY_ONE_NOTE*(1+1/2)}, {BUZZER_MIDDLE_XI_7, BUZZER_DELAY_ONE_NOTE/2}, // 笛声残 {BUZZER_MIDDLE_LA_6, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_HIGH_DO_1, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_MIDDLE_SO_5, BUZZER_DELAY_ONE_NOTE*2}, // 夕阳山外 {BUZZER_MIDDLE_SO_5, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_MIDDLE_RE_2, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_MI_3, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_FA_4, BUZZER_DELAY_ONE_NOTE*(1+1/2)}, {BUZZER_LOW_XI_7, BUZZER_DELAY_ONE_NOTE/2}, // 山 {BUZZER_MIDDLE_DO_1, BUZZER_DELAY_ONE_NOTE*3}, {0, BUZZER_DELAY_ONE_NOTE*1}, // 天之涯 {BUZZER_MIDDLE_LA_6, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_HIGH_DO_1, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_HIGH_DO_1, BUZZER_DELAY_ONE_NOTE*2}, // 地之角 {BUZZER_MIDDLE_XI_7, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_MIDDLE_LA_6, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_XI_7, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_HIGH_DO_1, BUZZER_DELAY_ONE_NOTE*2}, // 知交半零 {BUZZER_MIDDLE_LA_6, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_XI_7, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_HIGH_DO_1, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_XI_7, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_LA_6, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_SO_5, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_MI_3, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_DO_1, BUZZER_DELAY_ONE_NOTE/2}, // 落 {BUZZER_MIDDLE_RE_2, BUZZER_DELAY_ONE_NOTE*3}, {0, BUZZER_DELAY_ONE_NOTE*1}, // 一瓢浊酒 {BUZZER_MIDDLE_SO_5, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_MIDDLE_MI_3, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_SO_5, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_HIGH_DO_1, BUZZER_DELAY_ONE_NOTE*(1+1/2)}, {BUZZER_MIDDLE_XI_7, BUZZER_DELAY_ONE_NOTE/2}, // 尽余欢 {BUZZER_MIDDLE_LA_6, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_HIGH_DO_1, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_MIDDLE_SO_5, BUZZER_DELAY_ONE_NOTE*2}, // 今宵别梦 {BUZZER_MIDDLE_SO_5, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_MIDDLE_RE_2, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_MI_3, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_FA_4, BUZZER_DELAY_ONE_NOTE*(1+1/2)}, {BUZZER_LOW_XI_7, BUZZER_DELAY_ONE_NOTE/2}, // 寒 {BUZZER_MIDDLE_DO_1, BUZZER_DELAY_ONE_NOTE*3}, {0, BUZZER_DELAY_ONE_NOTE*1}, // 长亭外 {BUZZER_MIDDLE_SO_5, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_MIDDLE_MI_3, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_SO_5, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_HIGH_DO_1, BUZZER_DELAY_ONE_NOTE*2}, // 古道边 {BUZZER_MIDDLE_LA_6, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_HIGH_DO_1, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_MIDDLE_SO_5, BUZZER_DELAY_ONE_NOTE*2}, // 芳草碧连 {BUZZER_MIDDLE_SO_5, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_MIDDLE_DO_1, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_RE_2, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_MI_3, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_MIDDLE_RE_2, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_DO_1, BUZZER_DELAY_ONE_NOTE/2}, // 天 {BUZZER_MIDDLE_RE_2, BUZZER_DELAY_ONE_NOTE*3}, {0, BUZZER_DELAY_ONE_NOTE*1}, // 晚风拂柳 {BUZZER_MIDDLE_SO_5, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_MIDDLE_MI_3, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_SO_5, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_HIGH_DO_1, BUZZER_DELAY_ONE_NOTE*(1+1/2)}, {BUZZER_MIDDLE_XI_7, BUZZER_DELAY_ONE_NOTE/2}, // 笛声残 {BUZZER_MIDDLE_LA_6, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_HIGH_DO_1, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_MIDDLE_SO_5, BUZZER_DELAY_ONE_NOTE*2}, // 夕阳山外 {BUZZER_MIDDLE_SO_5, BUZZER_DELAY_ONE_NOTE*1}, {BUZZER_MIDDLE_RE_2, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_MI_3, BUZZER_DELAY_ONE_NOTE/2}, {BUZZER_MIDDLE_FA_4, BUZZER_DELAY_ONE_NOTE*(1+1/2)}, {BUZZER_LOW_XI_7, BUZZER_DELAY_ONE_NOTE/2}, // 山 {BUZZER_MIDDLE_DO_1, BUZZER_DELAY_ONE_NOTE*3}, {0, BUZZER_DELAY_ONE_NOTE*1}, // 结束符 {0, 0} }; unsigned int buzzer_gpio = LS1C_PWM3_GPIO47; pwm_info_t buzzer_pwm; // 无源蜂鸣器初始化 void buzzer_init(void) { buzzer_pwm.gpio = buzzer_gpio; buzzer_pwm.mode = PWM_MODE_NORMAL; } // 播放指定音高 void buzzer_sound(unsigned int freq) { buzzer_pwm.period_ns = 1000000000 / freq; buzzer_pwm.low_ns = buzzer_pwm.period_ns / 2; pwm_init(&buzzer_pwm); return ; } // 停止播放 void buzzer_stop(void) { pwm_disable(&buzzer_pwm); gpio_init(buzzer_gpio, gpio_mode_output); gpio_set(buzzer_gpio, gpio_level_high); return ; } /* * 休止符 * @time_ms 休止符时间 */ void buzzer_quiet(unsigned int time_ms) { pwm_disable(&buzzer_pwm); delay_ms(time_ms); pwm_enable(&buzzer_pwm); return ; } // 测试无源蜂鸣器--依次播放do re mi fa so la xi void buzzer_test(void) { buzzer_init(); buzzer_sound(BUZZER_LOW_DO_1); delay_ms(BUZZER_DELAY_ONE_NOTE); buzzer_sound(BUZZER_LOW_RE_2); delay_ms(BUZZER_DELAY_ONE_NOTE); buzzer_sound(BUZZER_LOW_MI_3); delay_ms(BUZZER_DELAY_ONE_NOTE); buzzer_sound(BUZZER_LOW_FA_4); delay_ms(BUZZER_DELAY_ONE_NOTE); buzzer_sound(BUZZER_LOW_SO_5); delay_ms(BUZZER_DELAY_ONE_NOTE); buzzer_sound(BUZZER_LOW_LA_6); delay_ms(BUZZER_DELAY_ONE_NOTE); buzzer_sound(BUZZER_LOW_XI_7); delay_ms(BUZZER_DELAY_ONE_NOTE); buzzer_stop(); } // 无源蜂鸣器唱歌 void buzzer_play(void) { int i = 0; buzzer_init(); while (1) { // 判断是否结束 if (0 == song[i].time_ms) break; if (0 == song[i].freq) { buzzer_quiet(song[i].time_ms); } else { buzzer_sound(song[i].freq); delay_ms(song[i].time_ms); } i++; } buzzer_stop(); return ; }

main.c

#include "../lib/public.h" #include "../lib/gpio.h" #include "../lib/delay.h" #include "../example/test_gpio.h" #include "../example/test_delay.h" #include "../example/test_simulate_i2c.h" #include "../example/test_timer.h" #include "buzzer.h" // pmon提供的打印接口 struct callvectors *callvec; int main(int argc, char **argv, char **env, struct callvectors *cv) { callvec = cv; // 测试无源蜂鸣器--依次播放do re mi fa so la xi // buzzer_test(); while (1) { // 无源蜂鸣器唱歌 buzzer_play(); // 延时一会 delay_s(5); } return(0); } 完整的代码请移步到http://pan.baidu.com/s/1dEA19GP

感谢耐心阅读!

转载请注明原文地址: https://www.6miu.com/read-22716.html

最新回复(0)