用51单片机中断编写的4x4键盘程序应用查询扫描编写键盘程序,由于要给按键去抖动,程序变得比较复杂和冗长(详见2013年9月29日博文《MSP430和AT89C51单片机4x4键盘C程序》),如果用中断编写,设置中断响应在下降沿时执行中断,则程序编写不用去抖动判断,所以相比较要简单很多!下面用汇编和C语言两种方式编写4X4键盘程序!一、汇编程序ORG 0000HLJMP MAINORG 0003hLjmp ZD0ORG 000BhLJMP TZD0ORG 0013hLjmp ZD1ORG 001BhLJMP TZD1ORG 0040H MAIN: Mov TMOD,#66hMOV TH0,#0ffhMOV TL0,#0ffhMOV TH1,#0ffhMOV TL1,#0ffhSETB EASETB ET0SETB TR0SETB ET1SETB TR1SETB IT0SETB IT1SETB EX0SETB EX1xh: mov P1,#0fehLcall Delaymov P1,#0fdhLcall Delaymov P1,#0fbhLcall Delaymov P1,#0f7hLcall DelaySJMP xhZD0: JNB P1.0,dat1JNB P1.1,dat2JNB P1.2,dat3JNB P1.3,dat4 dat1: mov P2,#06h ;1sjmp ZD0Rdat2: mov P2,#5bh ;2sjmp ZD0Rdat3: mov P2,#4fh ;3sjmp ZD0Rdat4: mov P2,#66h ;4ZD0R: retiZD1: JNB P1.0,dat5JNB P1.1,dat6JNB P1.2,dat7JNB P1.3,dat8dat5: mov P2,#6dh ;5 0110sjmp ZD1Rdat6: mov P2,#7dh ;6sjmp ZD1Rdat7: mov P2,#07h ;7sjmp ZD1Rdat8: mov P2,#7fh ;8ZD1R: retiTZD0: JNB P1.0,dat9JNB P1.1,dat0JNB P1.2,dat10JNB P1.3,dat11 dat9: mov P2,#6fh ;9sjmp ZD0Rdat0: mov P2,#3fh ;0sjmp ZD0Rdat10: mov P2,#77h ;Asjmp ZD0Rdat11: mov P2,#7ch ;BTZD0R:retiTZD1: JNB P1.0,dat12JNB P1.1,dat13JNB P1.2,dat14JNB P1.3,dat15 dat12: mov P2,#39h ;Csjmp TZD1Rdat13:mov P2,#5eh ;Dsjmp TZD1Rdat14:mov P2,#79h ;Esjmp TZD1Rdat15:mov P2,#71h ;FTZD1R:retiDelay:mov r7,#10ddjnz r7,$retend二、C语言程序(扫描P1)#include"reg51.h"intyu[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x 5e,0x79,0x71};int i,j,k,time,temp,dat;void delay(time){while(time--)for(i=0;i<120;i++);}void main(){P2=0x40;TMOD=0x66; //设定定时计数器T0、T1为方式2计数模式TH0=0xFF;TL0=0xFF;TH1=0xFF;TL1=0xFF;IE=0x8F; //开总中断和定时计数器两个中断,两个外中断IT0=1;IT1=1; //设置外中断为下降沿触发 TR0=1;TR1=1; //打开定时计数器开始计数 while(1){P1=0xfe;delay(1);P1=0xfd;delay(1);P1=0xfb;delay(1);P1=0xf7;delay(1);}}void intsvr0(void) interrupt 0 using 1 {temp=P1;switch(temp){case 0xfe:key=0;break;case 0xfd:key=1;break;case 0xfb:key=2;break;case 0xf7:key=3;break;default:break;}P2=yu[dat];}void timer0(void) interrupt 1 using 1 {temp=P1;if(temp==0xfe) dat=4;if(temp==0xfd) dat=5;if(temp==0xfb) dat=6;if(temp==0xf7) dat=7;P2=yu[dat];}void intsvr1(void) interrupt 2 using 1 {temp=P1;if(temp==0xfe) dat=8;if(temp==0xfd) dat=9;if(temp==0xfb) dat=10;if(temp==0xf7) dat=11;P2=yu[dat];}void timer1(void) interrupt 3 using 1{int dat;temp=P1;switch(temp){case 0xfe:key=12;break;case 0xfd:key=13;break;case 0xfb:key=14;break;case 0xf7:key=15;break;default:break;}P2=yu[dat];}/********************************************* ****************/三、C语言(扫描P3的P3.0、P3.1、P3.6、P3.7)从这个程序也可以看出51单片机I/O口没有方向性,输入输出都可读写,而且在一个寄存器中。
注意该程序对应电路图与上图的区别。
#include"reg51.h"sbit pp0=P3^0;sbit pp1=P3^1;sbit pp2=P3^6;sbit pp3=P3^7;intyu[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x 5e,0x79,0x71};int i,j,k,time,temp,dat;void delay(time){while(time--)for(i=0;i<120;i++);}void main(){P2=0x40;TMOD=0x66; //设定定时计数器T0、T1为方式2计数模式TH0=0xFF;TL0=0xFF;TH1=0xFF;TL1=0xFF;IE=0x8F; //开总中断和定时计数器两个中断,两个外中断IT0=1;IT1=1; //设置外中断为下降沿触发 TR0=1;TR1=1; //打开定时计数器开始计数 while(1){pp0=0;delay(5);pp0=1;pp1=0;delay(5);pp1=1;pp2=0;delay(5);pp2=1;pp3=0;delay(5);pp3=1;/*以上可用下列这段代替P3=0xfe;delay(5);P3=0xfd;delay(5);P3=0xbf;delay(5);P3=0x7f;delay(5);*/}}void intsvr0(void) interrupt 0 using 1 {temp=P3;switch(temp){case 0xfa:dat=0;break;case 0xf9:dat=1;break;case 0xbb:dat=2;break;case 0x7b:dat=3;break;default: break;}P2=yu[dat];}void timer0(void) interrupt 1 using 1 {temp=P3;if(temp==0xee) dat=8;if(temp==0xed) dat=9;if(temp==0xaf) dat=10;if(temp==0x6f) dat=11;P2=yu[dat];}void intsvr1(void) interrupt 2 using 3 {temp=P3;if(temp==0xf6) dat=4;if(temp==0xf5) dat=5;if(temp==0xb7) dat=6;if(temp==0x77) dat=7;P2=yu[dat];}void timer1(void) interrupt 3 using 1 {int dat;temp=P3;switch(temp){case 0xde:dat=12;break;case 0xdd:dat=13;break;case 0x9f:dat=14;break;case 0x5f:dat=15;break;default: break;}P2=yu[dat];}。