#include AT89X51.H
unsigned char temp;
unsigned char key;
unsigned char i,j;
unsigned char STH0;
unsigned char STL0;
unsigned int code tab[]={64021,64103,64260,64400,
64524,64580,64684,64777,
64820,64898,64968,65030,
65058,65110,65157,65178};
void main(void)
{
TMOD=0x01;
ET0=1;
EA=1;
while(1)
{
P3=0xff; //将P3口取出
P3_4=0; //使P3_4为低电平,这样可以判断第一竖排有没有键按下
temp=P3;
temp=temp 0x0f;
if (temp!=0x0f) //有键按下
{
for(i=50;i0;i--)
for(j=200;j0;j--); //延时
temp=P3;
temp=temp 0x0f;
if (temp!=0x0f) //再判断是否有键按下
{
temp=P3;
temp=temp 0x0f;
switch(temp) //判断是哪个键按下
{
case 0x0e:
key=0;
break;
case 0x0d:
key=1;
break;
case 0x0b:
key=2;
break;
case 0x07:
key=3;
break;
}
temp=P3;
P1_0=~P1_0;
P0=table[key];
STH0=tab[key]/256; //找出键对应的频率的时间,作为定时器中断初始值
STL0=tab[key]%256;
TR0=1;
temp=temp 0x0f;
while(temp!=0x0f)
{
temp=P3;
temp=temp 0x0f;
}
TR0=0;
}
}
P3=0xff;
P3_5=0; //跟上面差不多,现在是判断第二排的按键
temp=P3;
temp=temp 0x0f;
if (temp!=0x0f)
{
for(i=50;i0;i--)
for(j=200;j0;j--);
temp=P3;
temp=temp 0x0f;
if (temp!=0x0f)
{
temp=P3;
temp=temp 0x0f;
switch(temp)
{
case 0x0e:
key=4;
break;
case 0x0d:
key=5;
break;
case 0x0b:
key=6;
break;
case 0x07:
key=7;
break;
}
temp=P3;
P1_0=~P1_0;
P0=table[key];
STH0=tab[key]/256;
STL0=tab[key]%256;
TR0=1;
temp=temp 0x0f;
while(temp!=0x0f)
{
temp=P3;
temp=temp 0x0f;
}
TR0=0;
}
}
P3=0xff;
P3_6=0;
temp=P3;
temp=temp 0x0f;
if (temp!=0x0f)
{
for(i=50;i0;i--)
for(j=200;j0;j--);
temp=P3;
temp=temp 0x0f;
if (temp!=0x0f)
{
temp=P3;
temp=temp 0x0f;
switch(temp)
{
case 0x0e:
key=8;
break;
case 0x0d:
key=9;
break;
case 0x0b:
key=10;
break;
case 0x07:
key=11;
break;
}
temp=P3;
P1_0=~P1_0;
P0=table[key];
STH0=tab[key]/256;
STL0=tab[key]%256;
TR0=1;
temp=temp 0x0f;
while(temp!=0x0f)
{
temp=P3;
temp=temp 0x0f;
}
TR0=0;
}
}
P3=0xff;
P3_7=0;
temp=P3;
temp=temp 0x0f;
if (temp!=0x0f)
{
for(i=50;i0;i--)
for(j=200;j0;j--);
temp=P3;
temp=temp 0x0f;
if (temp!=0x0f)
{
temp=P3;
temp=temp 0x0f;
switch(temp)
{
case 0x0e:
key=12;
break;
case 0x0d:
key=13;
break;
case 0x0b:
key=14;
break;
case 0x07:
key=15;
break;
}
temp=P3;
P1_0=~P1_0;
P0=table[key];
STH0=tab[key]/256;
STL0=tab[key]%256;
TR0=1;
temp=temp 0x0f;
while(temp!=0x0f)
{
temp=P3;
temp=temp 0x0f;
}
TR0=0;
}
}
}
}
void t0(void) interrupt 1 using 0
{
TH0=STH0;
TL0=STL0;
P1_0=~P1_0;
}
电路图和原理我都有,刚好我也在做这个。 你自己看下程序吧,我也不愿意注释。
这个是能发出16个音符声音的,你写的AD89S52,应该是AT89S52吧
不可以,STC89系列的单片机是51内核,但不是和AT89S系列的结构完全相同,STC是用的串口通信下载,而AT89S是用自己的串行或并行下载的,如果你的电路上没有下载程序部分的电路,硬件是可以通用的,但是程序可能需要有细微的改动,具体您可以参考一下厂家提供的技术文档。
T2 的脉冲输出,频率是可以改的,以前曾经用它发出不同的音频。
用 P1 输入16个按键数值,控制输出16种频率,制作过“单片机电子琴”。
/***************************************************
程序名称:音乐演奏器
简要说明:P1.0口输出各音调的频率方波
编 写: MMC
更新时间:09\05
***************************************************/
#includeAT89X52.h
#define SPK P0_0 //定义方波输出口
#define LED P1_1
#define shumaguan P0 //定义数码管段码输出
unsigned int tone1,tone2;
/*****标准音符表*****/
//用于使定时器初值变化以产生相应频率的定时
unsigned char code yinfu[]={
0xfb,0xe9, //Do
0xfc,0x5c, //Re
0xfc,0xc1, //Mi
0xfc,0xef, //Fa
0xfd,0x45, //So
0xfd,0x92, //La
0xfd,0xd0, //Si
0xfd,0xee, //Do#
0xfa,0x14, //So低
0xfa,0xb9, //La低
0xfb,0x4d, //Si低
0x00,0x00 //音符之间的间隔,只要间隔时间小于65ms时,
//喇叭不会发出声音,用作拍子之间的短暂停顿
};
/*****军港之夜音调表*****/
unsigned char code shengri_tone[]={9,3,3,1,2,3,2,3,3,10,9,1,2,1,3,5,5,3,6,5,3,
3,3,2,1,2,3,2,3,11,9,10,11,10,1,11,3,3,11,10,11,10,11,3,3,11,
11,10,11,10,2,10,1,11,10,9,10,9,3,5,5,3,6,5,6,5,3,5,3,1,3,3,3,5,
3,5,5,3,3,2,3,2,11,10,11,10,9,3,3,5,5,3,6,5,6,5,3,5,3,1,3,
3,5,3,5,5,3,3,3,2,3,2,11,10,11,10,9,1 //0代表不发声,即停顿;数字即为音调
};
/*****军港之夜节拍表*****/
unsigned char code shengri_beat[]={24,24,24,24,12,12,48,24,48,24,24,12,12,86,24,24,24,24,24,48,24,
48,12,12,24,12,12,86,48,24,24,12,12,48,24,24,24,24,24,12,12,72,24,24,24,24,
24,12,12,48,24,12,12,24,24,12,12,86,24,24,24,24,24,12,12,48,12,24,12,24,12,12,12,48,
24,24,24,24,24,12,12,48,24,12,12,24,24,86,24,24,24,24,24,12,12,48,12,24,12,24,24,
24,72,24,24,24,12,12,24,12,12,48,24,12,12,24,24,86 //节拍,即tone表各音调的延时
};
/*****自动演示音调表*****/
unsigned char code yanshi_tone[]={ 1,0,2,0,3,0,4,0,5,0,6,0,7,0,8,0,
8,0,7,0,6,0,5,0,4,0,3,0,2,0,1,0
};
/*****自动演示节拍表*****/
unsigned char code yanshi_beat[]={ 48,1,48,1,48,1,48,1,48,1,48,1,48,1,48,2,
48,1,48,1,48,1,48,1,48,1,48,1,48,1,48,2
};
/*****15ms延时子程序,用于节拍*****/
void delay(void)
{
unsigned char n=15;
while(n--)
{
unsigned char i;
for(i=0;i125;i++);
}
}
/*****定时器0初始化*****/
void initTimer(void)
{
TMOD=0x01; //定时器0,工作方式1;定时器1,工作方式1
TH0=tone1;
TL0=tone2;
}
/*****定时器0中断服务程序*****/
void timer0(void) interrupt 1
{
TH0=tone1;
TL0=tone2;
SPK=~SPK; //取反,以产生方波
}
/*****演奏子程序1*****/
void play1(void)
{
unsigned char m=0;
unsigned char s;
unsigned char a=1;
while(1)
{
EA=0;
LED=0;
a=shengri_tone[m]; //取音符
s=shengri_beat[m]; //取节拍
tone1=yinfu[2*a-2];
tone2=yinfu[2*a-1];
EA=1;
while(s--)
{
delay();
}
LED=1;
m++;
if(m=119) return; //数值是shengri相关表中的元素数量
}
}
/*****演奏子程序2*****/
void play2(void)
{
unsigned char m=0;
unsigned char s;
unsigned char a=1;
while(1)
{
EA=0;
LED=0;
a=yanshi_tone[m];
s=yanshi_beat[m];
tone1=yinfu[2*a-2];
tone2=yinfu[2*a-1];
EA=1;
while(s--)
{
delay();
}
LED=1;
m++;
if(m=32) return;
}
}
/*****按键检测*****/
void check_key(void)
{
P2=0xff;
P3=0xff; //设置为输入状态
switch(P2) //检测按键,输出数码管、载入定时器初值、允许中断
{
case 0xfe:shumaguan=0xF9;tone1=0xfb;tone2=0x90;EA=1;break;
case 0xfd:shumaguan=0xA4;tone1=0xfc;tone2=0xc;EA=1;break;
case 0xfb:shumaguan=0xB0;tone1=0xfc;tone2=0x7b;EA=1;break;
case 0xf7:shumaguan=0x99;tone1=0xfc;tone2=0xad;EA=1;break;
case 0xef:shumaguan=0x92;tone1=0xfd;tone2=0xa;EA=1;break;
case 0xdf:shumaguan=0x82;tone1=0xfd;tone2=0x5d;EA=1;break;
case 0xbf:shumaguan=0xF8;tone1=0xfd;tone2=0xa7;EA=1;break;
case 0x7f:play1();break;
default: EA=0;SPK=0;shumaguan=0xff;//如果没有键按下则关闭中断和数码管
}
switch(P3)
{
case 0xfe:shumaguan=0x79;tone1=0xfd;tone2=0xc8;EA=1;break;
case 0xfd:shumaguan=0x24;tone1=0xfe;tone2=0x6;EA=1;break;
case 0xfb:shumaguan=0x30;tone1=0xfe;tone2=0x3e;EA=1;break;
case 0xf7:shumaguan=0x19;tone1=0xfe;tone2=0x57;EA=1;break;
case 0xef:shumaguan=0x12;tone1=0xfe;tone2=0x85;EA=1;break;
case 0xdf:shumaguan=0x02;tone1=0xfe;tone2=0xaf;EA=1;break;
case 0xbf:shumaguan=0x78;tone1=0xfe;tone2=0xd4;EA=1;break;
case 0x7f:play2();break;
default: EA=0;SPK=0;shumaguan=0xff;//如果没有键按下则关闭中断和数码管
}
}
/*****主程序*****/
void main(void)
{
initTimer();
// shumaguan=0xff;
TR0=1;
ET0=1;
SPK=0;
while(1)
{
check_key();
}
}
/*****END*****/
这个不仅有你说的功能,还集有了一首《军港之夜》的歌在里面
AT89S52
是一种低功耗、高性能CMOS8位微控制器,具有8K
在系统可编程Flash存储器。使用Atmel
公司高密度非易失性存储器技术制造,与工业80C51
产品指令和引脚完全兼容。片上Flash允许程序存储器在系统可编程,亦适于常规编程器。在单芯片上,拥有灵巧的8
位CPU
和在系统可编程Flash,使得AT89S52为众多嵌入式控制应用系统提供高灵活、超有效的解决方案。
AT89S52具有以下标准功能:
8k字节Flash,256字节RAM,
32
位I/O
口线,看门狗定时器,2
个数据指针,三个16
位
定时器/计数器,一个6向量2级中断结构,全双工串行口,
片内晶振及时钟电路。另外,AT89S52
可降至0Hz
静态逻
辑操作,支持2种软件可选择节电模式。空闲模式下,CPU
停止工作,允许RAM、定时器/计数器、串口、中断继续工
作。掉电保护方式下,RAM内容被保存,振荡器被冻结,单片机一切工作停止,直到下一个中断或硬件复位为止。
1、与MCS-51单片机产品兼容;
2、8K字节在系统可编程Flash存储器;
3、1000次擦写周期;
4、全静态操作:0Hz-33MHz;
5、三级加密程序存储器;
6、32个可编程I/O口线;
7、三个16位定时器/计数器;
8、8个中断源;
9、全双工UART串行通道;
10、低功耗空闲和掉电模式;
11、掉电后中断可唤醒;
12、看门狗定时器;
13、双数据指针;
14、掉电标识符。
1.从沙子中提取二氧化硅。
2.把二氧化硅还原成硅(化学纯)。
3.用菜刀切割纯硅成片(尺寸0.4公分x0.4公分x0.05公分)。
4.用0.001纳米的激光束在电子显微镜下,在硅表面画出10个晶体管的布局图(不用自己画,网上下载一个数据包就可以,计算机会自己执行,这个数据是3000G左右)。
5.之后用化学试剂蚀刻就成了。
6.制作电路板,并焊好针脚。
7.盖上屏蔽罩,就OK了。
8.插上开机。
9.1分钟后电脑出现一下文字。
10.成功进入进入系统,打开浏览器进入网页读新闻。
at89s52单片机电子琴的介绍到此就结束了,感谢您耐心阅读,谢谢。
本文标签:at89s52单片机电子琴