基于单片机的电子琴(汇编与C语言&&延时播放与发声第二键)

基于51单片机的电子琴程序设计


实现功能

设计一个带显示按键序号的电子琴,要求如下:
1、设计一个电子琴,利用所给键盘的8个按键,发出8个不同的音调,并在LED数码管上显示相应的音调。
2、要求按下按键发声,松开延时一段时间后停止;在前一个按下的键发声的同时如果有另一个键被按下,则前面键的发音停止,后按的键发音开始。
3、具有简易的控制按键。


电路设计

如图:
在这里插入图片描述
电子琴设有8个按键, 8个按键分别代表8个音符,分别连接到P3口的8个接口,共阳极数码管接到P2口,发声模块接到P1.4口。


程序设计

我们可以利用单片机的定时/计数器T0来产生不同的方波频率信号,每个按键对应不同的定时器预设值,对应不同的音调。

说下对定时器中断的理解:cpu在执行机器周期时会在末尾自动查看中断是否打开,也就是隔几微秒查看中断是否打开。当我们按键被按下时TR0置1,打开中断,cpu检测到,调用我们的中断服务程序,给定时器高8位和低8位赋时间预设值,时间预设值到定时结束的这段时间内,在这段时间喇叭没有接收到电压。定时时间到了,调用CPL P1.4将喇叭接口取反,即喇叭接口赋高电平。在中断服务程序里给高八位和低八位重新的赋值。由于按键还是被按下,中断还是打开,重装执行中断服务程序,继续定时,这段时间喇叭接口是有电压的。定时结束,取反,喇叭接口赋低电平。由于cpu执行指令很快的,就会产生预设值期间的高电平和定时期间的低电平的节拍,这就是频率,因为我们定义每个按键的预设值不一样,节拍不一样,频率就不一样了,电压的占空比不一样,以此就可以通过PWM调节蜂鸣器,所以产生不一样的音调。

定义一个按键扫描函数,在主程序里不断循环调用按键扫描函数,以此检测是否有按键被按下。8个按键对应8种情况,每种情况又有第二个键被按下的7种情况。通过赋值P3口全部高电平,当有按键按下时,该接口就会变成低电平。当检测到该接口为低电平时,循环判断自己的接口是否变为高电平。如果一直按下该键,则一直为低电平,在循环之中。在循环之中再判断是否有其他接口变为低电平,如果有其他接口变为低电平,重新给定时器的高八位和第八位赋值,以此达到了同时按下第二个键时发声第二个键的音调;如果松开该按键,则跳出循环,调用延时1s的函数,以此达到延时播放的功能。之后关闭中断,一旦中断被置0,中断结束,喇叭接口不再取反,不再产生频率,但此时的喇叭接口有可能是高电平,要在调用延时函数之后将喇叭接口置0,以此关闭声音。
焊接实物如下:
在这里插入图片描述


C语言程序设计

#include<reg52.h>//包含头文件
#define uint unsigned int
#define uchar unsigned char//宏定义

//喇叭引脚定义
sbit speaker=P1^4;
//按钮引脚定义
sbit key1 = P3^0; 																
sbit key2 = P3^1;
sbit key3 = P3^2;
sbit key4 = P3^3;
sbit key5 = P3^4;
sbit key6 = P3^5;
sbit key7 = P3^6;
sbit key8 = P3^7;

//声明两个无符号字符型变量,用于定时器初值的赋值
uchar a;
uchar b;

//延时函数(用于按键松开后延时播放音调)
void delay(uint temp)
{
	uint i, j;
	for (i = 0; i <= temp; i++)
		for (j = 0; j <= 120; j++);
}

void check_key()
{
	P3=0xff;//先赋给P3组口高电平
	switch(P3)//当有按键按下,P3口的状态就会改变
	{
		case 0xfe:  //11111110,第一次扫描到按键1
			P2 = 0xfc;   //11111100    数字1
			a = 0xfb;   //高八位赋时间预设值 
			b = 0xe9;   //低八位赋时间预设值
			EA = 1;     //开中断
			//发声按下的第二个按键(按下第一个按键的后同时按第二个键,发声第二个键的音调)
			//每个case里面循环判断自己的按键是否松开,如果一直被按着,则判断其他7个按键是否按下并改变中断的预初始值。
			while (key1==0)
			{
				//先按1的同时再按下2
				if(key2==0)
				{
					P2 = 0xa2;
					a = 0xfc;
				    b = 0x5c;
				}
				//先按1的同时再按下3
				if (key3 == 0)
				{
					P2 = 0xb0;
					a = 0xfc;
					b = 0xc1;
				}
				//先按1的同时再按下4
				if (key4 == 0)
				{
					P2 = 0x9c;
					a = 0xfc;
					b = 0xef;
				}
				//先按1的同时再按下5
				if (key5 == 0)
				{
					P2 = 0x91;
					a = 0xfd;
					b = 0x45;
				}
				//先按1的同时再按下6
				if (key6 == 0)
				{
					P2 = 0x81;
					a = 0xfd;
					b = 0x92;
				}
				//先按1的同时再按下7
				if (key7 == 0)
				{
					P2 = 0xf8;
					a = 0xfd;
					b = 0xd0;
				}
				//先按1的同时再按下8
				if (key8 == 0)
				{
					P2 = 0x80;
					a = 0xfd;
					b = 0xee;
				}
			}
			//当按键1松开
			P2= 0xff; //数码管不显示
			delay(800);//延时一段时间
			EA = 0; //关中断
			speaker = 0; //关声音
			break;//当第一个按键按下,P3口状态就是11111110,也就是0xfe,就执行后面的P2口点亮对应的LED,并给定时器赋初值,打开中断系统总开关
		
		case 0xfd:     //11111101,当按下按键2
			P2=0xa2;   //10100010 ,数码管显示数字2
			a=0xfc;
			b=0x5c;
			EA=1;
			while (key2 == 0)
			{
				//先按2的同时再按下1
				if(key1 == 0)
				{
					P2 = 0xfc;
					a = 0xfb;
					b = 0xe9;
				}
				//先按2的同时再按下3
				if (key3 == 0)
				{
					P2 = 0xb0;
					a = 0xfc;
					b = 0xc1;
				}
				//先按2的同时再按下4
				if (key4 == 0)
				{
					P2 = 0x9c;
					a = 0xfc;
					b = 0xef;
				}
				//先按2的同时再按下5
				if (key5 == 0)
				{
					P2 = 0x91;
					a = 0xfd;
					b = 0x45;
				}
				//先按2的同时再按下6
				if (key6 == 0)
				{
					P2 = 0x81;
					a = 0xfd;
					b = 0x92;
				}
				//先按2的同时再按下7
				if (key7 == 0)
				{
					P2 = 0xf8;
					a = 0xfd;
					b = 0xd0;
				}
				//先按2的同时再按下8
				if (key8 == 0)
				{
					P2 = 0x80;
					a = 0xfd;
					b = 0xee;
				}
			}
			//当按键2松开
			P2 = 0xff; //数码管不显示
			delay(800);//延时一段时间
			EA = 0; //关中断
			speaker = 0; //关声音
			break;
		
		case 0xfb:   //11111011
			P2=0xb0;  //10110000  数字3
			a=0xfc;
			b=0xc1;
			EA=1;
			while (key3 == 0)
			{
				//先按3的同时再按下1
				if(key1 == 0)
				{
					P2 = 0xfc;
					a = 0xfb;
					b = 0xe9;
				}
				//先按3的同时再按下2
				if(key2 == 0)
				{
					P2 = 0xa2;
					a = 0xfc;
					b = 0x5c;
				}
				//先按3的同时再按下4
				if (key4 == 0)
				{
					P2 = 0x9c;
					a = 0xfc;
					b = 0xef;
				}
				//先按3的同时再按下5
				if (key5 == 0)
				{
					P2 = 0x91;
					a = 0xfd;
					b = 0x45;
				}
				//先按3的同时再按下6
				if (key6 == 0)
				{
					P2 = 0x81;
					a = 0xfd;
					b = 0x92;
				}
				//先按3的同时再按下7
				if (key7 == 0)
				{
					P2 = 0xf8;
					a = 0xfd;
					b = 0xd0;
				}
				//先按3的同时再按下8
				if (key8 == 0)
				{
					P2 = 0x80;
					a = 0xfd;
					b = 0xee;
				}
			}
			//当按键3松开
			P2 = 0xff; //数码管不显示
			delay(800);//延时一段时间
			EA = 0; //关中断
			speaker = 0; //关声音
			break;//同上
	
		case 0xf7:  //11110111
			P2=0x9c;  //10011100  数字4
			a=0xfc;
			b=0xef;
			EA=1;
			while (key4 == 0)
			{
				//先按4的同时再按下1
				if(key1 == 0)
				{
					P2 = 0xfc;
					a = 0xfb;
					b = 0xe9;
				}
				//先按4的同时再按下2
				if(key2 == 0)
				{
					P2 = 0xa2;
					a = 0xfc;
					b = 0x5c;
				}
				//先按4的同时再按下3
				if (key3 == 0)
				{
					P2 = 0xb0;
					a = 0xfc;
					b = 0xc1;
				}
				//先按4的同时再按下5
				if (key5 == 0)
				{
					P2 = 0x91;
					a = 0xfd;
					b = 0x45;
				}
				//先按4的同时再按下6
				if (key6 == 0)
				{
					P2 = 0x81;
					a = 0xfd;
					b = 0x92;
				}
				//先按4的同时再按下7
				if (key7 == 0)
				{
					P2 = 0xf8;
					a = 0xfd;
					b = 0xd0;
				}
				//先按4的同时再按下8
				if (key8 == 0)
				{
					P2 = 0x80;
					a = 0xfd;
					b = 0xee;
				}
			}
			//当按键4松开
			P2 = 0xff; //数码管不显示
			delay(800);//延时一段时间
			EA = 0; //关中断
			speaker = 0; //关声音
			break;
	
		case 0xef:   //11101111,当按下按键5
			P2=0x91;  //10010001 ,数码管显示数字5
			a=0xfd;
			b=0x45;
			EA=1;
			while (key5 == 0)
			{
				//先按5的同时再按下1
				if(key1 == 0)
				{
					P2 = 0xfc;
					a = 0xfb;
					b = 0xe9;
				}
				//先按5的同时再按下2
				if(key2 == 0)
				{
					P2 = 0xa2;
					a = 0xfc;
					b = 0x5c;
				}
				//先按5的同时再按下3
				if (key3 == 0)
				{
					P2 = 0xb0;
					a = 0xfc;
					b = 0xc1;
				}
				//先按5的同时再按下4
				if (key4 == 0)
				{
					P2 = 0x9c;
					a = 0xfc;
					b = 0xef;
				}
				//先按5的同时再按下6
				if (key6 == 0)
				{
					P2 = 0x81;
					a = 0xfd;
					b = 0x92;
				}
				//先按5的同时再按下7
				if (key7 == 0)
				{
					P2 = 0xf8;
					a = 0xfd;
					b = 0xd0;
				}
				//先按5的同时再按下8
				if (key8 == 0)
				{
					P2 = 0x80;
					a = 0xfd;
					b = 0xee;
				}
			}
			//当按键5松开
			P2 = 0xff; //数码管不显示
			delay(800);//延时一段时间
			EA = 0; //关中断
			speaker = 0; //关声音
			break;//P2组为发光二极管组

		case 0xdf:   //11011111,当按下按键6
			P2=0x81;  //10000001  ,数码管显示数字6
			a=0xfd;
			b=0x92;
			EA=1;
			while (key6 == 0)
			{
				//先按6的同时再按下1
				if(key1 == 0)
				{
					P2 = 0xfc;
					a = 0xfb;
					b = 0xe9;
				}
				//先按6的同时再按下2
				if(key2 == 0)
				{
					P2 = 0xa2;
					a = 0xfc;
					b = 0x5c;
				}
				//先按6的同时再按下3
				if (key3 == 0)
				{
					P2 = 0xb0;
					a = 0xfc;
					b = 0xc1;
				}
				//先按6的同时再按下4
				if (key4 == 0)
				{
					P2 = 0x9c;
					a = 0xfc;
					b = 0xef;
				}
				//先按6的同时再按下5
				if (key5 == 0)
				{
					P2 = 0x91;
					a = 0xfd;
					b = 0x45;
				}
				//先按6的同时再按下7
				if (key7 == 0)
				{
					P2 = 0xf8;
					a = 0xfd;
					b = 0xd0;
				}
				//先按6的同时再按下8
				if (key8 == 0)
				{
					P2 = 0x80;
					a = 0xfd;
					b = 0xee;
				}
			}
			//当按键6松开
			P2 = 0xff; //数码管不显示
			delay(800);//延时一段时间
			EA = 0; //关中断
			speaker = 0; //关声音
			break;//注意:EA不能改为TR0
	
		case 0xbf:  //10111111,当按下按钮7
			P2=0xf8;   //11111000 ,数码管显示数字7
			a=0xfd;
			b=0xd0;
			EA=1;
			while (key7 == 0)
			{
				//先按7的同时再按下1
				if(key1 == 0)
				{
					P2 = 0xfc;
					a = 0xfb;
					b = 0xe9;
				}
				//先按7的同时再按下2
				if(key2 == 0)
				{
					P2 = 0xa2;
					a = 0xfc;
					b = 0x5c;
				}
				//先按7的同时再按下3
				if (key3 == 0)
				{
					P2 = 0xb0;
					a = 0xfc;
					b = 0xc1;
				}
				//先按7的同时再按下4
				if (key4 == 0)
				{
					P2 = 0x9c;
					a = 0xfc;
					b = 0xef;
				}
				//先按7的同时再按下5
				if (key5 == 0)
				{
					P2 = 0x91;
					a = 0xfd;
					b = 0x45;
				}
				//先按7的同时再按下6
				if (key6 == 0)
				{
					P2 = 0x81;
					a = 0xfd;
					b = 0x92;
				}
				//先按7的同时再按下8
				if (key8 == 0)
				{
					P2 = 0x80;
					a = 0xfd;
					b = 0xee;
				}
			}
			//当按键7松开
			P2 = 0xff; //数码管不显示
			delay(800);//延时一段时间
			EA = 0; //关中断
			speaker = 0; //关声音
			break;
	
		case 0x7f:  //11111111,当按下按钮8
			P2=0x80;  //10000000, 数码管显示数字8
			a=0xfd;
			b=0xee;
			EA=1;
			while (key8 == 0)
			{
				//先按8的同时再按下1
				if(key1 == 0)
				{
					P2 = 0xfc;
					a = 0xfb;
					b = 0xe9;
				}
				//先按8的同时再按下2
				if(key2 == 0)
				{
					P2 = 0xa2;
					a = 0xfc;
					b = 0x5c;
				}
				//先按8的同时再按下3
				if (key3 == 0)
				{
					P2 = 0xb0;
					a = 0xfc;
					b = 0xc1;
				}
				//先按8的同时再按下4
				if (key4 == 0)
				{
					P2 = 0x9c;
					a = 0xfc;
					b = 0xef;
				}
				//先按8的同时再按下5
				if (key5 == 0)
				{
					P2 = 0x91;
					a = 0xfd;
					b = 0x45;
				}
				//先按8的同时再按下6
				if (key6 == 0)
				{
					P2 = 0x81;
					a = 0xfd;
					b = 0x92;
				}
				//先按8的同时再按下7
				if (key7 == 0)
				{
					P2 = 0xf8;
					a = 0xfd;
					b = 0xd0;
				}
			}
			//当按键8松开
			P2 = 0xff; //数码管不显示
			delay(800);//延时一段时间
			EA = 0; //关中断
			speaker = 0; //关声音
			break;
	
		//当什么都没按下
		default:
			EA=0;
			speaker=0;
			P2=0xff;//当P3口为其他状态时(包括无按键按下和多按键按下)关闭声音输出和LED
	}
}

//中断初始化函数
void init()
{
	TMOD=0x01;//定时器工作方式1
	TH0=a;//定时器0初值的高八位
	TL0=b;//定时器0初值的低八位
	ET0=1;//允许中断
	TR0=1;//打开定时器
	EA=0;
}

//主函数
void main()
{
	init();

	while(1)//进入循环
	{
		check_key();//扫描按键
	}
}

//中断服务程序
void time0() interrupt 1//定时器工作函数
{
	TH0=a;//定时器高八位赋初值
	TL0=b;//定时器低八位赋初值
	speaker=~speaker;//喇叭引脚取反
}

汇编程序设计


	        ORG    0000H
	        AJMP   INIT	  ;初始化程序
	        ORG    00BH
	        AJMP   INQP	  ;中断程序
	        ORG    0030H
;初始化
INIT:		MOV     TMOD,#01H	;设置定时器工作方式1
            SETB    ET0			 
  			SETB    TR0
			CLR     EA
;主程序
LOOP:	    LCALL   CHECK		 ;调用按键扫描程序
			SJMP  	 LOOP		 ;循环

;按键检查函数
CHECK:      MOV      P3,#0FFH
            ;如果按键被按下,则跳转到相应的CASE
			JNB      P3.0,CASE1
			JNB      P3.1,CASE2
			JNB      P3.2,CASE3
			JNB      P3.3,CASE4
			JNB      P3.4,CASE5
			JNB      P3.5,CASE6
			JNB      P3.6,CASE7
			JNB      P3.7,CASE8
			LJMP     None
			RET

;由于JNB指令只能跳转到-128~128B之间,所以用CASE的程序LJMP过渡到KEY来执行
CASE1:      LJMP	KEY1
			RET
CASE2:      LJMP	KEY2
            RET
CASE3:      LJMP	KEY3
            RET
CASE4:      LJMP	KEY4
            RET
CASE5:      LJMP	KEY5
            RET
CASE6:      LJMP	KEY6
            RET
CASE7:      LJMP	KEY7
            RET
CASE8:      LJMP	KEY8
            RET


;扫描到按键1被按下
KEY1:      MOV     P2,#0FCH	     ;数码管显示数字1
		   MOV     R0,#0FBH		 ;定时器高八位赋值	
		   MOV     R1,#0E9H		 ;定时器低八位赋值
		   SETB    EA			 ;打开中断,播放声音
		   ;函数名First表示第一个按键被按下,后面的数字是是否有其他按键被按下
		   First1:	  JB      P3.0,Disable1     ;判断当前按键是否松开,如果松开跳转到DISABLE1函数(延时和关中断)
					  ;在第一个按键被按下的情况下判断其他按键是否被按下
					  ;判断第二个按键是否被按下	   
					  JB      P3.1,First3	;如果没有被按下则跳到判断下一个按键的函数
					  MOV     P2,#0A2H		;如果第二个按键被按下,数码管显示数字2
					  MOV     R0,#0FCH		;中断预设值赋值
					  MOV     R1,#05CH		;之后循序执行到SJMP First1,再次不断循环自己判断
					  ;判断第三个按键是否被按下
		   First3:	  JB      P3.2,First4	;如果没有被按下则跳到判断下一个按键的函数
					  MOV     P2,#0B0H		;如果第3个按键被按下,数码管显示数字3
					  MOV     R0,#0FCH		;中断预设值赋值
					  MOV     R1,#0C1H		;之后循序执行到SJMP CASE1,再次不断循环自己判断
					  ;判断第四个按键是否被按下
		   First4:     JB      P3.3,First5	;与上面一样
					  MOV     P2,#09CH		
					  MOV     R0,#0FCH		
					  MOV     R1,#0EFH		
					  ;判断第五个按键是否被按下
		   First5:    JB      P3.4,First6
					  MOV     P2,#091H
					  MOV     R0,#0FDH
					  MOV     R1,#045H
					  ;判断第六个按键是否被按下
		   First6:    JB      P3.5,First7
					  MOV     P2,#081H
				 	  MOV     R0,#0FDH
					  MOV     R1,#092H
					  ;判断第七个按键是否被按下
		   First7:    JB      P3.6,First8
					  MOV     P2,#0F8H
					  MOV     R0,#0FDH
					  MOV     R1,#0D0H
					  ;判断第八个按键是否被按下
		   First8:    JB      P3.7,First1	;如果第8个键也没有被按下,则跳转到First1循环重新执行
					  MOV     P2,#080H
					  MOV     R0,#0FDH
				      MOV     R1,#0EEH
		   ;循环扫描自己的按键
		   SJMP     First1
		   ;JB指令只能跳转到-128~123B直接,所以用DISABLE1过渡到DISABLE来延时声音与清除
		   Disable1:     LJMP    Disable	   ;按键松开,调用关闭声音和中断和延时
		   RET

;扫描到按键2被按下
KEY2:			     MOV     P2,#0A2H	 ;数码管显示数字2
			         MOV     R0,#0FCH	 ;定时器高八位赋值
			         MOV     R1,#05CH	 ;定时器低八位赋值
			         SETB    EA			 ;打开中断,播放声音
					 Second2:     JB      P3.1,Disable2	;判断当前按键是否松开,如果松开跳转到Disable2函数(延时和关中断)
					 ;在第二个按键被按下的情况下判断其他按键是否被按下
					 ;判断第1个按键是否被按下	
					 JB      P3.0,Second3
					 MOV     P2,#0FCH
					 MOV     R0,#0FBH
					 MOV     R1,#0E9H
					 ;判断第3个按键是否被按下
		Second3:     JB      P3.2,Second4
					 MOV     P2,#0B0H
					 MOV     R0,#0FCH
					 MOV     R1,#0C1H
					 ;判断第4个按键是否被按下
	    Second4:     JB      P3.3,Second5
					 MOV     P2,#09CH
					 MOV     R0,#0FCH
					 MOV     R1,#0EFH
					 ;判断第5个按键是否被按下
		Second5:     JB      P3.4,Second6
					 MOV     P2,#091H
					 MOV     R0,#0FDH
					 MOV     R1,#045H
					 ;判断第6个按键是否被按下
		Second6:     JB      P3.5,Second7
					 MOV     P2,#081H
					 MOV     R0,#0FDH
					 MOV     R1,#092H
					 ;判断第7个按键是否被按下
		Second7:     JB      P3.6,Second8
					 MOV     P2,#0F8H
					 MOV     R0,#0FDH
					 MOV     R1,#0D0H
					 ;判断第8个按键是否被按下
		Second8:	 JB      P3.7,Second2	 ;如果第8个键也没有被按下,则跳转到Second2循环重新执行
					 MOV     P2,#080H
					 MOV     R0,#0FDH
					 MOV     R1,#0EEH
		;跳转到Second2循环重新执行
		SJMP    Second2
		Disable2:		 LJMP    Disable
		RET


;扫描到按键3被按下
KEY3:			    MOV     P2,#0B0H	;数码管显示数字3
					MOV     R0,#0FCH		;定时器高八位赋值
					MOV     R1,#0C1H		;定时器低八位赋值
					SETB    EA			;打开中断,播放声音
					Third3:     JB      P3.2,Disable3
					;在第三个按键被按下的情况下判断其他按键是否被按下
					;判断第1个按键是否被按下
					JB      P3.0,Third2
					MOV     P2,#0FCH
					MOV     R0,#0FBH
					MOV     R1,#0E9H
					;判断第2个按键是否被按下
		Third2:     JB      P3.1,Third4
					MOV     P2,#0A2H
					MOV     R0,#0FCH
					MOV     R1,#05CH
					;判断第4个按键是否被按下
		Third4:     JB      P3.3,Third5
					MOV     P2,#09CH
					MOV     R0,#0FCH
					MOV     R1,#0EFH
					;判断第5个按键是否被按下
		Third5:     JB      P3.4,Third6
					MOV     P2,#091H
					MOV     R0,#0FDH
					MOV     R1,#045H
					;判断第6个按键是否被按下
		Third6:     JB      P3.5,Third7
					MOV     P2,#081H
					MOV     R0,#0FDH
					MOV     R1,#092H
					;判断第7个按键是否被按下
		Third7:		JB      P3.6,Third8
					MOV     P2,#0F8H
					MOV     R0,#0FDH
					MOV     R1,#0D0H
					;判断第8个按键是否被按下
		Third8:		JB      P3.7,Third3		 ;如果第8个键也没有被按下,则跳转到Third3循环重新执行
					MOV     P2,#080H
					MOV     R0,#0FDH
					MOV     R1,#0EEH
		;跳转到Third3循环重新执行
		SJMP    Third3
		Disable3:		LJMP    Disable
		RET

;扫描到按键4被按下
KEY4:				     MOV     P2,#09CH
					     MOV     R0,#0FCH
					     MOV     R1,#0EFH
					     SETB    EA
			 Forth4:	 JB      P3.3,Disable4
						 ;在第4个按键被按下的情况下判断其他按键是否被按下
					     ;判断第1个按键是否被按下
						 JB      P3.0,Forth2
						 MOV     P2,#0FCH
						 MOV     R0,#0FBH
						 MOV     R1,#0E9H
						 ;判断第2个按键是否被按下
			 Forth2:	 JB      P3.1,Forth3
						 MOV     P2,#0A2H
						 MOV     R0,#0FCH
						 MOV     R1,#05CH
						 ;判断第3个按键是否被按下
			 Forth3:	 JB      P3.2,Forth5
						 MOV     P2,#0B0H
						 MOV     R0,#0FCH
						 MOV     R1,#0C1H
						 ;判断第5个按键是否被按下
			 Forth5:	 JB      P3.4,Forth6
						 MOV     P2,#091H
						 MOV     R0,#0FDH
						 MOV     R1,#045H
						 ;判断第6个按键是否被按下
             Forth6:	 JB      P3.5,Forth7
						 MOV     P2,#081H
						 MOV     R0,#0FDH
						 MOV     R1,#092H
						 ;判断第7个按键是否被按下
			 Forth7:	 JB      P3.6,Forth8
						 MOV     P2,#0F8H
						 MOV     R0,#0FDH
						 MOV     R1,#0D0H
						 ;判断第8个按键是否被按下
             Forth8:	 JB      P3.7,Forth4	   ;如果第8个键也没有被按下,则跳转到Forth4循环重新执行
						 MOV     P2,#080H
						 MOV     R0,#0FDH
						 MOV     R1,#0EEH

			 SJMP    Forth4
			 Disable4:	 LJMP    Disable
			 RET

;扫描到按键5被按下
KEY5:			 		 MOV     P2,#091H
						 MOV     R0,#0FDH
						 MOV     R1,#045H
						 SETB    EA
			 Fifth5:	 JB      P3.4,Disable5
						 ;在第5个按键被按下的情况下判断其他按键是否被按下
					     ;判断第1个按键是否被按下
						 JB      P3.0,Fifth2
						 MOV     P2,#0FCH
						 MOV     R0,#0FBH
						 MOV     R1,#0E9H
						 ;判断第2个按键是否被按下
			 Fifth2:	 JB      P3.1,Fifth3
						 MOV     P2,#0A2H
						 MOV     R0,#0FCH
						 MOV     R1,#05CH
						 ;判断第3个按键是否被按下
             Fifth3:	 JB      P3.2,Fifth4
						 MOV     P2,#0B0H
						 MOV     R0,#0FCH
						 MOV     R1,#0C1H
						 ;判断第4个按键是否被按下
			 Fifth4:	 JB      P3.3,Fifth6
						 MOV     P2,#09CH
						 MOV     R0,#0FCH
						 MOV     R1,#0EFH
						 ;判断第6个按键是否被按下
			 Fifth6:	 JB      P3.5,Fifth7
						 MOV     P2,#081H
						 MOV     R0,#0FDH
						 MOV     R1,#092H
						 ;判断第7个按键是否被按下
			 Fifth7:	 JB      P3.6,Fifth8
						 MOV     P2,#0F8H
						 MOV     R0,#0FDH
						 MOV     R1,#0D0H
						 ;判断第8个按键是否被按下
			 Fifth8:	 JB      P3.7,Fifth5
						 MOV     P2,#080H
						 MOV     R0,#0FDH
						 MOV     R1,#0EEH
						 
			 SJMP    Fifth5
			 Disable5:	 LJMP    Disable
			 RET


;扫描到按键6被按下
KEY6:		           MOV     P2,#081H
					   MOV     R0,#0FDH
					   MOV     R1,#092H
					   SETB    EA
			 Sixth6:   JB      P3.5,Disable6
					   ;在第6个按键被按下的情况下判断其他按键是否被按下
					   ;判断第1个按键是否被按下
					   JB      P3.0,Sixth2
                       MOV     P2,#0FCH
					   MOV     R0,#0FBH
					   MOV     R1,#0E9H
					   ;判断第2个按键是否被按下
			 Sixth2:   JB      P3.1,Sixth3
					   MOV     P2,#0A2H
					   MOV     R0,#0FCH
					   MOV     R1,#05CH
					   ;判断第3个按键是否被按下
			 Sixth3:   JB      P3.2,Sixth4
					   MOV     P2,#0B0H
					   MOV     R0,#0FCH
					   MOV     R1,#0C1H
					   ;判断第4个按键是否被按下
			 Sixth4:   JB      P3.3,Sixth5
					   MOV     P2,#09CH
					   MOV     R0,#0FCH
					   MOV     R1,#0EFH
					   ;判断第5个按键是否被按下
			 Sixth5:   JB      P3.4,Sixth7
					   MOV     P2,#091H
					   MOV     R0,#0FDH
					   MOV     R1,#045H
					   ;判断第7个按键是否被按下
			 Sixth7:   JB      P3.6,Sixth8
					   MOV     P2,#0F8H
					   MOV     R0,#0FDH
					   MOV     R1,#0D0H
					   ;判断第8个按键是否被按下
			 Sixth8:   JB      P3.7,Sixth6
					   MOV     P2,#080H
					   MOV     R0,#0FDH
					   MOV     R1,#0EEH
			 SJMP    Sixth6
			 Disable6:   LJMP    Disable
			 RET

;扫描到按键7被按下
KEY7:			 		MOV     P2,#0F8H
						MOV     R0,#0FDH
						MOV     R1,#0D0H
						SETB    EA
						Seventh7:	JB      P3.6,Disable7
						;在第7个按键被按下的情况下判断其他按键是否被按下
					    ;判断第1个按键是否被按下
						JB      P3.0,Seventh2
						MOV     P2,#0FCH
						MOV     R0,#0FBH
						MOV     R1,#0E9H
						;判断第2个按键是否被按下
			 Seventh2:	JB      P3.1,Seventh3
						MOV     P2,#0A2H
						MOV     R0,#0FCH
						MOV     R1,#05CH
						;判断第3个按键是否被按下
			 Seventh3:	JB      P3.2,Seventh4
						MOV     P2,#0B0H
						MOV     R0,#0FCH
						MOV     R1,#0C1H
						;判断第4个按键是否被按下
			 Seventh4:	JB      P3.3,Seventh5
						MOV     P2,#09CH
						MOV     R0,#0FCH
						MOV     R1,#0EFH
						;判断第5个按键是否被按下
			 Seventh5:	JB      P3.4,Seventh6
						MOV     P2,#091H
						MOV     R0,#0FDH
						MOV     R1,#045H
						;判断第6个按键是否被按下
			 Seventh6:	JB      P3.5,Seventh8
						MOV     P2,#081H
						MOV     R0,#0FDH
						MOV     R1,#092H
						;判断第8个按键是否被按下
			 Seventh8:	JB      P3.7,Seventh7
						MOV     P2,#080H
						MOV     R0,#0FDH
						MOV     R1,#0EEH
			 SJMP    Seventh7
			 Disable7:	SJMP    Disable
			 RET

;扫描到按键8被按下
KEY8:		  	 		MOV     P2,#080H
						MOV     R0,#0FDH
						MOV     R1,#0EEH
						SETB    EA
			 Eighth8:	JB      P3.7,Disable8
						;在第8个按键被按下的情况下判断其他按键是否被按下
					    ;判断第1个按键是否被按下
						JB      P3.0,Eighth2
						MOV     P2,#0FCH
						MOV     R0,#0FBH
						MOV     R1,#0E9H
						;判断第2个按键是否被按下
			 Eighth2:	JB      P3.1,Eighth3
						MOV     P2,#0A2H
						MOV     R0,#0FCH
						MOV     R1,#05CH
						;判断第3个按键是否被按下
			 Eighth3:	JB      P3.2,Eighth4
						MOV     P2,#0B0H
						MOV     R0,#0FCH
						MOV     R1,#0C1H
						;判断第4个按键是否被按下
			 Eighth4:	JB      P3.3,Eighth5
						MOV     P2,#09CH
                        MOV     R0,#0FCH
						MOV     R1,#0EFH
						;判断第5个按键是否被按下
			 Eighth5:	JB      P3.4,Eighth6
						MOV     P2,#091H
						MOV     R0,#0FDH
						MOV     R1,#045H
						;判断第6个按键是否被按下
			 Eighth6:	JB      P3.5,Eighth7
						MOV     P2,#081H
						MOV     R0,#0FDH
						MOV     R1,#092H
						;判断第7个按键是否被按下
			 Eighth7:	JB      P3.6,Eighth8
						MOV     P2,#0F8H
						MOV     R0,#0FDH
						MOV     R1,#0D0H
			 SJMP    Eighth8
			 Disable8:	SJMP    Disable
			 RET

;没有按键被按下
None:		CLR     EA
			CLR     P1.4
			MOV     P2,#0FFH
            RET

;延时1s子程序
DELAY:      MOV    R7,#10    
            DL1:   MOV      R6,#150
            DL2:   MOV      R5,#200
            DJNZ   R5,$
            DJNZ   R6,DL2
            DJNZ   R7,DL1
            RET

;当按下的键松开时调用此函数
Disable:	MOV     P2,#0FFH  ;清除数码管的显示
			LCALL   DELAY	  ;调用延时函数,此时的中断仍然是打开的,即延时期间播放音调
			CLR     EA		  ;关闭中断
			CLR     P1.4	  ;断开声音
			RET	   

;中断服务程序
INQP:    	 MOV     TH0,R0
             MOV     TL0,R1
			 CPL     P1.4
			 RETI

END

点个赞,点个关注呀‎|•’-’•)و✧

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

#本文链接:https://blog.csdn.net/weixin_45617323/article/details/111569616

  • 17
    点赞
  • 62
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
51单片机电子琴是一种基于51单片机电子琴系统,采用C语言编程实现。其流程图如下所示: 1. 初始化:设置引脚模式、计时器、中断等,对相关寄存器进行初始化。 2. 获取按输入:通过轮询或中断方式获取按的输入状态。 3. 判断按:根据按状态判断按动作,如按下、长按、释放等。 4. 处理按事件:根据不同的按动作,进行相应的处理操作,如播放音符、改变音色、调节音量等。 5. 生成音频信号:通过DAC芯片将数字信号转换为模拟音频信号。可以通过PWM、PWM-DAC、R-2R网络等方式实现。 6. 播放音频:将音频信号输出到扬声器或耳机,实现声音的发声。 7. 循环播放:通过循环结构保持电子琴的运行,不断处理按事件和生成音频信号,实现连续的音乐播放。 而51单片机电子琴的原理图主要包括以下几个方面: 1. 按部分:包括按开关、按矩阵等,用于获取用户的输入。 2. 控制部分:包括51单片机、相关的外设(如定时器、中断控制器等),用于控制整个电子琴系统的运行。 3. 数字音频转换部分:包括DAC芯片,用于将数字音频信号转换为模拟音频信号。 4. 声音输出部分:包括扬声器或耳机,用于将模拟音频信号转换为声音输出。 通过连接这些模块,按输入经过处理后,最终通过扬声器或耳机发出声音,实现电子琴的功能。 总之,51单片机电子琴C语言流程图和原理图相互配合,通过对按输入的处理和音频信号的生成和输出,实现了电子琴的基本功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值