龙芯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_