4个按键通过一个二极管与门电路接到891外部中断INT0或INT1连接

51单片机利用外部中断INT0和INT1实现编码器双向计数功能_百度知道君,已阅读到文档的结尾了呢~~
扫扫二维码,随身浏览文档
手机或平板扫扫即可继续访问
INT0及INT1中断计数.doc
举报该文档为侵权文档。
举报该文档含有违规或不良信息。
反馈该文档无法正常浏览。
举报该文档为重复文档。
推荐理由:
将文档分享至:
分享完整地址
文档地址:
粘贴到BBS或博客
flash地址:
支持嵌入FLASH地址的网站使用
html代码:
&embed src='/DocinViewer-4.swf' width='100%' height='600' type=application/x-shockwave-flash ALLOWFULLSCREEN='true' ALLOWSCRIPTACCESS='always'&&/embed&
450px*300px480px*400px650px*490px
支持嵌入HTML代码的网站使用
您的内容已经提交成功
您所提交的内容需要审核后才能发布,请您等待!
3秒自动关闭窗口查看: 5601|回复: 18
《KEY(按键)应用》大全
一种另类的键盘扩展方法
4×4矩阵式键盘识别技术(1)
4×4矩阵式键盘识别技术(2)
4×4矩阵式键盘识别技术(3)
平凡单片机教学——第二十四讲 键盘接口与编程
平凡单片机教学——第二十五讲 矩阵式键盘接口技术及编程
支持键盘双击事件的C程序设计
8条口线24按键的C51源程序
96个key的零延时采集
按键扫描驱动程序
键盘接口软件设计
CH451的LED驱动及8*8键盘驱动程序
8个IO接36个按键(没有用二极管)--键扫描程序
《一个按键的多次击键组合判别技巧》大话篇
《多个按键的连按处理技巧》大话篇
PC机键盘按键通码与ASCII对照表
单片机驱动标准PC机键盘的C51程序
一个比较通用的行列键盘程序(KEY.C)
一个比较通用的行列键盘程序(KEY .H)
支持键盘双击事件的C程序设计
Freescale H08C键盘中断子函数(c)
Freescale H08C键盘中断子函数的头文件&KB.h&(c)
来自网友 xwj 的 按键程序设计方法
20键PS2小键盘中断服务程序
The PC's keyboard.
设计中你是否遇到过这样的问题:你的产品上要求有几十个按键,处理器IO口很少,PCB的面积又有严格限制,或者你要严格控制成本,无法使用象7219那样的扩展芯片,怎么解决这个问题?
下面有个方法,大家都见过遥控器吧,上面不但有几十个按键,而且功能还挺多什么去抖动,同时按键处理都有了,最最重要的是控制芯片体积小,价格便宜(也就1,2块钱),外围器件少。。不过具体实现起来有点小麻烦,这类芯片的信号一般是PPM输出的,通常为了有更远的遥控距离,按键编码调制在一个38k左右的载波上。所以我们不得不再为这个方案多花上1块钱,加一个有烂运放做的低通滤波器,将载波滤除后在接到单片机的IO脚上,由于两个频率相差较多,这个滤波器并不难做。我使用LM324做的。其中有两级低通,一个比较器。
当你的示波器上出现一串可爱的几百赫兹的方波时,你的硬件就成功啦。既然只用一条IO就扩展了几十个按键,软件上自然会多费些事,此类芯片发码都是有引导头,同步部分,用户码,键码等部分组成,有三十多个位,具体可参照sc6121资料。下面时一个完整的接收程序,针对的芯片是sc6121,处理器89c51
///////////////////////////////////////////////////////////////////////////////
/*定时器1中断服务程序*/
每100us中断一次,定时检测HangSignal线上的电平状态,根据6121的砝码格式译出用户码键码.\\
ib_KeyCode[0] 用户码低位
,ib_KeyCode[1]用户码高位
,ib_KeyCode[2]键码
,ib_KeyCode[3]键码的反码
/////////////////////////////////////////////////////////////////////////////////////
void HandIn()&&interrupt 3 using 3 {
& &unsigned char tempbit=0;
& &Hbit=HandS& && && && && && && && && && && && && && && && && && &&&/*采样信号线*/
& &if (NewKey==FALSE){& && && && && && && && && && && && && && && && && &&&/*如果上一次按键事件已经北处理*/
switch (ib_HandState){& && && && && && && && && && && && && & /*根据接收状态散转*/
& &case LEAD:& && && && && && && && && && && && && && && && &/*引导头接收情况*/& && && && && && && && && && && && && && && &
& && && && && &if (Hbit){& && && && && && && && && && && && && && && & /*如果信号线是高电平*/&&
& && && && && &&&if ((ib_LowTime&MIN_LeadTime)&&(ib_LowTime&MAX_LeadTime)) /*判断低电平时间是否合乎要求*/
& && &ib_HandState=START;& && && && && && && && && && && & /*正确进入同步头接收状态*/
& && && && && &&&else ib_HandState=RESTART;& && && && && && && && && && &&&/*否则复位接收程序*/
& && &&&ib_LowTime=0;& && && && && && && && && && && && && && & /*清除低电平时间计数*/
& &else{& && && && && && && && && && && && && && && && & /*如果信号是低电平*/&&
& &&&ib_LowTime++;& && && && && && && && && && && && && &/*增加低电平时间计数器*/
if (ib_LowTime&MAX_LeadTime)& && && && && && && && &/*判断低电平时间是否超时*/
& && && && && &&&ib_HandState=RESTART;& && && && && && && && && && & /*是的话复位接收程序*/
& && && && && &
& && & case START:& && && && && && && && && && && && && && && &/*同步头接收情况*/
& && && && && &if(Hbit){& && && && && && && && && && && && && &&&/*如果信号线是高电平*/&&
& && &ib_HighTime++;& && && && && && && && && && && &&&/*高电平时间计数器加一*/
& && && && && && &if (ib_HighTime&MAX_SynTime)& && && && && && && &/*如果高电平时间超长,复位接收程序*/
& && && && && && &ib_HandState=RESTART;
& && && && && && & }
& && &else{& && && && && && && && && && && && && && &&&/*如果信号线是低电平*/
& && && && && && && && &if ((ib_HighTime&MIN_SynTime)&&(ib_HighTime&MAX_SynTime)) /*如果高电平时间合乎要求,将状态设定为数据为高电平检测*/
& && && && && && &&&ib_HandState=WAIT_HIGH;&&
& && && && && && &&&else ib_HandState=RESTART;& && && && && && && && && && & /*否则复位接收程序*/&&
& && && && && && && && &ib_HighTime=0;& &
& && && && && &
& &case WAIT_HIGH:&&/*等待数据位的上升沿的情况*/
& && && && && & if (Hbit){& && && && && && && && && && && && && && && && & /*如果检测到一个上升沿*/& && && && && && && &
& && && && && && && &if ((ib_LowTime&MIN_L_Time)&&(ib_LowTime&MAX_L_Time)) {&&/*如果低电平时间合乎要求,将状态设定为等待数据下降沿*/
& && && && && && && && &&&ib_HandState=WAIT_LOW;
& && && && && && && && & else ib_HandState=RESTART;& && && && && && && && && &/*否则复位接收程序*/
& &&&ib_LowTime=0;
else{& && && && && && && && && && && && && && && && &&&/*如果仍为低电平*/
&&ib_LowTime++;& && && && && && && && && && && && && & /*低电平时间计数器加一*/
&&if (ib_LowTime&MAX_L_Time)& && && && && && && && && &/*如果低电平时间超长,则复位寄售程序*/
& && && && && && && & ib_HandState=RESTART;
& &case WAIT_LOW:& && && && && && && && && && && && && & /*等待数据下降沿的情况*/& && && &&&
& && && && && &&&if (Hbit){& && && && && && && && && && && && && && &&&/*如果仍是高电平*/
& && && && && && && && &ib_HighTime++;& && && && && && && && && && && && && &&&/*高电平数据计数器加一*/&&
& && && && && && &&&if (ib_HighTime&MAX_H_Time)& && && && && && && && & /*如果高电平实际超长,则复位接收程序*/
& && && && && && &&&ib_HandState=RESTART;
else{& && && && && && && && && && && && && && && && & /*如果收到一个下降沿*/
& && && && && && &&&ib_KeyCode[ib_KeyPoint]&&=1;& && && && && && && && &&&/*接收数据字节右移一位*/
& && && && && && &&&if ((ib_HighTime&MIN_B1TIME)&&(ib_HighTime&MAX_B1TIME)) { /*如果高电平宽度符合逻辑1标准,接收字节高位置一*/
& && && && && && &&&ib_KeyCode[ib_KeyPoint]+=0x80;
& && && && && && && & ib_BitCount++;& && && && && && && && && && && && && && &/*接收数据位计数器加一*/
&&if (ib_BitCount&7) {& && && && && && && && && && && && &&&/*如果接收满一个字节*/
& &&&ib_BitCount=0;& && && && && && && && && && && && && && & /*清空位计数器*/
ib_KeyPoint++;& && && && && && && && && && && && && && &&&/*指向下一个字节*/
if (ib_KeyPoint&3)& && && && && && && && && && && && && &/*如果接收完整个数据*/
& && && &//
& &&&NewKey=TRUE;& && && && && && && && && && && && && && && && &&&/*置有新键按下标志*/
& &&&//for (i=0;i&4;i++){
& && & //TI=0;
& && & //SBUF=ib_KeyC
& && & //while(!TI);
& && & //TI=0;
& && && && && && && && && & //ib_HandState=RESTART;
& && && && && && && & ib_HighTime=0;& && && && && && && && && && && && && && && & /*将高电平时间计数器清零*/
&&ib_HandState=WAIT_HIGH;& && && && && && && && &/*设定系统为等待上升沿状态*/
& && && && && &&&
& && && &default:
& &if (ib_HandState==RESTART){& && && && && && && && && && && && && && && && && &/*如果程序处于复位状态*/
& && &ib_LowTime=0;& && && && && && && && && && && && && && && && && && && && && && & /*复位各项参数*/
& && &ib_HighTime=0;
& && &ib_HandState=LEAD;&&
&&ib_KeyCode[0]=0; ib_KeyCode[1]=0;
&&ib_KeyCode[2]=0; ib_KeyCode[3]=0;
&&ib_KeyPoint=0;
&&ib_BitCount=0;
& && &NewKey=FALSE;
好多遥控器(无线,红外)发射数据都是PPM调制的,以上程序稍微改动后可以应用于各种PPM调制信号的场合。
实验任务如图4.14.2所示,用AT89S51的并行口P1接4×4矩阵键盘,以P1.0-P1.3作输入线,以P1.4-P1.7作输出线;在数码管上显示每个按键的“0-F”序号。对应的按键的序号排列如图4.14.1所示
图4.14.12.
硬件电路原理图图4.14.23.
系统板上硬件连线(1.
把“单片机系统“区域中的P3.0-P3.7端口用8芯排线连接到“4X4行列式键盘”区域中的C1-C4 R1-R4端口上;(2.
把“单片机系统”区域中的P0.0/AD0-P0.7/AD7端口用8芯排线连接到“四路静态数码显示模块”区域中的任一个a-h端口上;要求:P0.0/AD0对应着a,P0.1/AD1对应着b,……,P0.7/AD7对应着h。4.
程序设计内容(1.
4×4矩阵键盘识别处理(2.
每个按键有它的行值和列值 ,行值和列值的组合就是识别这个按键的编码。矩阵的行线和列线分别通过两并行接口和CPU通信。每个按键的状态同样需变成数字量“0”和“1”,开关的一端(列线)通过电阻接VCC,而接地是通过程序输出数字“0”实现的。键盘处理程序的任务是:确定有无键按下,判断哪一个键按下,键的功能是什么;还要消除按键在闭合或断开时的抖动。两个并行口中,一个输出扫描码,使按键逐行动态接地,另一个并行口输入按键状态,由行扫描值和回馈信号共同形成键编码而识别按键,通过软件查表,查出该键的功能。5.
4×4矩阵式键盘识别技术(2)
5、汇编源程序
KEYBUFEQU 30HORG 00HSTART:MOV KEYBUF,#2WAIT:MOV P3,#0FFHCLR P3.4MOV A,P3ANL A,#0FHXRL A,#0FHJZ NOKEY1LCALL DELY10MSMOV A,P3ANL A,#0FHXRL A,#0FHJZ NOKEY1MOV A,P3ANL A,#0FHCJNE A,#0EH,NK1MOV KEYBUF,#0LJMP DK1NK1:CJNE A,#0DH,NK2MOV KEYBUF,#1LJMP DK1NK2:CJNE A,#0BH,NK3MOV KEYBUF,#2LJMP DK1NK3:CJNE A,#07H,NK4MOV KEYBUF,#3LJMP DK1NK4:NOPDK1:MOV A,KEYBUFMOV DPTR,#TABLEMOVC A,@A+DPTRMOV P0,A DK1A:MOV A,P3ANL A,#0FHXRL A,#0FHJNZ DK1ANOKEY1:MOV P3,#0FFHCLR P3.5MOV A,P3ANL A,#0FHXRL A,#0FHJZ NOKEY2LCALL DELY10MSMOV A,P3ANL A,#0FHXRL A,#0FHJZ NOKEY2MOV A,P3ANL A,#0FHCJNE A,#0EH,NK5MOV KEYBUF,#4LJMP DK2NK5:CJNE A,#0DH,NK6MOV KEYBUF,#5LJMP DK2NK6:CJNE A,#0BH,NK7MOV KEYBUF,#6LJMP DK2NK7:CJNE A,#07H,NK8MOV KEYBUF,#7LJMP DK2NK8:NOPDK2:MOV A,KEYBUFMOV DPTR,#TABLEMOVC A,@A+DPTRMOV P0,A DK2A:MOV A,P3ANL A,#0FHXRL A,#0FHJNZ DK2ANOKEY2:MOV P3,#0FFHCLR P3.6MOV A,P3ANL A,#0FHXRL A,#0FHJZ NOKEY3LCALL DELY10MSMOV A,P3ANL A,#0FHXRL A,#0FHJZ NOKEY3MOV A,P3ANL A,#0FHCJNE A,#0EH,NK9MOV KEYBUF,#8LJMP DK3NK9:CJNE A,#0DH,NK10MOV KEYBUF,#9LJMP DK3NK10:CJNE A,#0BH,NK11MOV KEYBUF,#10LJMP DK3NK11:CJNE A,#07H,NK12MOV KEYBUF,#11LJMP DK3NK12:NOPDK3:MOV A,KEYBUFMOV DPTR,#TABLEMOVC A,@A+DPTRMOV P0,A DK3A:MOV A,P3ANL A,#0FHXRL A,#0FHJNZ DK3ANOKEY3:MOV P3,#0FFHCLR P3.7MOV A,P3ANL A,#0FHXRL A,#0FHJZ NOKEY4LCALL DELY10MSMOV A,P3ANL A,#0FHXRL A,#0FHJZ NOKEY4MOV A,P3ANL A,#0FHCJNE A,#0EH,NK13MOV KEYBUF,#12LJMP DK4NK13:CJNE A,#0DH,NK14MOV KEYBUF,#13LJMP DK4NK14:CJNE A,#0BH,NK15MOV KEYBUF,#14LJMP DK4NK15:CJNE A,#07H,NK16MOV KEYBUF,#15LJMP DK4NK16:NOPDK4:MOV A,KEYBUFMOV DPTR,#TABLEMOVC A,@A+DPTRMOV P0,A DK4A:MOV A,P3ANL A,#0FHXRL A,#0FHJNZ DK4ANOKEY4:LJMP WAITDELY10MS:MOV R6,#10D1:MOV R7,#248DJNZ R7,$DJNZ R6,D1RETTABLE:DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07HDB 7FH,6FH,77H,7CH,39H,5EH,79H,71HEND
4×4矩阵式键盘识别技术(3)
6、C语言源程序
#include &AT89X51.H&unsigned char ID;void delay10ms(void){unsigned char i,j;for(i=20;i&0;i--)for(j=248;j&0;j--);} void delay02s(void){for(i=20;i&0;i--){delay10ms();}} void main(void){ while(1){ if(P3_7==0){delay10ms();if(P3_7==0){ID++;if(ID==4){ID=0;}while(P3_7==0);}}switch(ID){ case 0:P1_0=~P1_0;delay02s();case 1:P1_1=~P1_1;delay02s();case 2:P1_2=~P1_2;delay02s();case 3:P1_3=~P1_3;delay02s();}}}
平凡单片机教学 第二十四讲 键盘接口与编程键盘是由若干按键组成的开关矩阵,它是微型计算机最常用的输入设备,用户可以通过键盘向计算机输入指令、地址和数据。一般单片机系统中采和非编码键盘,非编码键盘是由软件来识别键盘上的闭合键,它具有结构简单,使用灵活等特点,因此被广泛应用于单片机系统。
按键开关的抖动问题
组成键盘的按键有触点式和非触点式两种,单片机中应用的一般是由机械触点构成的。在下图中,当开关S未被按下时,P1。0输入为高电平,S闭合后,P1。0输入为低电平。由于按键是机械触点,当机械触点断开、闭合时,会有抖动动,P1。0输入端的波形如图2所示。这种抖动对于人来说是感觉不到的,但对计算机来说,则是完全可以感应到的,因为计算机处理的速度是在微秒级,而机械抖动的时间至少是毫秒级,对计算机而言,这已是一个“漫长”的时间了。前面我们讲到中断时曾有个问题,就是说按键有时灵,有时不灵,其实就是这个原因,你只按了一次按键,可是计算机却已执行了多次中断的过程,如果执行的次数正好是奇数次,那么结果正如你所料,如果执行的次数是偶数次,那就不对了。图1 图2 为使CPU能正确地读出P1口的状态,对每一次按键只作一次响应,就必须考虑如何去除抖动,常用的去抖动的方法有两种:硬件方法和软件方法。单片机中常用软件法,因此,对于硬件方法我们不介绍。软件法其实很简单,就是在单片机获得P1。0口为低的信息后,不是立即认定S1已被按下,而是延时10毫秒或更长一些时间后再次检测P1。0口,如果仍为低,说明S1的确按下了,这实际上是避开了按键按下时的抖动时间。而在检测到按键释放后(P1。0为高)再延时5-10个毫秒,消除后沿的抖动,然后再对键值处理。不过一般情况下,我们通常不对按键释放的后沿进行处理,实践证明,也能满足一定的要求。当然,实际应用中,对按键的要求也是千差万别,要根据不同的需要来编制处理程序,但以上是消除键抖动的原则。2.键盘与单片机的连接 图3图41、通过1/0口连接。将每个按键的一端接到单片机的I/O口,另一端接地,这是最简单的方法,如图3所示是实验板上按键的接法,四个按键分别接到P3.2 、P3.3、P3.4和P3.5。对于这种键各程序可以采用不断查询的方法,功能就是:检测是否有键闭合,如有键闭合,则去除键抖动,判断键号并转入相应的键处理。下面给出一个例程。其功能很简单,四个键定义如下:
P3.2:开始,按此键则灯开始流动(由上而下)
P3.3:停止,按此键则停止流动,所有灯为暗
P3.4:上,按此键则灯由上向下流动
P3.5:下,按此键则灯由下向上流动
UpDown EQU 00H ;上下行标志
StartEnd EQU 01H ;起动及停止标志
LAMPCODE EQU 21H ;存放流动的数据代码
MOV SP,#5FH
MOV P1,#0FFH
CLR UpD启动时处于向上的状态
CLR StartE启动时处于停止状态
MOV LAMPCODE,#0FEH ;单灯流动的代码
ACALL KEY ;调用键盘程序
JNB F0,LNEXT ;如果无键按下,则继续
ACALL KEYPROC ;否则调用键盘处理程序
ACALL LAMP ;调用灯显示程序
AJMP LOOP ;反复循环,主程序到此结束
;---------------------------------------
MOV R7,#100
D1: MOV R6,#100
DJNZ R7,D1
;----------------------------------------延时程序,键盘处理中调用
MOV A,B ;从B寄存器中获取键值
JB ACC.2,KeyS分析键的代码,某位被按下,则该位为1(因为在键盘程序中已取反)
JB ACC.3,KeyOver
JB ACC.4,KeyUp
JB ACC.5,KeyDown
AJMP KEY_RET
SETB StartE第一个键按下后的处理
AJMP KEY_RET
CLR StartE第二个键按下后的处理
AJMP KEY_RET
KeyUp: SETB UpD第三个键按下后的处理
AJMP KEY_RET
CLR UpD第四个键按下后的处理
KEY_RET:RET
CLR F0 ;清F0,表示无键按下。
ORL P3,#B ;将P3口的接有键的四位置1
MOV A,P3 ;取P3的值
ORL A,#B ;将其余4位置1
CPL A ;取反
JZ K_RET ;如果为0则一定无键按下
ACALL DELAY ;否则延时去键抖
MOV B,A ;确实有键按下,将键值存入B中
SETB F0 ;设置有键按下的标志
ORL P3,#B ;此处循环等待键的释放
JZ K_RET1 ;直到读取的数据取反后为0说明键释放了,才从键盘处理程序中返回
AJMP K_RET
;-----------------------------------
D500MS: ;流水灯的延迟时间
MOV R7,#200
D51: MOV R6,#250
DJNZ R6,D52
DJNZ R7,D51
;-----------------------------------
JB StartEnd,LampS如果StartEnd=1,则启动
MOV P1,#0FFH
AJMP LAMPRET ;否则关闭所有显示,返回
LampStart:
JB UpDown,LAMPUP ;如果UpDown=1,则向上流动
MOV A,LAMPCODE
RL A ;实际就是左移位而已
MOV LAMPCODE,A
LCALL D500MS
AJMP LAMPRET
MOV A,LAMPCODE
RR A ;向下流动实际就是右移
MOV LAMPCODE,A
LCALL D500MS
END以上程序功能很简单,但它演示了一个键盘处理程序的基本思路,程序本身很简单,也不很实用,实际工作中还会有好多要考虑的因素,比如主循环每次都调用灯的循环程序,会造成按键反应“迟钝”,而如果一直按着键不放,则灯不会再流动,一直要到松开手为止,等等,大家可以仔细考虑一下这些问题,再想想有什么好的解决办法。2、采用中断方式:如图4所示。各个按键都接到一个与非上,当有任何一个按键按下时,都会使与门输出为低电平,从而引起单片机的中断,它的好处是不用在主程序中不断地循环查询,如果有键按下,单片机再去做相应的处理。
平凡单片机教学 第二十五讲 矩阵式键盘接口技术及编程1.矩阵式键盘接口技术及编程1.矩阵式键盘的结构与工作原理:
在键盘中按键数量较多时,为了减少I/O口的占用,通常将按键排列成矩阵形式,如图1所示。在矩阵式键盘中,每条水平线和垂直线在交叉处不直接连通,而是通过一个按键加以连接。这样,一个端口(如P1口)就可以构成4*4=16个按键,比之直接将端口线用于键盘多出了一倍,而且线数越多,区别越明显,比如再多加一条线就可以构成20键的键盘,而直接用端口线则只能多出一键(9键)。由此可见,在需要的键数比较多时,采用矩阵法来做键盘是合理的。矩阵式结构的键盘显然比直接法要复杂一些,识别也要复杂一些,上图中,列线通过电阻接正电源,并将行线所接的单片机的I/O口作为输出端,而列线所接的I/O口则作为输入。这样,当按键没有按下时,所有的输出端都是高电平,代表无键按下。行线输出是低电平,一旦有键按下,则输入线就会被拉低,这样,通过读入输入线的状态就可得知是否有键按下了。具体的识别及编程方法如下所述。2.矩阵式键盘的按键识别方法
确定矩阵式键盘上何键被按下介绍一种“行扫描法”。
行扫描法 行扫描法又称为逐行(或列)扫描查询法,是一种最常用的按键识别方法,如上图所示键盘,介绍过程如下。
1.判断键盘中有无键按下 将全部行线Y0-Y3置低电平,然后检测列线的状态。只要有一列的电平为低,则表示键盘中有键被按下,而且闭合的键位于低电平线与4根行线相交叉的4个按键之中。若所有列线均为高电平,则键盘中无键按下。
2.判断闭合键所在的位置 在确认有键按下后,即可进入确定具体闭合键的过程。其方法是:依次将行线置为低电平,即在置某根行线为低电平时,其它线为高电平。在确定某根行线位置为低电平后,再逐行检测各列线的电平状态。若某列为低,则该列线与置为低电平的行线交叉处的按键就是闭合的按键。下面给出一个具体的例子:
图仍如上所示。8031单片机的P1口用作键盘I/O口,键盘的列线接到P1口的低4位,键盘的行线接到P1口的高4位。列线P1.0-P1.3分别接有4个上拉电阻到正电源+5V,并把列线P1.0-P1.3设置为输入线,行线P1.4-P.17设置为输出线。4根行线和4根列线形成16个相交点。
1.检测当前是否有键被按下。检测的方法是P1.4-P1.7输出全“0”,读取P1.0-P1.3的状态,若P1.0-P1.3为全“1”,则无键闭合,否则有键闭合。
2.去除键抖动。当检测到有键按下后,延时一段时间再做下一步的检测判断。
3.若有键被按下,应识别出是哪一个键闭合。方法是对键盘的行线进行扫描。P1.4-P1.7按下述4种组合依次输出:
P1.7 1 1 1 0
P1.6 1 1 0 1
P1.5 1 0 1 1
P1.4 0 1 1 1
在每组行输出时读取P1.0-P1.3,若全为“1”,则表示为“0”这一行没有键闭合,否则有键闭合。由此得到闭合键的行值和列值,然后可采用计算法或查表法将闭合键的行值和列值转换成所定义的键值
4.为了保证键每闭合一次CPU仅作一次处理,必须却除键释放时的抖动。键盘扫描程序:
从以上分析得到键盘扫描程序的流程图如图2所示。程序如下SCAN: MOV P1,#0FH
ANL A,#0FH
CJNE A,#0FH,NEXT1
SJMP NEXT3
NEXT1: ACALL D20MS
MOV A,#0EFH
NEXT2: MOV R1,A
ANL A,#0FH
CJNE A,#0FH,KCODE;
NEXT3: MOV R0,#00H
KCODE: MOV B,#0FBH
NEXT4: RRC A
NEXT5: RRC A
NEXT6: MOV A,P1
ANL A,#0FH
CJNE A,#0FH,NEXT6
MOV R0,#0FFH
RET 键盘处理程序就作这么一个简单的介绍,实际上,键盘、显示处理是很复杂的,它往往占到一个应用程序的大部份代码,可见其重要性,但说到,这种复杂并不来自于单片机的本身,而是来自于操作者的习惯等等问题,因此,在编写键盘处理程序之前,最好先把它从逻辑上理清,然后用适当的算法表示出来,最后再去写代码,这样,才能快速有效地写好代码。
//键盘扫描处理,无按键返回0,有按键返回键值,键值对应于keycode[]下标值。8条(以P2为例)口线24按键
//键盘码也可定义为局部数组变量
unsigned char code keycode[]=
{0x00,0xee,0xde,0xbe,0xed,0xdd,0xbd,0xeb,0xdb,0xbb,0xd7,0xe7,0xb7,0x7b,0x7d,0x7e,0x77,
0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0x7f,0xbf};
unsigned char keyread(void)
{ unsigned char i,j,x,k1,k2;
if(P2!=0xff)
if(P2!=0xff)
{for(P2=0P2!=0P2=0xff)
//以上判断接地按键
//以下判断交叉按键(反转法)
if(P2!=0x0f)
if(P2!=0x0f)
if(P2!=0xf0)
for(P2=0xf0;P2!=0xf0;P2=0xf0)
else{x=0;} }
if(x==0){i=0;}
else{i=j=0
do{i++;j++;
if(keycode==x){j=24;}
else if(j==24){i=0;}else{;} }
while(j!=24);}
return(i);
void delay()//延时
for (b=0;b&=0b++)
for (b=0;b&=0b++)
8楼 Juliet 发表于
11:31:00   支持键盘双击事件的C程序设计!
/**********************************************************************************
& && && &KeyBoard Encode Program
& && && &This Program can encode press_key up to 128 and it can deal KB_DBClick Message
& && && &This is just a test proram and only use 2 key.If More Key need to Encode ,please
& && &modify the function:KBKeyPress()
& && && &This Porgram use Message_Driver method,the KB_Msg is used to record what KB_Msg has occured.
& && && &The meaning of 'SysKBMsg' is list as following.
& && && & Program Design:LiBaizhan
& && && && && && && &Ver:1.10
& && && && && && &&&Date:
************************************************************************************/
#include &reg51.h&
#include &intrins.h&
sbit&&Key1& && && && && & =& && && &&&P1^0;
sbit&&Key2& && && && && & =& && && &&&P1^1;
& & Some System Var Pre_Definition
& & Crystal Frequence is 11.0592MHz
#define& && &&&TIME_2MS& && && & 0X74
#define& && &&&TIME_20MS& && && &0X043B
#define& && &&&KB_INTERNAL& && & 3& && &&&/*Key DBClk Detection Internal */
& &SysKBMsg define Keyboard Message,it include Single_Click or Double_Click
& &It's bit6~bit0 record key_encode and bit 7 record DBClk(1) or SglClk(0)
& &It can record and encode up to 127(2^7-1) keys
& &No key is press when it is 0
& &This method did not deal key such as Ctrl_Key or Alt_Key or Shift_Key...etc.
& && && && && && && && && && && &/*_________________________________________________*/
data unsigned char SysKBMsg=0;& &/*|&&7&&|&&6&&|&&5&&|&&4&&|&&3&&|&&2&&|&&1&&|&&0&&|*/
& && && && && && && && && && && &/*| D/S | KB6 | KB5 | KB4 | KB3 | KB2 | KB1 | KB0 |*/
data unsigned char KBCounter=0;
bit&&KBCounterStart=0;
bit&&KBCounterStop=0;& && && && &/*if KeyBoard counter stop then this bit is 1*/
bit&&KBCounterFlag=0;& && && && &/*Current Counter is used by KeyBoard*/
void TimerInt0(void) interrupt 1& && & /*timer 0 interrupt use to record how long key is press*/
& &if(KBCounterFlag)& && && && & /*Current Counter is used by KeyBoard*/
& && &if(KBCounter&KB_INTERNAL)&&/*if DBClk Detection is not finish then detect continue*/
& && && &KBCounter++;
& && && &TR0=1;
& && &else
& && && &KBCounter=0;& && && && &/*DBClk Detection is finish*/
& && && &KBCounterStop=1;
& && && &void DelayMS(unsigned int dltime);
& && && &void Init51(void);
unsigned char KBKeyPress(void);& && &&&/*only return what key is press*/
& && && &void KBKeyEncode(void);& && & /*encode which key is pressed and DBClk or SglClk*/
& && && &void KBStartTimer(unsigned char CntH,unsigned char CntL);&&/*load counter initial value and start timer*/
& && && &void KBStopTimer(void);
& && && &void KBDealPressKey(void);& & /*deal key_press message*/
void main(void)
& &Init51();
& &while(1)
& && &KBKeyEncode();& && && && && & /*recored what KeyBoard Msg occure:which key is press and single clk or db clk*/
& && &KBDealPressKey();
& && &Delay Time is :(20+17*dl_time)*12/CrystalFrequence(us)
void DelayMS(unsigned int dltime)
& &for(i=0;i&i++);
void Init51(void)
& &SCON&&= 0x50;& && && && && && && & /* mode 1: 8-bit UART, enable receiver& &&&*/
& &TMOD&&= 0x21;& && && && && && && & /* timer 1 mode 2: 8-Bit reload& && && && &*/
& && && && && && && && && && && && &&&/* timer 0 mode 1: 16-bit Timer& && && && &*/
& &TH1& &= BAUD_4800;& && && && && &&&/* reload value 9600 baud& && && && && && &*/
& &TR1& &= 1;& && && && && && && && & /* timer 1 run& && && && && && && && && &&&*/
& &IE& & = 0X12;& && && && && && && & /* enable Serial INT,Timer0 INT& && && && &*/
& &ES& & = 0;& && && && && && && && & /* disable Serial INT*/
& &EA& & = 1;& && && && && && && && & /* Open INT Ctrl& && && && && && && && && &*/
void KBKeyEncode(void)
& &data unsigned char CurrPress=0,LastPress=0;
& &if((LastPress=KBKeyPress())!=0)& && && && &&&/*if some key is press then start encode*/
& && &KBStartTimer(0,0);& && && && && && && && &/*some key is press then start DBClk Detection Counter*/
& && &SysKBMsg=LastP& && && && && && && & /*record the key that is pressed this time*/
& && &while(!KBCounterStop)
& && && &if((CurrPress=KBKeyPress())!=0X0)& && &/*if some key is pressed during DBClk Detection then jump out to see wether DBclk is occured*/
& && && && &
& && &if((KBCounterStop==0)&&(LastPress==CurrPress))& && && && &/*this key DBClk occured*/
& && && &SysKBMsg|=0X80;
& && &KBStopTimer();
unsigned char KBKeyPress(void)
& &data unsigned char KeyPress=0;
& &if((P1&0X03)!=0X03)
& && &DelayMS(TIME_20MS);
& && &if((KeyPress=(P1&0X03))!=0X03)& && && &/*some key is press*/
& && && &if(KBCounterStart)
& && && && &TR0=0;
& && && &while((P1&0X03)!=0X03);& && && && & /*wait until key is free*/
& && && &DelayMS(TIME_20MS);
& && && &if(KBCounterStart)
& && && && &TR0=1;
& && &else& && && && &&&/*Key is not real press*/
& && && &KeyPress=0;
& &return KeyP
void KBStartTimer(unsigned char CntH,unsigned char CntL)
& &TH0=CntH;
& &TR0=1;& && && && && && && && && &/*Start Counter*/
& &TL0=CntL;
& &KBCounterFlag=1;& && && && && &&&/*this counter is used by KeyBoard*/
& &KBCounterStart=1;
& &KBCounterStop=0;
void KBStopTimer(void)
& &KBCounter=0;
& &KBCounterFlag=0;
& &KBCounterStart=0;
void KBDealPressKey(void)
& &data unsigned char tmp=0;
& &switch(SysKBMsg)& && &&&/*here is just a test program,test to deal Sgl_Clk and DB_Clk Msg*/
& && &case&&0X01:& && & tmp=0X01;
& && &case&&0X02:& && & tmp=0X02;
& && &case&&0X81:& && & tmp=0X81;
& && &case&&0X82:& && & tmp=0X82;
& && &default& &:& && &
& &SysKBMsg=0;& && && && && && && && && && && &/*this key msg has been done*/
96个key的零延时采集
HotPower 发表于
18:04 侃单片机 ←返回版面& &
;-------96键演示程序-------------------------
;这是1个回复题中的应用示例,已通过软仿真“验证”
;这只是键扫描技术的1个“缩影”,方法实在太多.
;有“难看之处”,敬请高手们批评指教.
;HotPower将虚心接受,坚决改正.重新做人.
;发表目的: 在21IC中壮大游击队.
;----------------------------------------------------
;由于2051资源问题,本程序只取多任务键盘的压放键2个事件
;废除长压键(压键1段时间后才激活)事件
;废除长放键(放键1段时间后才激活)事件
;废除双击键事件
;废除任意组合键事件
;----------常数定义------------------------------
TIME208US&&EQU -208;20mS/96=208uS
TIME50MS& &EQU -uS
;KEYCOUNT& &EQU& &1;键盘键个数(软仿真时用)
;------------------------------------------------
KEYCOUNT& &EQU& &96;键盘键个数(实际应用)
;----------RAM地址定义----------------------------
;--------96键键状态标志位数组Bits[12*8位]--------
KEYBUFF1& &DATA&&08H;08H~13H(12个字节96位)对应96键
;--------96键键跳变标志位数组Bits[12*8位]--------
KEYBUFF2& &DATA&&14H;14H~1FH(12个字节96位)对应96键
;------------------------------------------------
KEYNUM& &&&DATA&&30H;
HotPower_55H& && &DATA& &6EH
HotPower_AAH& && &DATA& &6FH
;---------------------------------------
SP_MIN& && & DATA HotPower_AAH
;-------主程序开始----------------------
& & ORG& &0000H
& & LJMP&&MAINSTART;主程序开始
& & ORG& &0003H
;-------掉电保护中断INT0服务程序--------
INT0_INTADDR:
& & ORG& &000BH
;-------定时器T0中断服务程序------------
;工作在8位自动装载方式,每208uS中断一次
T0_INTADDR:
& & LJMP&&T0INTPROC;定时器T0中断服务程序
& & ORG& &0013H
;-------外部中断INT1服务程序------------
INT1_INTADDR:
& & ORG& &001BH
;-------定时器T1中断服务程序------------
T1_INTADDR:
& & LJMP&&T1INTPROC;定时器T1中断服务程序
;& & ORG& &0023H
;-------串行中断服务程序----------------
;SINT_INTADDR:
;-------------------------------------------
;& & ORG& &002BH
;-------定时器T2中断服务程序------------
;& & LJMP&&T2INTPROC;执行中断服务程序
;-------执行键盘命令----------------------
;本程序利用散转回收技术(指针函数)
;它的最大优点是散转处的子程序可被它用(函数)
;它比JMP @A+DPTR指令要“游击”很多,灵活和隐蔽了许多
;它在对付“反汇编”方面,比JMP @A+DPTR更“坏”
;HotPower打死也不用JMP @A+DPTR
;入口:&&DPTR散转地址表
;& && & ACC 散转号
& & CJNE&&A,#KEYCOUNT,$+3
& & JNC& &KEYPROC_EXIT;非法键(96~255)防止程序飞,不散转
& & RL& & A;*2;地址需要2字节(像ARM的大端模式)
& & ADD& &A,DPL
& & MOV& &DPL,A
& & CLR& &A
& & ADDC&&A,DPH
& & MOV& &DPH,A
& & MOV& &A,#01H;低8位
& & MOVC&&A,@A+DPTR;取低8位地址
& && &&&PUSH&&ACC;压入事件处理低8位地址
& && &&&CLR& &A;高8位
& & MOVC&&A,@A+DPTR;取高8位地址
& && &&&PUSH&&ACC;压入事件处理高8位地址
KEYPROC_EXIT:
& & RET;执行键盘命令(散转JMP @A+DPTR)
;-------压键事件处理地址表--------------------
KEYJMPPROCTAB:
& & DW& & KEYPROC0;0键压键
& & DW& & KEYPROC1
& & DW& & KEYPROC2
;............................
& & DW& & KEYPROC95;95键压键
;-------放键事件处理地址表--------------------
KEYJMPPROCTABX:
& & DW& & KEYPROC0X;0键放键
& & DW& & KEYPROC1X
& & DW& & KEYPROC2X
;............................
& & DW& & KEYPROC95X;95键放键
MAINSTART:
;-------P0口初始化------------------
& & MOV& &P0,#B
;-------P1口初始化------------------
& & MOV& &P1,#B
;-------P2口初始化------------------
& & MOV& &P2,#B
;-------P3口初始化------------------
& & MOV& &P3,#B
;--------------------------------
& & MOV& &IE,#B;EA=0,ES=ET2=ET1=EX1=ET0=EX0=0
& & MOV& &SP,#SP_MIN;
& && && & MOV& &PSW,#B;RS1RS0=00,R0~R7=00H~07H
& & MOV& &A,#LOW(MAINNEXT)
& & PUSH&&ACC
& & MOV& &A,#HIGH(MAINNEXT)
& & PUSH&&ACC
& & LCALL MAININIT;系统初始化
& && &&&MOV& &IE,#B;开中断
;-------主循环-------------------------------
& & ORL& &PCON,#B;待机
& & SJMP&&MAINLOOP;死循环
& & MOV& &A,#LOW(MAINPROC)
& & PUSH&&ACC
& & MOV& &A,#HIGH(MAINPROC)
& & PUSH&&ACC
;-------主程序初始化------------------------
;-------接口初始化--------------------------
;-------内存初始化-------------------------
& & MOV& &A,HotPower_55H
& & XRL& &A,HotPower_AAH
& & CPL& &A
& & JZ& & MAININITNEXT;内存未破坏
& & MOV& &HotPower_55H,#055H
& & MOV& &HotPower_AAH,#0AAH
& & LCALL SYSTEMINIT;系统初始化
MAININITNEXT:
;-------运行初始化---------------
& & LCALL SYSTEMSETUP;系统设置
SYSTEMINIT:
& & LCALL KEYBUFFINIT
SYSTEMSETUP:
;-------系统主频12MHz---------------------------------
;& & MOV& &IP,#B;中断优先级EX0&ET2&ET0&EX1&ES
& &&&MOV& &TMOD,#B;T1=MODE1(16位定时器),T0=MODE2(8位定时器)
& & MOV& &TCON,#B;启动定时器TR1EQUTR0EQU1,IT1EQUIT0EQU1
;------------------------------------------------------
& & MOV& &TL0,#TIME208US;设置定时器0时间常数
& & MOV& &TH0,#TIME208US;设置定时器0时间常数
;------------------------------------------------------
;& & MOV& &TL1,#LOW(TIMEXMS);设置定时器1时间常数
;& & MOV& &TH1,#HIGH(TIMEXMS)
KEYBUFFINIT:
& & MOV& &KEYNUM,#00H
& & MOV& &R0,#KEYBUFF1
KEYBUFFINITLOOP:
& & MOV& &@R0,#00H
& & INC& &R0
& & CJNE&&R0,#KEYBUFF2+12,KEYBUFFINITLOOP
;---------------------------------------------
;T0每中断1次,将进行1次键&扫描&
& & LCALL TESTKEY;键盘测试(不扫但描)
;-------键盘软仿真测试点-----------------
;在此& &A=0 无键压下,A&&0有键压下
;若调试n个键,需将KEYCOUNT设置为n.(KEYCOUNT=1~96)
;----------------------------------------
& & JNZ& &INKEY1;有键压下
;-------无键压下------------------------
& & LCALL GETKEYBIT;取键状态
& & JZ& & INKEY01;键状态未发生变化
& && &&&LCALL CLRKEYBIT;设置放键标志
& & LCALL SETKEYBITK;设置跳变标志(防止放键抖动)
& & LCALL GETKEYBITK;取键跳变标志
& & JZ& & INKEY02;键未发生跳变(防止2次事件处理)
& & LCALL CLRKEYBITX;设置重入标志
& && &&&MOV& &A,KEYNUM;取键号
& && &&&MOV& &DPTR,#KEYJMPPROCTABX;键盘放键事件处理表
& & LCALL KEYPROC;执行键盘放键事件处理
;-------有键压下------------------------
& & LCALL GETKEYBIT;取键状态
& & JNZ& &INKEY11;键状态未发生变化(防止2次事件处理)
& && &&&LCALL SETKEYBIT;设置压键标志
& & LCALL SETKEYBITK;设置跳变标志(防止压键抖动)
& & LCALL GETKEYBITK;取键跳变标志
& & JZ& & INKEY12;键未发生跳变
& & LCALL CLRKEYBITX;设置重入标志
& && &&&MOV& &A,KEYNUM;取键号
& && &&&MOV& &DPTR,#KEYJMPPROCTAB;键盘压键事件处理表
& & LCALL KEYPROC;执行键盘压键事件处理
GETKEYBITK:
& & MOV& &A,R0
& & ADD& &A,#12
& & MOV& &R0,A
& & SJMP&&GETKEYBITX
GETKEYBIT:
& & LCALL GETKEYBITADDR
& & LCALL GETKEYBITVAL
GETKEYBITX:
& & MOV& &A,@R0
& && &&&ANL& &A,B
SETKEYBITK:
& & MOV& &A,R0
& & ADD& &A,#12
& & MOV& &R0,A
& & SJMP&&SETKEYBITX
SETKEYBIT:
& & LCALL GETKEYBITADDR
& & LCALL GETKEYBITVAL
SETKEYBITX:
& & MOV& &A,@R0
& && &&&ORL& &A,B
& & MOV& &@R0,A
CLRKEYBITK:
& & MOV& &A,R0
& & ADD& &A,#12
& & MOV& &R0,A
& & SJMP&&CLRKEYBITX
CLRKEYBIT:
& & LCALL GETKEYBITADDR
& & LCALL GETKEYBITVAL
CLRKEYBITX:
& & MOV& &A,@R0
& & XRL& &B,#0FFH;取反B
& && &&&ANL& &A,B
& & XRL& &B,#0FFH;还原B
& & MOV& &@R0,A
;-----------------------------------
;CPLKEYBITK:
;& & MOV& &A,R0
;& & ADD& &A,#12
;& & MOV& &R0,A
;& & SJMP&&CPLKEYBITX
;CPLKEYBIT:
;& & LCALL GETKEYBITADDR
;& & LCALL GETKEYBITVAL
;CPLKEYBITX:
;& & MOV& &A,@R0
;& && &&&XRL& &A,B
;& & MOV& &@R0,A
;---------------------------------------------
GETKEYBITVAL:
& & MOV& &A,KEYNUM
& & ANL& &A,#07H
& & ADD& &A,#GETKEYBITTAB-GETKEYBITTABOFF
& & MOVC&&A,@A+PC
GETKEYBITTABOFF:
& & MOV& &B,A
GETKEYBITTAB:
& & DB& & B
& & DB& & B
& & DB& & B
& & DB& & B
& & DB& & B
& & DB& & B
& & DB& & B
& & DB& & B
;----------------------------------------------
GETKEYBITADDR:
& & MOV& &A,KEYNUM
& & ANL& &A,#B
& & RR& & A
& & RR& & A
& & RR& & A
& & ADD& &A,#KEYBUFF1
& & MOV& &R0,A
;-------键测试子程序--------------------------
;键号KEYNUM=000 11B(0~95)
;入口& &无
;出口& &ACC==0 无键压下(键号KEYNUM)
;& && & ACC&&0 有键压下(键号KEYNUM)
& & MOV& &A,KEYNUM;取键号
& & ANL& &A,#0FH;取行号(键号低4位)
& & ANL& &P3,#0F0H;清行信号
& & ORL& &P3,A;发送行扫描信号DCBA;P3.3~P3.0
& & MOV& &A,KEYNUM;取键号
& & ANL& &A,#B;取列号(键号高3位)
& & SWAP&&A;变换到低3位
& & ADD& &A,#TESTKEYTAB-TESTKEYTABOFF;得到表地址
& && &&&MOVC&&A,@A+PC;取列表值
TESTKEYTABOFF:
& & JZ& & TESTKEYEXIT;6,7非法列,认为无键压下
& & PUSH&&B;保护现场
& & MOV& &B,A;暂存
& & ANL& &A,P1;接收列值P1.7~P1.2,有键压下为0
& & XRL& &A,B;有键压下非0
& & POP& &B;恢复现场
TESTKEYEXIT:
TESTKEYTAB:
& & DB& & 列
& & DB& & 列
& & DB& & 列
& & DB& & 列
& & DB& & 列
& & DB& & 列
& & DB& & 列非法
& & DB& & 列非法
;-------定时器T0中断服务程序--------------------
;每个键20mS扫描1次,并自动进行压键或放键消抖处理
;这是1个大规模(96键)的键盘游击战的非典战例
;1.不需键扫描.(T0中断的次序即为键扫描号)
;2.不需键消抖.(在T0中断96次后自动消抖)
;3.压键放键事件分离(散转回收技术)
;4.用户事件&并行处理&(mS级分时)
T0INTPROC:
& & PUSH&&PSW
& & PUSH&&ACC
& & PUSH&&B
& & PUSH&&DPL
& & PUSH&&DPH
T0INTPROC_START:
& & LCALL INKEY;键扫描并执行压放键事件处理
& & INC& &KEYNUM;准备下一键号(T0中断计数)
& & MOV& &A,KEYNUM
& & CJNE&&A,#KEYCOUNT,T0INTPROC_EXIT
& & MOV& &KEYNUM,#00H;开始下1轮键扫描
T0INTPROC_EXIT:
& & POP& &DPH
& & POP& &DPL
& & POP& &B
& & POP& &ACC
& & POP& &PSW
;-------定时器T1中断服务程序------------
T1INTPROC:
;-------0键压键事件处理---------------------
;在此添加用户压键事件
;-------1键压键事件处理---------------------
;在此添加用户压键事件
;-------2键压键事件处理---------------------
;在此添加用户压键事件
;-------95键压键事件处理---------------------
KEYPROC95:
;在此添加用户压键事件
;-------0键放键事件处理---------------------
KEYPROC0X:
;在此添加用户放键事件
;-------1键放键事件处理---------------------
KEYPROC1X:
;在此添加用户放键事件
;-------2键放键事件处理---------------------
KEYPROC2X:
;在此添加用户放键事件
;-------95键放键事件处理---------------------
KEYPROC95X:
;在此添加用户放键事件
;-------全部程序结束--------------------------------------
按键扫描驱动程序
//按键扫描驱动程序
unsigned char key,key_h,
unsigned int key_l;
//按键连接到p1.0、p1.1、p1.2
void int_t0(void) interrupt 1 {
unsigned char dd,i;
TL0=TL0+30;TH0=0 //800
/* 按键判别 */
if ((P1&0x7)==0x7) {
&&if ((key_l&30)&&(key_l&800)&&(key_h&30)) {&&//释放按键,如果之前按键时间少于1秒,读入键值
&&if ((++key_h)&200) key_h=200;
&&key_l=0;
&&if (key&=0x80) key=0;& && & //如果之前的按键为长按1秒,清除键值
&&kpush=P1&0x7;
&&key_l++;
&&if ((key_l&800)&&(key_h&30)) {& &&&//如果按键超过1秒,键值加0x80标志长按键
& &key=kpush|0x80;
& &key_h=0;
& &key_l=0;
void main(void) {
TMOD=0x1;TR0=1;ET0=1;EA=1;
while (1) {
&&while (!key) {}
&&switch (key) {
键盘接口软件设计
软件设计要考虑以下3部分内容:键盘缓冲区的设置;初始化程序;中断服务程序。
& & 1、键盘缓冲区
& & 键盘缓冲区地址为:30H-4FH,共32个字节。使用R1作为缓冲区放数指针,R7为取数指针。缓冲区为环形。放满后将R1置为30H,再从头放数;当放数指针追上取数指针时,停止放数。当取数指针追上放数指针时,停止取数。
& & 2、初始化程序
& & 包括8052的初始化和键盘的初始化。程序清单如下:
& && &&&MOV IE,#0H& && && && &;关中断
& && &&&CLR F0& && && && && & ;F0=0为类型1键盘;F0=1为类型2键盘
& && &&&MOV R0,#0H
& && &&&MOV R1,#30H& && && &&&;置缓冲区放数指针起始值
& && &&&MOV R2,#0H
& && &&&MOV R3,#0H
& && &&&MOV R4,#0H
& && &&&MOV R5,#0H
& && &&&MOV R6,#0H
& && &&&MOV R7,#2FH& && && &&&;置缓冲区取数指针起始值
& && &&&MOV B,#0H
& && &&&MOV TCON,#0H& && && & ;置INT0为电平触发方式
KEYINT:& && && && && && && &&&;主中断服务程序
& && &&&MOV IE,#0H& && && && &;关中断
& && &&&MOV A,R7& && && && &&&;取数指针放到A
& && &&&XRL A,R1& && && && &&&;与放数指针比较
& && &&&JZ KL4& && && && && & ;放数指针=取数指针则退出
& && &&&INC R0& && && && && & ;脉冲计数
KL1:& & JNB P3.2,KL1& && && & ;等待时钟脉冲为“1”
& && &&&CJNE R0,#01H,K12& && &;首次收到脉冲则判断键盘类型
& && &&&MOV C,P1.0
& && &&&KL2:JB F0,KL3& && && &;根据F0的值转不同服务程序
& && &&&MOV F0,C& && && && &&&;保存键盘类型
& && &&&MOV C,P1.0& && && && &;采用数据
& && &&&LCALL INTB& && && && &;类型2键盘中断服务程序
& && &&&MOV IE,#81H& && && &&&;开中断
& && &&&RETI
KL3:& & MOV C,P1.0& && && && &;采样数据
& && &&&LCALL INTA& && && && &;类型1键盘中断服务程序
KL4:& & MOV IE,#81H& && && &&&;开中断
& && &&&RETI
& & 限于篇幅,以下公列出类型1键盘中断服务子程序的处理程序,类型2键盘中断服务子程序除需要进行奇校验及计数脉冲个数不同外,流程基本一致。
& & 类型1键盘中断服务子程序:
& && &&&MOV A,R2& && && && &&&;数据位移入R2和R3中
& && &&&RRC A
& && &&&MOV R2,A
& && &&&MOV A,R3
& && &&&RRC A
& && &&&MOV R3,A
& && &&&CJNE R0,#0AH,INTA1& & ;计数脉冲不为10退出,否则转换
& && &&&CLR C
& && &&&MOV A,R3
& && &&&RLC A
& && &&&MOV A,R2
& && &&&RLC A
& && &&&MOV R5,A& && && && &&&;数据存入R5
& && &&&ANL A,#80H
& && &&&JNZ INTA3& && && && & ;是否为放键码,是则退出
& && &&&MOV A,R5
& && &&&MOV DPTR,#1000H& && & ;1000H为码表转换区起址
& && &&&MOVC A,@A+DPTR& && &&&;扫描码转换为ASCII码
& && &&&MOV @R1,A& && && && & ;ASCII码存入键盘缓冲区
& && &&&INC R1
& && &&&CJNE R1,#50H,INTA3
& && &&&MOV R1,#30H& && && &&&;缓冲区满则R1=30H
INTA3:&&CJNE R7,#2FH,INT4
& && &&&MOV R7,#30H
INTA4:&&MOV R0,#0H& && && && &;脉冲计数清零
& && &&&MOV R5,#0H
INTA2:&&MOV R2,#0H
& && &&&MOV R3,#0H
INTA1:&&RET
& && &&&ORG 1000H& && && && & ;码表转换区
& && &&&ORG 1002H& && && && & ;这里仅列出0-9的转换表
& && &&&DB 31H,32H,33H,34H,35H,36H,37H,38H,39H,30H
// AT89C51 C语言程序
//Web:http//
//Author: yhw&&2003.7
#define CH451_RESET& &&&0x0201& && && && && && && && && &//复位
#define CH451_LEFTMOV& &0x0300& && && && & //设置移动方式-作移
#define CH451_LEFTCYC& &0x0301& && && && & //设置移动方式-左循
#define CH451_RIGHTMOV&&0x0302& && && && & //设置移动方式-右移
#define CH451_RIGHTCYC&&0x0303& && && && & //设置移动方式-右循
#define CH451_SYSOFF& & 0x0400& && && && && && && & //关显示、键盘、看门狗
#define CH451_SYSON1& & 0x0401& && && && && && && & //开显示
#define CH451_SYSON2& & 0x0403& && && && && && && & //开显示、键盘
#define CH451_SYSON3& & 0x0407& && && && && && && & //开显示、键盘、看门狗功能
#define CH451_DSP& && & 0x0500& && && && && && && & //设置默认显示方式
#define CH451_BCD& && & 0x0580& && && && && && && & //设置BCD译码方式
#define CH451_TWINKLE& &0x0600& && && && & //设置闪烁控制
#define CH451_DIG0& && &0x0800& && && && && && && & //数码管位0显示
#define CH451_DIG1& && &0x0900& && && && & //数码管位1显示
#define CH451_DIG2& && &0x0a00& && && && & //数码管位2显示
#define CH451_DIG3& && &0x0b00& && && && & //数码管位3显示
#define CH451_DIG4& && &0x0c00& && && && & //数码管位4显示
#define CH451_DIG5& && &0x0d00& && && && && && && &//数码管位5显示
#define CH451_DIG6& && &0x0e00& && && && && && && &//数码管位6显示
#define CH451_DIG7& && &0x0f00& && && && & //数码管位7显示
//须主程序定义的参数
// sbit ch451_dclk=P1^7;& && && && && && && && && & //串行数据时钟上升延激活
// sbit ch451_din=P1^6;& && && && && && && &// 串行数据输出,接CH451的数据输入
// sbit ch451_load=P1^5;& && && && && && && && && & //串行命令加载,上升延激活
// sbit ch451_dout=P3^3;& && && && && && && && && && &//INT1,键盘中断和键值数据输入,接CH451的数据输出
// uchar&&ch451_& && && && && && && &// 存放键盘中断中读取的键值
//********************************************
//初始化子程序
void ch451_init()
&&ch451_din=0;& && && && && && && && && && && && & //先低后高,选择4线输入
&&ch451_din=1;
#ifdef USE_KEY
&&IT1=0;& && && && && && & //设置下降沿触发
&&IE1=0;& && && && && && & //清中断标志
&&PX1=0;& && && && && && & //设置低优先级
&&EX1=1;& && && && && && & //开中断
//*****************************************************
//输出命令子程序
//定义一无符号整型变量存储12字节的命令字。
void ch451_write(unsigned int command)
#ifdef USE_KEY
&&EX1=0;& && && && && && &//禁止键盘中断
&&ch451_load=0;& && && && && && && && && && && & //命令开始& && &
&&for(i=0;i&12;i++){& && && && && && && && && &&&//送入12位数据,低位在前
& & ch451_din=command&1;
& & ch451_dclk=0;
& & command&&=1;
& & ch451_dclk=1;& && && && && && && && && && & //上升沿有效
&&ch451_load=1;& && && && && && && && && && && &//加载数据
#ifdef USE_KEY
#ifdef USE_KEY
//*************************************************
//输入命令子程序,MCU从451读一字节
unsigned char ch451_read()
&&unsigned char command, //定义命令字,和数据存储器
&&EX1=0;& && && && && & //关中段
&&command=0x07;& && && && && & //输入读451命令字
&&ch451_load=0;
&&for(i=0;i&4;i++){
& & ch451_din=command&1;& && & //送入最低位
& & ch451_dclk=0;&&
& & command&&=1;& && & //往右移一位
& & ch451_dclk=1;& && & //产生时钟上升沿锁通知CH451输入位数据
&&ch451_load=1;& && & //产生加载上升沿通知CH451处理命令数据
&&keycode=0;& && & //清除keycode
&&for(i=0;i&7;i++){
& & keycode&&=1;& && & //数据移入keycode,高位在前,低位在后
& & keycode|=ch451_& && & //从高到低读入451的数据
& & ch451_dclk=0;& && & //产生时钟下升沿通知CH451输出下一位
& & ch451_dclk=1;
&&IE1=0;& && & //清中断标志
&&return(keycode);& && &//反回键值
//*************************************************
//中断子程序&&使用中断2,寄存器组1
void ch451_inter() interrupt 2 using 1
&&& && & //定义循环变量
&&unsigned char command,& && & //定义控制字寄存器,和中间变量定时器
&&command=0x07;& && & //读取键值命令的高4位0111B
&&ch451_load=0;& && & //命令开始
&&for(i=0;i&4;i++){
& & ch451_din=command&1;& && &//低位在前,高位在后
& & ch451_dclk=0;
& & command&&=1;& && &//右移一位
& & ch451_dclk=1;& && &//产生时钟上升沿锁通知CH451输入位数据
&&ch451_load=1;& && &//产生加载上升沿通知CH451处理命令数据
&&keycode=0;& && &//清除keycode
&&for(i=0;i&7;i++){
& & keycode&&=1;& && &//数据作移一位,高位在前,低位在后
& & keycode|=ch451_& && &//从高到低读入451的数据
& & ch451_dclk=0;& && &//产生时钟下升沿通知CH451输出下一位
& & ch451_dclk=1;
&&ch451_key=& &&&//保存上次的键值
&&IE1=0;& &&&//清中断标志
//***********************************************
8个IO接36个按键(没有用二极管)--键扫描程序
备注: 这张图是由网友fsaok提供的.
HotPower 发表于
20:30 侃单片机 ←返回版面 举报该贴
#include &REG52.h&//不知为何发帖不能用尖括弧?????
#include &intrins.h&//不知为何发帖不能用尖括弧?????
sbit Row0 = P1^0;
sbit Row1 = P1^1;
sbit Row2 = P1^2;
sbit Row3 = P1^3;
sbit Col0 = P1^4;
sbit Col1 = P1^5;
sbit Col2 = P1^6;
sbit Col3 = P1^7;
unsigned char KeyScan(void);
void main(void)
KeyScan();
unsigned char KeyScan(void)
unsigned char key,
unsigned char code keytab[] = {//键码表
//键值,//点,键名 键号
0x81,//07,key1 00
0x41,//06,key2 01
0x21,//05,key3 02
0x11,//04,key4 03
0x82,//17,key5 04
0x42,//16,key6 05
0x22,//15,key7 06
0x12,//14,key8 07
0x84,//27,key9 08
0x44,//26,key10 09
0x24,//25,key11 0A
0x14,//24,key12 0B
0x88,//37,key13 0C
0x48,//36,key14 0D
0x28,//35,key15 0E
0x18,//34,key16 0F
0x03,//01,key17 10
0x06,//12,key18 11
0x0c,//23,key19 12
0x05,//02,key20 13
0x09,//03,key21 14
0x0d,//13,key22 15
0xc0,//67,key23 16
0x60,//56,key24 17
0x30,//45,key25 18
0xa0,//57,key26 19
0x50,//46,key27 1A
0x90,//47,key28 1B
0x01,//G0,key29 1C
0x02,//G1,key30 1D
0x04,//G2,key31 1E
0x08,//G3,key32 1F
0x10,//G4,key33 20
0x20,//G5,key34 21
0x40,//G6,key35 22
0x80,//G7,key36 23
P1 = 0//释放键盘
_nop_();//延时
key = P1;//测试独占键(与GND连接)
key = ~//取反,变为正逻辑
if (key) {//有独占键压下,键码28~35,键key29..key36
temp = 35;//最后一个独占键key36
if (key &= 0x80)//有独占键压下,退出测试
key &&= 1;//测试下一独占键
temp --;//键号-1
while(key);//未测完继续
if (key != 0x80) key = 0//多个独占键压下,出错键码0xff
else key =//得到键码28~35,键号key29~key36.
else {//测试组合键,键码0~27
temp = 0x01;//实为从P1_1测起,到P1_7测完
do {//只需扫描7次!!!
temp &&= 1;//继续扫描下一位
P1 = ~//发送某位低电平
_nop_();//延时
key = P1;//接收键盘数据
key = ~//取反,变为正逻辑
while((temp & 0x80) && (key == temp));//测到P1_6或有键压下结束
if (key == temp) key = 0//无键压下,键码0xff
else {//有组合键压下
temp = 0;//初始键号
while(keytab[temp] && (key != keytab[temp])) temp ++;//查键值表
if (temp &= 28) temp = 0//查无此组合键,出错键码0xff
else key =//得到组合键码0~27,键key1~key28.
//返回键码0~35或出错码0xff
一个按键的多次击键组合判别技巧》大话篇
小匠自从上次在旧社区发表了一篇《&程序编写规范倡议书&大话篇》后,好久没有发表&高&论了.急坏了一帮MM,以为小匠退隐江湖了。
(斑竹在旁问道:“MM”不是“Mie Mie”,而是 “Ma Ma” 吧?)
论坛内外谣言四起,有人说小匠改行了,不做程序匠,改做泥水匠了;还有人说小匠上阿富汗反恐怖去了;其实非也,只因新板论坛启用后,小匠一直用不惯......
(斑竹在旁笑道:是“用不来”吧?)
今天,小匠再次隆重登坛献演。贴一个小程序段.....
(斑竹道:我看是“蹬痰现眼”吧?)
(程序匠人贴完帖子,下到后台,一边洗着手上残余的浆糊,一边哼着小曲:“如果你的‘芯’是一座作坊,我愿作那不知疲倦的程序匠,……”)
(一黑客悄悄贴近匠人,将一个废弃的浆糊桶扣到匠人头上......)
(匠人忙问:“斑竹,谁把灯给关了?”)
(众人哈哈大笑!......)
一个按键的多次击键组合判别技巧
有时在设计中,往往要用一个按键来输入多种信息。如:单击/双击/三击、短击/长击、还有各种组合击键方式。可以用以下程序来做。
如果按键闭合时间&500MS,判断为一次短击(0);
如果按键闭合时间&500MS,判断为一次长击(1);
两次击键时间间隔应&700MS,如果按键释放后700MS内无键按下,则结束读键。
读键完毕返回一个键号值KEY_NUM。其意义如下:
KEY_NUM& && &&&意义
& & 无键按下过
& & 无意义
& & 单次短击
& & 单次长击
& & 短击 + 短击
& & 短击 + 长击
& & 长击 + 短击
& & 长击 + 长击
……& && &&&……
& & 7次短击
& & 7次长击
上表中的KEY_NUM值的规律是,从左向右看,第一个&1&后面的每一位代表一次击键;&0&代表短击,&1&代表长击。掌握该规律后,我们可将任何一个8位的二进制数&翻译&成一种击键组合。例如:,代表的是:短+长+短+长+短+长。
该程序最多可识别7次连续击键,共254种组合。但并非每个程序中用得上。在大多数程序中,能判断双击即可以了,这时可将程序中的ZHBIT定义为2。同理,如果要判断3次按键,将ZHBIT定义为3即可。
当ZHBIT=1时,程序仅能判断一次击键,包括2种组合(短击/长击);当ZHBIT=2时,程序还能判断两次击键,包括6(2+4)种组合(短击/长击/(短+短)/(短+长)/(长+短)/(长+长));以次类推,当ZHBIT=3时,程序能判断三次击键,包括14(2+4+8)种组合。
ZHBIT& & 组合种类
2& & 2+4=6
3& & 2+4+8=14
4& & 2+4+8+16=30
5& & 2+4+8+16+32=62
6& & 2+4+8+16+32+64=126
7& & 2+4+8+16+32+64+128=254
下面这段程序摘自小匠的一个智能充电器程序(MCU是EM78P458),如下:
;********************************
;读键子程序
;出口:& & KEY_NUM& & =键号值
;中间:& & KEY_DL& & =计数器
短击:键按下时间&500MS
长击:键按下时间&500MS
两次按键间隔时间&700MS
& & KEY_NUM=:& & 无键按下
& & KEY_NUM=:& & 无意义
& & KEY_NUM=:& & 单次短击
& & KEY_NUM=:& & 单次长击
& & KEY_NUM=:& & 短击 + 短击
& & KEY_NUM=:& & 短击 + 长击
& & KEY_NUM=:& & 长击 + 短击
& & KEY_NUM=:& & 长击 + 长击
& & KEY_NUM=:& & 长击 + 长击 + 长击 + 长击 + 长击 + 长击 + 短击
& & KEY_NUM=:& & 长击 + 长击 + 长击 + 长击 + 长击 + 长击 + 长击
& & ZHBIT& & EQU& & 2& & ;按键组合位(选择范围1~7)
;********************************
& & CLR& & KEY_NUM& && &&&;清键号
& & JKOFF& & READKEYF& & ;键未按下跳
& & BS& & KEY_NUM,0& & ;&1& -& 键号低位
;=================
& & CLR& & KEY_DL& && &&&;清计数器
& & CALL& & DL10MS
& & INC& & KEY_DL
& & MOV& & A,@50
& & SUB& & A,KEY_DL
& & JBC& & R3,C& && &&&
& & JMP& & READKEYC& & ;计数器溢出跳
& & JKON& & READKEYB& & ;键未释放跳
& & BC& & R3,C& && &&&;C=0& &
& & JMP& & READKEYD
;=================
& & WDTC& && && && &;喂狗
& & JKON& & READKEYC& & ;键未释放跳
& & BS& & R3,C& && &&&;C=1
& & RLLC& & KEY_NUM& && &&&;键号左移一位,C -& 键号低位
& & JBC& & KEY_NUM,ZHBIT& & ;按键检测未完成继续
;=================
& & CLR& & KEY_DL& && &&&;清计数器
& & CALL& & DL10MS
& & INC& & KEY_DL
& & MOV& & A,@70
& & SUB& & A,KEY_DL
& & JBC& & R3,C& && &&&
& & RET& && && && &;计数器溢出返回
& & JKOFF& & READKEYE& & ;键未按下跳
& & JMP& & READKEYA& & ;再次检测
;=================
;键闭合跳(宏)
;=================
JKON& & MACRO& & ADDRESS
& & JBS& & R5,KEY& && && && &;键断开跳& && &&&
& & FJMP& & ADDRESS& && &&&;键闭合跳
& & CALL& & DL10MS& && && && &;延时去抖动& &
& & JBS& & R5,KEY& && && && &;键断开跳& && &&&
& & FJMP& & ADDRESS& && &&&;键闭合跳
ENDM& && &&&
;=================
;键断开跳(宏)
;=================
JKOFF& & MACRO& & ADDRESS
& & JBC& & R5,KEY& && && && &;键闭合跳& && &&&
& & FJMP& & ADDRESS& && &&&;键断开跳
& & CALL& & DL10MS& && && && &;延时去抖动& &
& & JBC& & R5,KEY& && && && &;键闭合跳& && &&&
& & FJMP& & ADDRESS& && &&&;键断开跳
多个按键的连按处理技巧》大话篇
咚咚呛!咚咚呛!咚咚呛!----锣鼓三响,小匠出场:“如果你的芯是一座作坊,我愿做那不知疲倦的程序匠……”
----台下,鲜花共烂西红柿一色,飞向台前……
----匠人连忙举起一个键盘,左遮右挡……
话说小匠的大话篇,自隆重推出以来,篇篇都考了个COOL,一时间人气大震。截止昨天,共结交了N位好友,众多MM纷纷到斑竹那里打听小匠的婚否情况……
----西红柿再次飞向台前……
上次贴了一篇《一个按键的多种击键组合判别技巧》,这次再贴个姊妹篇上来……
----匠人正在贴贴子,被值勤的斑竹逮个正着:“好啊!我才打扫干净,你又给糟蹋了……”
----匠人忙堆起一脸的媚笑:“斑竹大人,我贴的可是大话篇,麻烦你再给个COOL……”
----斑竹恍然:“哦,原来满纸胡言,通篇诋毁我斑竹光辉形象的那个匠人,就是你?!……”
----匠人一看情形不对,正想开溜……
----只见一道白光一晃……
----3个时辰之后,有人发现昏迷不醒的程序匠人躺在血泊之中……
----墙上提着一行血字:“十步杀一匠,千里不留行。事了拂衣去,深藏身与名。”……
----好了,言归正传,请看下文:
& & 《多个按键的连按处理技巧》
& & 在设计中,常常用UP键和DOEN来调节参数。这种键在处理时,要考虑连按的问题。而且希望键连续按下的时间越长,动作的响应速度越快(即加速度处理)
在连按的处理过程中,要考虑3个时间常数:
& & 1、连按响应时间常数(首次值),该值用于区分连按/单按。
& && &&&a)当按键闭和的时间&该参数时,判为单按;
& && &&&b)当按键闭和的时间&该参数时,判为连按;
& & 2、连按缓冲时间常数(最大值)。
& && &&&在连按操作刚开始时,按键响应速度较慢,这个参数就是用于决定每次动作之间的最大时间。
& & 3、连按缓冲时间常数(最小值)
& && &&&在连按的过程中,响应的速度越来越快,但也不能无限快。这个参数就是用于决定每次动作之间的最小时间。
& & 还有一个要考虑的问题是,可能并不是所有按键都具有连按功能。这时,可用一个标志位来区分。在读键子程序中返回键值的同时,也返回这个标志,告诉键盘监控程序是否要做连按处理。
& & 下面的一段例程中,可以识别单按/连按,并可处理加速度问题。只要在主程序中调用即可。程序中的延时用现实程序来代替。
;********************************
;按键处理模块
;********************************
;时间常数定义
KEY_T& && &&&==& & 250& && &&&;连按响应时间常数(首次值)
KEY_TMAX& & ==& & 120& && &&&;连按缓冲时间常数(最大值)
KEY_TMIN& & ==& & 30& && &&&;连按缓冲时间常数(最小值)
;********************************
& & MOV& & A,@KEY_T
& & MOV& & KEY_JS,A& && &&&;连按计数器置初值
& & BC& & TT1,KEY& && && && &;清连按标志
& & MOV& & A,@KEY_TMAX-KEY_TMIN
& & MOV& & KEY_JSJS,A& && &&&;连按加速计数器置初值
& & CALL& & READKEY& && && && &;读键
& & JBS& & R3,C& && && && &;有键按下跳
& & FCALL& & MOVLCD& && && && &;显示延时
& & CALL& & READKEY& && && && &;读键
& & JBS& & R3,C& && && && &;确实有键按下跳
;====确实有键按下
& & MOV& & KEY_BUF,A& && &&&;保存键值& &
& & FCALL& & MOVLCD& && && && &;显示延时
& & CALL& & READKEY& && && && &;读键
& & JBS& & R3,C& && && && &;键未释放跳
& & JMP& & KEY5
;====连按判断
& & JBS& & TT1,KEY_EN& && &&&;连按功能有效跳
& & JMP& & KEY1& && && && &;禁止连按跳
& & JBC& & TT1,KEY& && && && &;不是连按跳
& & JMP& & KEY2
& & DJZ& & KEY_JS& && && && &;连按计数器-1=0跳
& & JMP& & KEY1
& & BS& & TT1,KEY& && && && &;置连按标志
& & JMP& & KEY1
;====连按处理
& & CALL& & DOKEY& && && && &;执行按键功能& &
& & MOV& & WK_MODE,A& && &&&;刷新模式
;连按加速计数器-1
& & DJZ& & KEY_JSJS& && &&&
& & JMP& & $+2
& & INC& & KEY_JSJS
;连按计数器置延时值
& & MOV& & A,@KEY_TMIN
& & ADD& & A,KEY_JSJS& && &&&
& & MOV& & KEY_JS,A& && &&&;连按计数器置延时值
& & FCALL& & MOVLCD& && && && &;显示延时
& & DJZ& & KEY_JS& && && && &;连按计数器-1=0跳
& & JMP& & KEY4
& & JMP& & KEY1
;====单按处理
& & FCALL& & MOVLCD& && && && &;显示延时
& & CALL& & READKEY& && && && &;读键
& & JBC& & R3,C& && && && &;键确实已释放跳
& & JMP& & KEY1
& & JBC& & TT1,KEY& && && && &;不是连按跳
& & BS& & TT1,KEY_SP& && &&&;开蜂鸣器
& & FCALL& & MOVLCD
& & CALL& & DOKEY& && && && &;执行按键功能& &
& & MOV& & WK_MODE,A& && &&&;刷新模式
& & BC& & TT1,KEY_SP& && &&&;关蜂鸣器
& & FCALL& & MOVLCD
;********************************
;读键子程序
;出口:& & A=键号值(0=无,1=K2定时,2=K3功率选择,3=K4水温上调,4=K5水温下调,
;& && && && &5=K6时钟上调,6=K7时钟下调,7=K8时段设置)
;& & C:& && &&&(0=无,1=有)
;& & TT1,KEY_EN:& & 当前键连按有效标志(0=禁止连按,1=可连按)
;& & (K4/K5/K6/K7有连按功能)
;********************************
& & BS& & R3,C
;不可连按的按键
& & BC& & TT1,KEY_EN
& & JBS& & R7,6& && && && &;K2未闭合跳
& & RETL& & @01& && && && &;返回A=01& &&&
& & JBS& & R7,0& && && && &;K3未闭合跳
& & RETL& & @02& && && && &;返回A=02& &&&
& & JBS& & R7,5& && && && &;K8未闭合跳
& & RETL& & @07& && && && &;返回A=07& &&&
;可连按的按键
& & BS& & TT1,KEY_EN
& & JBS& & R7,1& && && && &;K4未闭合跳
& & RETL& & @03& && && && &;返回A=03& &&&
& & JBS& & R7,2& && && && &;K5未闭合跳
& & RETL& & @04& && && && &;返回A=04& &&&
& & JBS& & R7,3& && && && &;K6未闭合跳
& & RETL& & @05& && && && &;返回A=05& &&&
& & JBS& & R7,4& && && && &;K7未闭合跳
& & RETL& & @06& && && && &;返回A=06& &&&
& & BC& & R3,C
& & RETL& & @00& && && && &;返回A=00
PC机键盘按键通码与ASCII对照表
这个库要配合本站发部的 单片机驱动标准pc机键盘的c51程序使用
unsigned char code noshift[80][2]=
22 ,49,// { 1 }
30 ,50,// { 2 }
38 ,51,// { 3 }
37 ,52,// { 4 }
46 ,53,// { 5 }
54 ,54,// { 6 }
61 ,55,// { 7 }
62 ,56,// { 8 }
70 ,57,// { 9 }
69 ,48,// { 0 }
28 ,97,// { a }
50 ,98,// { b }
33 ,99,// { c }
35 ,100,// { d }
36 ,101,// { e }
43 ,102,// { f }
52 ,103,// { g }
51 ,104,// { h }
67 ,105,// { i }
59 ,106,// { j }
66 ,107,// { k }
75 ,108,// { l }
58 ,109,// { m }
49 ,110,// { n }
68 ,111,// { o }
77 ,112,// { p }
21 ,113,// { q }
45 ,114,// { r }
27 ,115,// { s }
44 ,116,// { t }
60 ,117,// { u }
42 ,118,// { v }
29 ,119,// { w }
34 ,120,// { x }
53 ,121,// { y }
26 ,122,// { z }
84 ,91,// { [ }
91 ,93,// { ] }
76 ,59,// { ; }
82 ,39,// { ' }
65 ,44,// { , }
73 ,46,// { . }
74 ,47,// { / }
78 ,45,// { - }
85 ,61,// { = }
93 ,92,// { \ }
14 ,96,// { ` }
90 ,32,// { enter }
5 , 0,// { f1 }
6 , 1,// { f2 }
4 , 2,// { f3 }
12 , 3,// { f4 }
3 , 4,// { f5 }
11 , 5,// { f6 }
131, 6,// { f7 }
10 , 7,// { f8 }
1 , 8,// { f9 }
9 , 9,// { f10 }
120,10,// { f11 }
7 ,11,// { f12 }
102,12,// { back }
224,13,// { home }
105,14,// { end }
125,15,// { pageup }
122,16,// { pagedown }
117,17,// { up }
114,18,// { down }
107,19,// { left }
116,20,// { right }
113,21,// { del }
112,22,// { insert }
225,23,// { pause }
118,24,// { esc }
13 ,25,// { tab }
88 ,26,// { caps }
20 ,27,// { ctrl }
17 ,28,// { alt }
41 ,29,// { space }
31 ,30,// { win }
47 ,31,// { winright }
};&/P&&P&unsigned char code addshift[47][2]=
14,126, // { ~ }
22, 33, // { ! }
30, 64, // { @ }
38, 35, // { # }
37, 36, // { $ }
46, 37, // { % }
54, 94, // { ^ }
61, 38, // { & }
62, 42, // { * }
70, 40, // { ( }
69, 41, // { ) }
78, 95, // { _ }
85, 43, // { + }
93,124, // { | }
84,123, // { { }
91,125, // { } }
76, 58, // { : }
82, 34, // { & }
65, 60, // { & }
73, 62, // { & }
74, 63, // { ? }
28 ,65,// { a }
50 ,66,// { b }
33 ,67,// { c }
35 ,68,// { d }
36 ,69,// { e }
43 ,70,// { f }
52 ,71,// { g }
51 ,72,// { h }
67 ,73,// { i }
59 ,74,// { j }
66 ,75,// { k }
75 ,76,// { l }
58 ,77,// { m }
49 ,78,// { n }
68 ,79,// { o }
77 ,80,// { p }
21 ,81,// { q }
45 ,82,// { r }
27 ,83,// { s }
44 ,84,// { t }
60 ,85,// { u }
42 ,86,// { v }
29 ,87,// { w }
34 ,88,// { x }
53 ,89,// { y }
26 ,90,// { z }
单片机驱动标准PC机键盘的C51程序
/*---------------------------------------------------------------------------------------------------
功能:实现pc机键盘(p/s2接口)与8位单片机连接使用
原理:键盘时钟接在p3.2口,既8051的外部中断int0上,键盘数据接到p1.0上
每次按键,键盘会向单片机发脉冲使单片机发生外部中断,数据有p1.0口一位一位传进来
传回的数据格式为:1位开始位(0),8位数据位(所按按键的通码,用来识别按键),1位校验位(奇校验)
1位结束位(1)
实现:将键盘发回的数据放到一个缓冲区里(数组),当按键结束后发生内部中断来处理所按的按键
缺点:由于51单片机的容量有限所以缓冲区不可以开的太大,这就导致可以记录键盘的按键次数过少,
也就是容错性一般。不过如果正常使用键盘是不会出错的
最后修改时间:2003年5月
开发人:鞠春阳
版权:哈尔滨众邦龙开发有限公司
单片机坐标网
====================================================================================================*/
//#include&reg51.h&
#include &intrins.h&
#include &ku.h& //按键通码与ascii对照表
sbit sda= p1^0; //键盘数据线
unsigned char dat=0,dat1=0,dat2=0; //接收键盘数据变量? 存储通码变量 接受连续通码变量
unsigned char count=0,num=9,temp[5],shu=0; //中数次数 中断控制变量 缓冲区数组 缓冲区指针
unsigned char key=0; //按键最终值
void zhongduan() interrupt 0 //外部中断0 用来接受键盘发来的数据
dat&&=1; //接受数据 低-&高
if(sda) dat|=0x80;
if(count==num)
if(count==9)
dat1= //中断9次后为键盘所按按键的通码(开始位始终为0在第一次中断时右移中忽略)
num=20; //使中断可以继续中断11次
if(count==20)
dat2= //取回第二个通码
if(dat1==0xe0 || dat2==0xf0) //第一个通码是0xe0则证明所按按键为功能键,第二个通码是0xf0证明按键结束
temp[shu]=dat1;temp[shu+1]=dat2; shu+=2; //将所按按键存到缓冲区中
ie=0x82; //关闭外部中断并打开内部中断来处理所按按键
temp[shu]=dat1;temp[shu+1]=dat2; shu+=2; //如果shift键被按下则记录与它同时按下的那个键
if((temp[0]==18 || temp[0]==89) && (temp[2]==18 || temp[2]==89) ) tr0=1; //如果缓冲区中有两个间隔的shift键则证明需要的铵键结束
void getkey() interrupt 1 //内部中断0 用来处理缓冲区里的数据
unsigned char i=0;
count=0; //中断记数则0
if((temp[0]==18 || temp[0]==89) && temp[1]!=0xf0 ) //shift被按下
for(i=0;i&21;i++)
if(addshift[0]==temp[1]) //搜索shift被按下的表
key=addshift[1];
ie=0x83; //打开外部中断
else if(temp[0]==0xe0) //所按下的按键是功能键
for(i=0;i&80;i++)
if(noshift[0]==temp[1]) //功能键的通码在缓冲区的第二位
key=noshift[1];
else //普通按键
for(i=0;i&80;i++)
if(noshift[0]==temp[0]) //普按键的通码在缓冲区的第一位
key=noshift[1];
for(i=0;i&5;i++)
//说明:由key.c文件和key.h文件组成,编译环境KEIL 750A,使用外部端口0X7F1D的输入输出作为行列线。
#define KEY
#include &includes.h&
void KeyBufIn(unsigned char kcode)
if(KeyNRead & KEY_BUF_SIZE)& && &&&
{& && && && && &
&&KeyNRead++;& && && && &
&&KeyBuf[KeyBufInIx++] =& &
&&if (KeyBufInIx &= KEY_BUF_SIZE)
&&{& && &&&
& &KeyBufInIx = 0;
&&EA=1;& && && && && && && && && && &&&
else& && && && && && &
{& && && && && && && && && && && && &
&&EA=1;& && && && && &&&
unsigned char KeyDecode(void)
unsigned char col_
done=FALSE;
while (row & KEY_MAX_ROWS && !done)& &
{& && && && &
&&KeySelRow(row);& && && && && && && && && && && && && &
&&if(KeyIsKeyDown())& && && && &&&
&&{& && && && && && && && &
& &done = TRUE;& && && && && && && && && && &
& &row++;& && && && && && && && && && && && && && &&&
col=KeyGetCol();& && && && && && && && && && && && && && && && &
offset = 0;& && && && && && && && &
if (col & KEY_SHIFT1_MSK)& && && && && &
归纳得很好,有特点,收藏了有空再看。
站长推荐 /1
18X24厘米超大PCB功能底板,板载19个芯片集成38大功能模块,扩展核心板9.5X6厘米,完美支持AT&STC51、AVR、PIC、MSP430、ARM、STM32、M0等等,配超大精美铝箱、触摸彩屏、OLED液晶....
Powered by}

我要回帖

更多关于 与门芯片 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信