目录
1 设计内容:
1.1 矩阵键盘代表琴键,实现至少8个音的弹奏,分别为1,2,3,4,5,6,7,i.
1.2 键按下时间的长短代表节拍的长短
1.3 用蜂鸣器发出声音
1.4 8*8led点阵动态显示音符高低(自用显示)
2 系统硬件设计
2.1 硬件组成
2.2 显示模块
2.3 按键模块
2.4 发音模块
3 系统主程序流程图
4 protues原理图
5 AD的pcb图
6 程序代码
本次设计简易电子琴,通过STC89C52芯片最小控制电路,以16位矩阵电盘,蜂鸣器产生16个音阶,8x8点阵led显示音符高低,独立按键控制复位。将不同模块结合起来,实现简易电子琴的设计。
硬件以ST89C52芯片为核心,外部扩展4x4矩阵式键盘来模拟16个按键,用蜂鸣器来发声,外部扩展8*8LED点阵来动态显示音符的简谱。
基本引荐结构图如图2所示。
图2
点阵屏的8个行引脚与单片机的P0口相连并且接上拉电阻;而点阵的8个列引脚则直接与单片机的P2口相连。
显示模块的电路图如图2.1所示。
16位矩阵键盘,通过P1口控制音阶的产生和led点阵显示,按下相应的的键产生设定的声音和点亮对应的led点阵屏,按键模块的电路图如图2.3所示。
图2.3
使用无源蜂鸣器,通过内部程序产生不同频率的方波,使蜂鸣器产生16个基本的音阶,16个按键分别是中音和高音的Do,Re,Mi,Fa,So,La,Si,Do.蜂鸣器与P3^6相接,电路图如图2.4所示。
图2.4
#include
#include
#include
//#define PA XBYTE[0xff7c]
//#define PB XBYTE[0xff7d]
//#define PC XBYTE[0xff7e]
#define CTRL XBYTE[0xff7f]
#define temp P1
#define uchar unsigned char
uchar code Table_of_Digits[] = { //8*8led点阵段码 ,1~f
0xFF,0xFF,0xF9,0xFB,0xFB,0xFB,0xF1,0xFF,/*"1",0*/
0xFF,0xFF,0xF8,0xFA,0xFD,0xFE,0xF8,0xFF,/*"2",1*/
0xFF,0xFF,0xF8,0xFB,0xFD,0xFB,0xF8,0xFF,/*"3",2*/
0xFF,0xFF,0xFB,0xF9,0xFA,0xF0,0xF1,0xFF,/*"4",3*/
0xFF,0xFF,0xF8,0xF8,0xFB,0xFB,0xF8,0xFF,/*"5",4*/
0xFF,0xFF,0xF9,0xF8,0xFA,0xFA,0xF8,0xFF,/*"6",5*/
0xFF,0xFF,0xF9,0xFB,0xFB,0xFB,0xFB,0xFF,/*"7",6*/
0xFF,0xFF,0xF8,0xFA,0xFD,0xFA,0xF8,0xFF,/*"8",7*/
0xFF,0xFF,0xF8,0xFA,0xF8,0xFB,0xFC,0xFF,/*"9",8*/
0xFF,0xFF,0xFF,0xF8,0xFB,0xF8,0xF0,0xFF,/*"a",0*/
0xFF,0xFD,0xFD,0xF9,0xF9,0xF9,0xF9,0xFF,/*"b",1*/
0xFF,0xFF,0xFF,0xF9,0xFE,0xFE,0xF8,0xFF,/*"c",2*/
0xFF,0xF9,0xFB,0xF8,0xFA,0xFA,0xF8,0xFF,/*"d",3*/
0xFF,0xFF,0xFF,0xF9,0xF9,0xF9,0xF9,0xFF,/*"e",4*/
0xFF,0xF9,0xFD,0xF8,0xFD,0xFD,0xF8,0xFF,/*"f",5*/
};
void delay(unsigned int z); //延时函数,参数为非负整型,延时1ms
void display( int yin) ; //led显示函数,参数为整型,
void function1 (void) ; //该函数用于主函数中的按键发音 和点阵显示
int keyscan(); //键盘扫描并返回键值
unsigned int pin[]={64580,64684,64777,64820,64898,64985,65030,65058,65110,65157,65178,65217,65252,65265,65283,65290};//16个音阶简谱码(T值)
unsigned int syin[16]={ 0}; //存储16音阶
sbit P36=P3^6; //beep蜂鸣器引脚
int yin,i;
unsigned poe; //用于存储按键扫描函数返回的键值
unsigned char key_num;
main() //???
{ EA=1; //总中断允许
TMOD=0x01; //定时器T0工作方式1
ET0=1; //T0中断允许
PT0=1; //T0为高级中断
CTRL=0x89;
while(1)
{
function1();
}
}
void function1 (void) //按键返回值存储,长按发音和显示
{ poe = keyscan(); //????????
switch(poe)
{
case 1:yin=1; //按键对应的音阶
break;
case 2:yin=2;
break;
case 3:yin=3;
break;
case 4:yin=4;
break;
case 5:yin=5;
break;
case 6:yin=6;
;break;
case 7:yin=7;
break;
case 8:yin=8;
break;
case 9:yin=9;
break;
case 10:yin=10;
break;
case 11:yin=11;
break;
case 12:yin=12;
break;
case 13:yin=13;
break;
case 14:yin=14;
;break;
case 15:yin=15;
break;
case 16:yin=16;
break;}
if(poe!=0xff) //按键按下
{ if (yin==1) {
TH0=pin[yin-1]/256; //寻找对应的简谱码给T0赋值,以获取相应的脉冲,蜂鸣器按照相应的频率发音
TL0=pin[yin-1]%256;
while(poe==1)
{
TR0=1; //定时器开始计数
poe = keyscan(); //用于不断扫描,判断键值是否还等于while小括号里面的值,如果等于,说明按键没有松开,则进入中断实现发音。
display(yin -1 );
}
TR0=0;
}
if (yin==2){
TH0=pin[yin-1]/256;
TL0=pin[yin-1]%256;
while(poe==2)
{
TR0=1;
poe = keyscan();
display(yin -1 );
}
TR0=0;
}
if (yin==3) {
TH0=pin[yin-1]/256;
TL0=pin[yin-1]%256;
while(poe==3)
{
TR0=1;
poe = keyscan();
display(yin -1 );
}
TR0=0;
}
if (yin==4) {
TH0=pin[yin-1]/256;
TL0=pin[yin-1]%256;
while(poe==4)
{
TR0=1;
poe = keyscan();
display(yin -1 );
}
TR0=0;
}
if (yin==5) {
TH0=pin[yin-1]/256;
TL0=pin[yin-1]%256;
while(poe==5)
{
TR0=1;
poe = keyscan();
display(yin -1 );
}
TR0=0;
}
if (yin==6) {
TH0=pin[yin-1]/256;
TL0=pin[yin-1]%256;
while(poe==6)
{
TR0=1;
poe = keyscan();
display(yin -1 );
}
TR0=0;
}
if (yin==7) {
TH0=pin[yin-1]/256;
TL0=pin[yin-1]%256;
while(poe==7)
{
TR0=1;
poe = keyscan();
display(yin -1 );
}
TR0=0;
}
if (yin==8) {
TH0=pin[yin-1]/256;
TL0=pin[yin-1]%256;
while(poe==8)
{
TR0=1;
poe = keyscan();
display(yin -1 );
}
TR0=0;
}
if (yin==9) {
TH0=pin[yin-1]/256;
TL0=pin[yin-1]%256;
while(poe==9)
{
TR0=1;
poe = keyscan();
display(yin -1 );
}
TR0=0;
}
if (yin==10) {
TH0=pin[yin-1]/256;
TL0=pin[yin-1]%256;
while(poe==10)
{
TR0=1;
poe = keyscan();
display(yin -1 );
}
TR0=0;
}
if (yin==11) {
TH0=pin[yin-1]/256;
TL0=pin[yin-1]%256;
while(poe==11)
{
TR0=1;
poe = keyscan();
display(yin -1 );
}
TR0=0;
}
if (yin==12) {
TH0=pin[yin-1]/256;
TL0=pin[yin-1]%256;
while(poe==12)
{
TR0=1;
poe = keyscan();
display(yin -1 );
}
TR0=0;
}
if (yin==13) {
TH0=pin[yin-1]/256;
TL0=pin[yin-1]%256;
while(poe==13)
{
TR0=1;
poe = keyscan();
display(yin -1 );
}
TR0=0;
}
if (yin==14) {
TH0=pin[yin-1]/256;
TL0=pin[yin-1]%256;
while(poe==14)
{
TR0=1;
poe = keyscan();
display(yin -1 );
}
TR0=0;
}
if (yin==15) {
TH0=pin[yin-1]/256;
TL0=pin[yin-1]%256;
while(poe==15)
{
TR0=1;
poe = keyscan();
display(yin -1 );
}
TR0=0;
}
if (yin==16) {
TH0=pin[yin-1]/256;
TL0=pin[yin-1]%256;
while(poe==16)
{
TR0=1;
poe = keyscan();
display(yin -1 );
// display(syin);
}
TR0=0;
}
for (i=15;i>0;i--)
syin[i]=syin[i-1];
syin[0]=yin;
} P36=1;
}
void delay(unsigned int z) //延时函数,延时1ms
{
unsigned int x,y;
for(x=z;x>0;x--)
for(y=125;y>0;y--);
}
void fasheng() interrupt 1 //T0 中断
{
TH0=pin[yin-1]/256;
TL0=pin[yin-1]%256;
P36=~P36; //P3^6引脚发出相应的脉冲信号驱动蜂鸣器发声
}
int keyscan() //矩阵键盘扫描函数,返回按键值num
{
uchar num;
temp=0xf0;
if(temp!=0xf0) //先将高四位全部置高电平,低四位全部置低电平,当高四位不全为高电平时,说明有按键按下,然后通过接受的数据值,判断是哪一列有按键按下
{
delay(10); //延时10ms消抖
if(temp!=0xf0)
{
temp=0xf0;
switch(temp)
{
case 0x70: num=1; break;
case 0xb0: num=5; break;
case 0xd0: num=9; break;
case 0xe0: num=13; break;
}
temp=0x0f;
switch(temp)
{
case 0x07: num=num+0; break;
case 0x0b: num=num+1; break;
case 0x0d: num=num+2; break;
case 0x0e: num=num+3; break;
}
}
else
num = 0xff;
}
return num;
}
void display(yin)
{
uchar i;
for(i = 0 ;i < 8;i++)
{
P0= i%8; //位值
P2 = Table_of_Digits[i+yin*8]; //段码
delay(1);
P2 = 0xff; //熄灭
}
}