笔者开发了一种电路,它可以安装在电子琴的按键上。这个电路有64个LED指示灯,64个按键。这64个按键和电子琴共用。电子琴也使用这64个按键弹奏音乐。每个按键对应一个LED灯。电路通过STC89C51单片机控制,当要演奏一首乐曲时,这个乐曲要弹奏的第一个按键上面的LED灯就会亮起来,只有演奏者按下这个按键,这个LED等才会熄灭。同时,当上一个LED灯熄灭以后,这个乐曲要弹奏的第二个按键上面的LED灯就会亮起。只有演奏者按下这个按键,这个LED等才会熄灭。紧接着,这个乐曲要弹奏的第三个按键上面的LED灯就会亮起,同样,只有演奏者按下这个按键,这个LED等才会熄灭。按键上面的LED就按照乐曲要弹奏的按键的顺序亮起,同时,只有演奏者按照乐曲要弹奏的按键的顺序弹奏乐曲,按键上的LED才会熄灭。这样就实现了,演奏者按照乐曲弹奏按键的顺序,也就是按照LED等亮起的顺序,演奏乐曲的功能。也就让一个不会弹琴的人,按照LED的指示来学习弹琴。下面是这个电路的电路图。
电路中,单片机STC89C51控制芯片HD7279A。使用KEILL软件编程。HD7279A控制64个按键和64个LED灯。按照程序,第一个LED亮,当按下第一个按键时,这个LED灭,同时,第二个LED亮,当按下第二个按键时,这个LED灭。这样就实现了按键以此熄灭LED的功能。下面是程序:
#include <reg52.h>
//*** 函数定义 ***
void long_delay(void); // 长延时
void short_delay(void); // 短暂延时
void delay10ms(unsigned char); // 延时10MS
void write7279(unsigned char, unsigned char); // 写入到HD7279
unsigned char read7279(unsigned char); // 从HD7279读出
void send_byte(unsigned char); // 发送一个字节
unsigned char receive_byte(void); // 接收一个字节
//*** 变量及I/O口定义 ***
unsigned char digit[5];
unsigned char key_number, j, k,m,n;
unsigned int tmr;
unsigned long wait_cnter;
unsigned char code dis_code[65]
=
{16,17,1,2};
unsigned char code dis_code1[256]
=
{0,1,2,3,4};
unsigned char code dis_code2[9]
=
{0,1,2,3,4,5,6,7,8};
unsigned char code dis_code3[65]
=
{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
unsigned char code dis_code4[256]
=
{0,1,2,3,4,5,6,7,8,9,10,11,12};
unsigned char code dis_code5[128]
=
{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17};
unsigned char code dis_code6[65]
=
{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
unsigned char code dis_code7[256]
=
{0,1,2,3,4,5,6,7,8,9,10};
unsigned char code dis_code8[128]
=
{0,1,2,3,4,5,6,7,8,9,10,11};
unsigned char code dis_code9[128]
=
{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
sbit cs=P1^4; // cs at P1.4
sbit clk=P1^5; // clk 连接于 P1.5
sbit dat=P1^2; // dat 连接于 P1.2
sbit key=P1^3; // key 连接于 P1.3
sbit S1=P0^0; // key 连接于 P1.3
sbit S2=P0^1; // key 连接于 P1.3
//****** HD7279A 指令 ******
#define CMD_RESET 0xa4
#define CMD_TEST 0xbf
#define DECODE0 0x80
#define DECODE1 0xc8
#define CMD_READ 0x15
#define UNDECODE 0x90
#define RTL_CYCLE 0xa3
#define RTR_CYCLE 0xa2
#define RTL_UNCYL 0xa1
#define RTR_UNCYL 0xa0
#define ACTCTL 0x98
#define SEGON 0xe0
#define SEGOFF 0xc0
#define BLINKCTL 0x88
void write7279(unsigned char cmd, unsigned char dta)
{
send_byte (cmd);
send_byte (dta);
}
unsigned char read7279(unsigned char command)
{
send_byte(command);
return(receive_byte());
}
void send_byte( unsigned char out_byte)
{
unsigned char i;
cs=0;
long_delay();
for (i=0;i<8;i++)
{
if (out_byte&0x80)
{
dat=1;
}
else
{
dat=0;
}
clk=1;
short_delay();
clk=0;
short_delay();
out_byte=out_byte*2;
}
dat=0;
}
unsigned char receive_byte(void)
{
unsigned char i, in_byte;
dat=1; // set to input mode
long_delay();
for (i=0;i<8;i++)
{
clk=1;
short_delay();
in_byte=in_byte*2;
if (dat)
{
in_byte=in_byte|0x01;
}
clk=0;
short_delay();
}
dat=0;
return (in_byte);
}
void long_delay(void)
{
unsigned char i;
for (i=0;i<0x30;i++);
}
void short_delay(void)
{
unsigned char i;
for (i=0;i<8;i++);
}
// ******* 延时n个1MS *******
// ******* 输入:n 延时个数 *******
void delay1ms(unsigned char n)
{
unsigned int i;
while(n --)
{
for(i = 0;i < 125;i ++); // i ++ ,8μS 左右
}
}
// ******* 延时n个10MS *******
// ******* 输入:n 延时个数 *******
void delay10ms(unsigned char n)
{
unsigned int i;
while(n --)
{
for(i = 0;i < 1250;i ++); // i ++ ,8μS 左右
}
}
void delay(void)
{
unsigned int n;
for(n=0;n<10000;n++)
;
}
//*** 主程序 ***
//*** 主程序 ***
main()
{
unsigned char p;
p=0; //将i初始化为0
while(1)
{
if(S1==0) //如果S1键按下
{ delay10ms(20);
//延时一段时间
if(S1==0) //如果再次检测到S1键按下
p++; //i自增1
delay10ms(20);
//延时一段时间
if(p==4) //如果i=9,重新将其置为1
p=1;
}
switch(p) //使用多分支选择语句
{
case 1:
for (j=0;j<256;)
{
write7279(SEGON,dis_code1[j]); // 将64个显示段逐个点亮
if (!key) // 如果有键按下
{
key_number=read7279(CMD_READ); // 读出键码
if (key_number==dis_code1[j]) // 如果有键按下
{
write7279(SEGOFF,dis_code1[j]); // 将64个显示段逐个点亮
delay10ms(20);
j++;
}
}
}
break;
case 2:
for (j=0;j<256;)
{
write7279(SEGON,dis_code[j]); // 将64个显示段逐个点亮
if (!key) // 如果有键按下
{
key_number=read7279(CMD_READ); // 读出键码
if (key_number==dis_code[j]) // 如果有键按下
{
write7279(SEGOFF,dis_code[j]); // 将64个显示段逐个点亮
delay10ms(20);
j++;
}
}
break;
default: //缺省值,关闭所有LED
P0=0xff;
}
}
}
}