其数念实原理很简单,就是控制单片机的某个引脚,输出一定频率的方波信号,而输出方波信号的方法,是最基础的,最简单的编程了,用定时器棚旅定时,根据信号频率算出信号周期,然后计算出定时的时间。那单片机演奏歌曲的程序,也是同样的原理,只是事先根据歌曲的简谱查出每个音阶的信号频率,再根据各音阶频率计算出定时器的初值。演奏时,按简谱的各音阶顺序输出不同的频率的信号就行了。
下表是音阶与频率对应关系薯和困表,给出常用音阶对应的定时常数。
//此程序在硬件上调试通过//本程序的单片机晶振采用11.0592m
#include
<reg51.h>
sbit
speaker=p1^2
unsigned
char
timer0h,timer0l,time
//世上只有妈妈好数据表
code
unsigned
char
sszymmh[]={
6,2,3,
5,2,1,
3,2,2,
5,2,2,
1,3,2,
6,2,1,
5,2,1,
6,2,4,
3,2,2,
5,2,1,
6,2,1,
5,2,2,
3,2,2,
1,2,1,
6,1,1,
5,2,1,
3,2,1,
2,2,4,
2,2,3,
3,2,1,
5,2,2,
5,2,1,
6,2,1,
3,2,2,
2,2,2,
1,2,4,
5,2,3,
3,2,1,
2,2,1,
1,2,1,
6,1,1,
1,2,1,
5,1,6,
0,0,0
}
//
音阶频率表
高八位
code
unsigned
char
freqh[]={
0xf2,0xf3,0xf5,0xf5,0xf6,0xf7,0xf8,
0xf9,0xf9,0xfa,0xfa,0xfb,0xfb,0xfc,0xfc,
//虚察1,2,3,4,5,6,7,8,i
0xfc,0xfd,0xfd,0xfd,0xfd,0xfe,
0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xff,
}
//
音阶频雀誉旁率表
低八位
code
unsigned
char
freql[]={
0x42,0xc1,0x17,0xb6,0xd0,0xd1,0xb6,
0x21,0xe1,0x8c,0xd8,0x68,0xe9,0x5b,0x8f,
//1,2,3,4,5,6,7,8,i
0xee,0x44,
0x6b,0xb4,0xf4,0x2d,
0x47,0x77,0xa2,0xb6,0xda,0xfa,0x16,
}
void
delay(unsigned
char
t)
{
unsigned
char
t1
unsigned
long
t2
for(t1=0t1<tt1++)
{
for(t2=0t2<8000t2++)
{
}
}
tr0=0
}
void
t0int()
interrupt
1
{
tr0=0
speaker=!speaker
th0=timer0h
tl0=timer0l
tr0=1
}
void
song()
{
th0=timer0h
tl0=timer0l
tr0=1
delay(time)
}
void
main(void)
{
unsigned
char
k,i
tmod=1
//置ct0定时工作方顷橡式1
ea=1
et0=1//ie=0x82
//cpu开中断,ct0开中断
while(1)
{
i=0
while(i<100){
//音乐数组长度
,唱完从头再来
k=sszymmh[i]+7*sszymmh[i+1]-1
timer0h=freqh[k]
timer0l=freql[k]
time=sszymmh[i+2]
i=i+3
song()
}
}
}
#include "reg51.h"#define uintunsigned int
#define uchar unsigned char
uchar * TABLE
code uint TABLE1 [15]={64260,64400,64524,64580,
64684,64777,64820,64898,
64968,65030,65058,65110,
65157,65178,65217}
code uchar SONG [ ]={
//1. 迟来的爱
}
code uchar SONG1 [ ]={
//2.两汪迹亏只蝴蝶
}
code uchar SONG3 [ ]={
//4.一个师傅三个徒弟
}
uchar hjsz
uchar ljsz
uchar jpm
uchar yfm
uchar t0 =0
uint i=0
sbit Speaker =P1^0
uint k
void Delay1()
{
for ( k=0k<20000k++)
}
void Lignt( )
{ uchar t
for(t=0t<10t++)
{
P2=0xff
Delay1()
P2=0x00
Delay1()
}
}
void Lignt1( )
{
P2=0xaa
Delay1()
P2=0x55
Delay1()
}
void Delay(uchar t0)//延时
{
while(t0--) //决定节拍
Lignt1()
}
void Delay2(uchar w0)//延时
{
while(w0--) //决定节拍
Lignt()
}
void T0Int() interrupt 1//TIMER0
{
TL0 = ljsz
TH0 = hjsz
Speaker=!Speaker
}
void ExtInt0() interrupt 0//INT0
{
if(t0>10)
t0=0
i=0 // 全局变量,指向歌谱的第1个
switch(t0++)
{
case 0 : TABLE=SONGbreak//选择第1首
case 1 : TABLE=SONG1break//选择第2首
case 2 : TABLE=SONG2break//选择第3首
case 3 : TABLE=SONG3break//选州旁择第4首
case 4 : TABLE=SONG4break//选择第5首
case 5 : TABLE=SONG5break//选择第6首
case 6 : TABLE=SONG6break/困神/选择第7首
case 7 : TABLE=SONG7break//选择第8首
case 8 : TABLE=SONG8break//选择第9首
case 9 : TABLE=SONG9break//选择第10首
}
}
void songsing()//发音程序
{
i=0
while(TABLE[i])
{
jpm=TABLE[i]&0x0f //节拍值
yfm=(TABLE[i]>>0x04)&0x0f//简谱值
if(yfm) //简谱为1,取计数值
{
yfm=yfm-1
hjsz=(uchar)(TABLE1[yfm]>>0x08)//取计数值高字节
TH0 = hjsz
ljsz=(uchar)(TABLE1[yfm])//取计数值低字节
TL0 = ljsz
TR0 = 1 //启动TIMER0
}
else TR0 = 0//简谱为0,不发音
Delay(jpm)//节拍延时
i++
}
}
void main(void)
{
TMOD =0X01//设TIMER0在MODE1
TCON =0X01//外部中断INT0,下降沿触发
IE =0x83//开中断(INT0,TIMER0)
IP =0x00//设置中断优先级
TABLE=SONG0
while(1)
{
Lignt( )
songsing()//调用发音程序
TR0 = 0//停止TIMER0
Delay2(1)
TABLE=SONG0// 更改歌曲0
songsing()
}
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)