定时器相关可见:https://blog.csdn.net/qq_53922901/article/details/135730245?spm=1001.2014.3001.5501
蜂鸣器介绍
有源无源蜂鸣器的外观基本一致不好分辨,需要提前了解。
驱动电路
集成电路驱动
原理图
ULN2003介绍
逻辑框图
典型应用电路
注意
无源蜂鸣器不能长时间通电,但是单片机I/O口默认给高电平,通过非门之后会使蜂鸣器通电,所以蜂鸣器是默认通电状态,不过单片机设有限流电阻,自己组装时要注意。给0时形成高阻态,使电路不通点
高阻态
高阻态这是一个数字电路里常见的术语,指的是电路的一种输出状态,既不是高电平也不是低电平。
如果高阻态再输入下一级电路的话,对下级电路无任何影响,和没接一样,如果用万用表测的话有可能是高电平也有可能是低电平,随它后面接的东西定。
乐理相关
键盘与音高对照
- #为升音,即升高半个音,每相邻的键盘(无论黑白)都是相隔半音,例如#c,就是c右上黑键的音。
- b为降音,即降低半个音,例如eb,就是e左上黑键的音
音符
从左到右依次(由慢到快)是全音符、二分音符、四分音符、八分音符、十六分音符、三十二分音符、六十四分音符,之间都是两倍的关系。
以上面谱子,是以C为主音,以四分音符为准,即每个普通音(普通数字)的持续时间与四分音符的时长一致。
- 如:5-,即延长5这个音的时间两倍。5- -即延长四倍
- 如:5下面一横,即缩短时间为原本的1/2,以此类推。
c调音与频率对照表
相邻按十二平均律计算,下一个音高频率 = 上一个音高频率*2^(1/12)
转换数据
使用excel得到需要使用的数据(音高使用的是赫尔姆霍茨音调记号法)
重装载值用于给定时器赋值
实现蜂鸣器发声
代码如下:
#include <REGX52.H>
#include <intrins.h>
// 蜂鸣器端口
sbit Buzzer = P2^5;
unsigned int i;
void Delay500us(void) //@11.0592MHz
{
unsigned char data i;
_nop_();
i = 227;
while (--i);
}
/**
* @brief 蜂鸣器发声时长
* @param ms 发声时长(单位毫秒)
* @retval 无
*/
void Buzzer_Time(unsigned int ms){
for(i=0;i<ms*2;i++){
Buzzer = !Buzzer;
Delay500us(); // 以1000Hz的频率响
}
}
实现蜂鸣器使用定时器播放天空之城
main.c内容如下:
#include <REGX52.H>
#include "Delay.h"
#include "Timer0.h"
//蜂鸣器端口定义
sbit Buzzer=P2^5;
//播放速度,值为四分音符的时长(500ms)
#define SPEED 500
//音符与索引对应表,P:休止符,L:低音,M:中音,H:高音,下划线:升半音符号#
#define P 0
#define L1 1
#define L1_ 2
#define L2 3
#define L2_ 4
#define L3 5
#define L4 6
#define L4_ 7
#define L5 8
#define L5_ 9
#define L6 10
#define L6_ 11
#define L7 12
#define M1 13
#define M1_ 14
#define M2 15
#define M2_ 16
#define M3 17
#define M4 18
#define M4_ 19
#define M5 20
#define M5_ 21
#define M6 22
#define M6_ 23
#define M7 24
#define H1 25
#define H1_ 26
#define H2 27
#define H2_ 28
#define H3 29
#define H4 30
#define H4_ 31
#define H5 32
#define H5_ 33
#define H6 34
#define H6_ 35
#define H7 36
// 索引与频率对照表
unsigned int FreqTable[]={
0,
63628,63731,63835,63928,64021,64103,64185,64260,64331,64400,64463,64528,
64580,64633,64684,64732,64777,64820,64860,64898,64934,64968,65000,65030,
65058,65085,65110,65134,65157,65178,65198,65217,65235,65252,65268,65283,
};
// 乐谱
unsigned char code Music[]={
//音符,时值,
//1
P, 4,
P, 4,
P, 4,
M6, 2,
M7, 2,
H1, 4+2,
M7, 2,
H1, 4,
H3, 4,
M7, 4+4+4,
M3, 2,
M3, 2,
//2
M6, 4+2,
M5, 2,
M6, 4,
H1, 4,
M5, 4+4+4,
M3, 4,
M4, 4+2,
M3, 2,
M4, 4,
H1, 4,
//3
M3, 4+4,
P, 2,
H1, 2,
H1, 2,
H1, 2,
M7, 4+2,
M4_,2,
M4_,4,
M7, 4,
M7, 8,
P, 4,
M6, 2,
M7, 2,
//4
H1, 4+2,
M7, 2,
H1, 4,
H3, 4,
M7, 4+4+4,
M3, 2,
M3, 2,
M6, 4+2,
M5, 2,
M6, 4,
H1, 4,
//5
M5, 4+4+4,
M2, 2,
M3, 2,
M4, 4,
H1, 2,
M7, 2+2,
H1, 2+4,
H2, 2,
H2, 2,
H3, 2,
H1, 2+4+4,
//6
H1, 2,
M7, 2,
M6, 2,
M6, 2,
M7, 4,
M5_,4,
M6, 4+4+4,
H1, 2,
H2, 2,
H3, 4+2,
H2, 2,
H3, 4,
H5, 4,
//7
H2, 4+4+4,
M5, 2,
M5, 2,
H1, 4+2,
M7, 2,
H1, 4,
H3, 4,
H3, 4+4+4+4,
//8
M6, 2,
M7, 2,
H1, 4,
M7, 4,
H2, 2,
H2, 2,
H1, 4+2,
M5, 2+4+4,
H4, 4,
H3, 4,
H3, 4,
H1, 4,
//9
H3, 4+4+4,
H3, 4,
H6, 4+4,
H5, 4,
H5, 4,
H3, 2,
H2, 2,
H1, 4+4,
P, 2,
H1, 2,
//10
H2, 4,
H1, 2,
H2, 2,
H2, 4,
H5, 4,
H3, 4+4+4,
H3, 4,
H6, 4+4,
H5, 4+4,
//11
H3, 2,
H2, 2,
H1, 4+4,
P, 2,
H1, 2,
H2, 4,
H1, 2,
H2, 2+4,
M7, 4,
M6, 4+4+4,
P, 4,
0xFF //终止标志
};
unsigned char FreqSelect,MusicSelect;
void main()
{
Timer0Init();
while(1)
{
if(Music[MusicSelect]!=0xFF) //如果不是停止标志位
{
FreqSelect=Music[MusicSelect]; // 根据音高对应的宏定义确定频率的索引
MusicSelect++; // +1显示为音乐时长
Delay(SPEED/4*Music[MusicSelect]); //选择音符对应的时值
MusicSelect++; // 在+1显示为下次的音高
TR0=0;
Delay(5); //音符间短暂停顿
TR0=1;
}
else //如果是停止标志位
{
TR0=0;
while(1);
}
}
}
void Timer0_Routine() interrupt 1
{
if(FreqTable[FreqSelect]) //如果不是休止符
{
// 将对应音高的频率值赋与定时器
TL0 = FreqTable[FreqSelect]%256; //设置定时初值
TH0 = FreqTable[FreqSelect]/256; //设置定时初值
Buzzer=!Buzzer; //翻转蜂鸣器IO口
}
}
Delay.c延时函数如下:
void Delay(unsigned int xms)
{
unsigned char i, j;
while(xms--)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
}