用龙芯1c库实现无源蜂鸣器唱歌《送别》
龙芯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; // 音调(频率),单位hzunsigned 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; // 音调(频率),单位hzunsigned 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
感谢耐心阅读!
用龙芯1c库实现无源蜂鸣器唱歌《送别》相关推荐
- 【龙芯1c库】封装模拟I2C接口和使用示例
龙芯1c库是把龙芯1c的常用外设的常用功能封装为一个库,类似于STM32库.Git地址:https://gitee.com/caogos/OpenLoongsonLib1c I2C接口是常用的接口之一 ...
- 【龙芯1c库】封装硬件pwm接口和使用示例
龙芯1c库是把龙芯1c的常用外设的常用功能封装为一个库,类似于STM32库.Git地址:https://gitee.com/caogos/OpenLoongsonLib1c 本文通过"龙芯1 ...
- 【龙芯1c库】封装硬件定时器接口和使用示例
龙芯1c库是把龙芯1c的常用外设的常用功能封装为一个库,类似于STM32库.完整源码请移步到https://gitee.com/caogos/OpenLoongsonLib1c 龙芯1c库中硬件定时器 ...
- 【龙芯1c库】移植硬浮点FPU
龙芯1c库是把龙芯1c的常用外设的常用功能封装为一个库,类似于STM32库.完整源码请移步到https://gitee.com/caogos/OpenLoongsonLib1c 龙芯1C上有硬浮点协处 ...
- 【龙芯1c库】封装CAN接口和使用示例
can使用还是比较广泛的,之前有网友在龙芯1b和龙芯1c上已经测试过了在裸机编程中使用CAN接口,这里把他们分享的程序贴上来,供大家参考. 龙芯1b上的测试程序在https://gitee.com/c ...
- 在龙芯1C单片机上使用ESP8266 wifi透传模块
龙芯1C既可以运行linux,也可以当作单片机用.当用作linux时,可以通过USB wifi模块RTL8192C,RTL8188ETV等,当作单片机用时,可以像STM32那样使用串口透传wifi模块 ...
- Buildroot 龙芯1C支持指南
本文转载自:https://github.com/pengphei/smartloong-sphinx/blob/master/source/cn/loongson1c_buildroot_guide ...
- 串口例程 龙芯1c_Buildroot 龙芯1C支持指南
Buildroot 龙芯1C支持指南 引子:从龙芯1C预订拿到板子已经很长一段时间了,因为各种事情,一直让它呆在角落的冷宫里.昨天,愤而出去骑行,有导航出错,入的一片幽静山林,正能量爆棚,一下午休息, ...
- 龙芯处理器可以适配鸿蒙os吗,SylixOS龙芯1C适配总结
1.龙芯1C简介 1.1龙芯1C简介 龙芯 1C300(以下简称 1C)芯片是基于 LS232 处理器核的高性价比单芯片系统,可应用于指纹生物识别.物联传感等领域.1C 包含浮点处理单元,可以有效增强 ...
最新文章
- 前沿科技山雨欲来,四大领域存创新机会
- 程序的内存模型—内存四区—堆区
- CSDN编程挑战——《交替字符串》
- spark总结——转载
- PS 色调——老照片效果
- NULL、nil、Nil、NSNull的区别
- C++ 实现无向图的最小生成树Prim算法(附完整代码)
- 第 4-2 课:反射和动态代理 + 面试题
- 机器学习是如何改善企业生产力的?(内附机器智能版图)
- insert into select from 部分字段插入_MySQL的故障分析,Insert 加锁与死锁分析-爱可生
- ios 微信分享重新编码链接_微信民众号IOS端复制链接失足,安卓端分享链接翻开只能进入首页等题目的处理...
- android下在屏幕适配小总结
- java 取模运算_JAVA算术运算符_四则与取模
- python3的字符串操作
- access orcad 数据库_OrCAD Capture CIS使用MySQL数据库
- H5微信分享 自定义图标和内容(以及二次分享图片丢失的解决办法)
- 网络基础2---->网络数据传输(局域网)
- 思维导图 基础篇(11)应用-文章分析-框架法
- “蚂蚁呀嘿” 刷屏的背后:算法工程师带你理性解构神曲
- 想学文字生成图片?3招告诉你描述文字生成图片怎么做