单片机实现音乐

  • 格式:doc
  • 大小:30.00 KB
  • 文档页数:5

*******************************************************************************
**************************
*
*
* 单片机音乐编程 方法(一) *
*
*
*******************************************************************************
**************************/
//摘抄自http://mcubase.com/ 源程序 没有试过!

原理就是利用单片机的引脚发出某一定频率的信号驱动外部发声设备发出声音,或者放出美
妙的音乐.
参数两个:前一个按照曲谱对照编码表给定,第二个,为节拍数,8->1拍,4->半拍.

************************曲谱编码,这是定义的曲谱表,对应如下
******************************
// 1 低音 DO 2 低音 RE 3 低音ME 4 低音 FA 5 低音 SO 6 低音LA 7 低音SI
mustab: db 'h','j', 0f8h,8bh, 0f9h,5bh, 0fah,14h, 0fah,0ch, 0fbh,03h, 0fbh,8fh, 0fch,0bh

// 8 中音 DO 9 中音 RE 0ah 中音ME 0bh 中音 FA 0ch 中音 SO 0dh 中音LA 0eh 中音SI
db 0fch,43h, 0fch,0abh, 0fdh,08h, 0fdh,33h, 0fdh,81h, 0fdh,0c7h, 0feh,05h

// 0fh 高音 DO 10h 高音 RE 11h 高音ME 12h 高音 FA 13h 高音 SO 14h 高音LA 15h 高
音SI
db 0feh,21h, 0feh,55h, 0feh,84h, 0fdh,99h, 0feh,0c0h, 0feh,0e3h, 0ffh,02h
// 以下为音乐乐谱代码,前两位表示曲谱,后一位表示节拍
// 8为 1 拍,4 ->半拍

mu_tab: db 6,4,8,4,10,4,1,4, 9,8,8,4,7,4,10,8,9,8,6,16
db 8,4,10,4,12,4,12,4, 13,8,12,4,11,4,10,16
db 00h

//以下是
//c语言
//*******************************************
// 音乐编程
//通过蜂鸣器发出讯响
//只要通过修改 后面的音乐程序里面的码
//表就可以自己谱曲唱歌!
//前一个参数为按照编码表给定,第二个参数为节拍数
#i nclude <80d51.h>

#define uchar unsigned char
#define beep P3_7 //蜂鸣器定义
uchar timer_h;
uchar timer_l;

//****************************************************************************
void reset();
void delay(uchar times);
void dems(); //休止符延时
void display(uchar disseg,uchar disdata);
uchar keyb();

// 这里定义音乐音符表
code uchar musictabl[]={0xf0,0xf0,

0xf8,0x8b,0xf9,0x5b,0xfa,0x14,0xfa,0x0c,0xfb,0x03,0xfb,0x8f,0xfc,0x0b,

0xfc,0x43,0xfc,0xab,0xfd,0x08,0xfd,0x33,0xfd,0x81,0xfd,0xc7,0xfe,0x05,
0xfe,0x32,0xfe,0x55,0xfe,0x84,0xfe,0x99,0xfe,0xc0,0xfe,0xe3,0xff,0x02};

//这里定义音乐曲谱表格
code uchar musicdata[]={6,4, 8,4,10,4, 1,4, 9,8, 8,4, 7,4,10,8,9,8,6,16,
8,4,10,4,12,4,12,4,13,8,12,4,11,4,10,16,0};

// ***************************************************************************
void ClockIrqHandler (void) interrupt 1 using 3; //定义定时器T0中断服务程序
//下面是定时器T0的中断服务程序
void ClockIrqHandler (void) interrupt 1 using 3 {
TR0 = 0; //关闭定时器
TL0 = timer_l;
TH0 = timer_h;
beep = ~beep;
TR0 = 1; //打开定时器
}
// ***************** 定时器程序 **********************************

uchar keybuf;
void main()
{
uchar counts,mustmp,tmp,keym = 0; //键盘返回结果的缓冲区

reset(); //调用初始化程序

while(1) //设置一个无限制循环
{
for(counts=0;musicdata[counts]!=0;counts+=2)
{
mustmp = musicdata[counts];
TR0 = 0;

tmp = musictabl[mustmp];
timer_h = tmp;

tmp = musictabl[mustmp+1];
timer_l = tmp;

TR0 = 1;
display(0,musicdata[counts+1]);
delay(musicdata[counts+1]);
TR0 = 0;
dems();
}
}
}

void reset()
{

keybuf = 0;
P2 = 255; //
//********* 上面是一些基础定义 **************

TL0 = 0xff; //初值
TH0 = 0xff; //初值
ET0=1; // 允许定时器T0中断
EA =1; // 中断总允许
}
//*****************************************************************************
//下面是延时程序.具体的延时时间不能通过表面程序看出,(为什么?)
//如果我们需要一个精密的延时程序,那么我们可以采用内嵌汇编代码的方式
void delay(uchar times)
{
int t=24000; //延时倍数
uchar i=times;
for(;i!=0;i--)
{for(;t!=0;t--){}}
}

void dems() //休止符延时
{
_asm
mov R0,#0
llp: mov R1,#100
llk: djnz R1,llk
djnz R0,llp
_endasm;
}
uchar keyb()
{
uchar key,keytmp;
key1 = 1; //将输出线拉高
key2 = 1;
key3 = 1;

key = P3 ; //读回来
key = key & 0xf0; //获得键盘结果
if(key == 112 ) return 0; //如果用户没有按键返回 0
else
{
keytmp = key;
delay(1); //判断是不是干扰
key = P3 & 0xf0;
if (key != keytmp ) return 0; //是干扰,返回 0
else //不是干扰,等待用户释放按键
{
do{
key1 = 1; //输出拉高
key2 = 1;
key3 = 1;
key = P3 & 0xf0; //读回来
P1_0 = ~P1_0; //如果用户不释放,闪烁 p1.0
}while(key != 112 ); //等待用户释放
P1_0 = 1; //用户释放以后,清除p1.0指示灯
switch(keytmp)
{
case 96: return 3;//返回用户按键结果
case 80: return 2;
case 48: return 1;
}
}
}
}