单片机在日常生活中用途广泛,除了可以输出外控制外部设备外,还可以检测用户实时发出的指令;这就是人机交互,要实现人机交互,需要给单片机安上输入设备,这里指定就是人们能够输入的键盘,就像个人电脑一样,给电脑输入文字、命令等。单片机的键盘可分为编码键盘和非编码键盘,这里主要分享非编码键盘的检测,以单按键检测为例。
/****************
此程序需要按键一直按下不松手,灯才会亮
松手灯就熄灭
*/
ORG 0000H
LOOP:SETB P3.2 ;p3.2为输入引脚
JNB P3.2,LD ;P3.2按下执行灯亮
SETB P0.0 ;否则灯灭
SJMP LOOP
LD:CLR P0.0
AJMP LOOP
END
第一个例子可以看出,要让灯亮必须一直按住按钮,这可要把人累坏。能不能按一次,灯的状态就变化一次,模拟我们日常开关灯,答案是肯定的。
/****************
此程序用一个按键模拟开灯和关灯、
按下一次按键,灯的状态取反一次
实现单按键控制开关灯,
程序有一个问题,有时按一次按键,灯的状态
并不改变,这是什么原因呢?原来机械按键有抖动
我们按一次按键,单片机扫描速度很快,它认为按下了
多次,进行逻辑判断后,确定灯的状态,可能发生很多次
翻转,造成输出不是预定的效果,这就是机械抖动。
*/
ORG 0000H
LOOP:SETB P3.2 ;设为输入口
JB P3.2,LOOP ;等待按键按下
CPL F0 ;按下一次取反一次
JB F0,liang
SETB p0.0 ;F0为0,灯灭
SJMP LOOP
liang:CLR P0.0 ;F0为1,灯亮
SJMP LOOP
END
通过实验,发现这段程序还是不能很好模拟开关灯,那是为什么呢?难道利用一个按键控制一个灯的亮灭就这么难吗?由于按键的机械特性,按键按下时,并不是我们想的从高电平直接降为低电平,其实在按下的过程中,电平高低极其不稳定,这就是大名鼎鼎的“按键抖动”,要解决这个问题就必须消除按键过程产生的抖动,可以用什么方法消抖,一般有两种,硬件消抖和软件消抖;硬件消抖主要是通过外加电容或者触发器消抖,会增加成本,一般采用软件消抖的方法。软件消抖又分为延时消抖和中断法消抖,下面就两种方法分别介绍。
一、延时消抖法
/* 此程序采用延时消抖的方法
检测一次按键,更改灯的状态,
程序在延时10ms的时间内,以及在等待
按键松手的时间内cpu无法做其他的事,浪费
cpu的资源。
*/
ORG 0000H
CLR P2.0
LOOP:SETB P3.2 ;设为输入口
JB P3.2,LOOP ;等待按键按下
ACALL DELAY10MS ;延时消抖动
JB P3.2,LOOP ;再次判断是否按下
CPL F0 ;按下一次取反一次
JNB P3.2,$ ;等待按键释放
JB F0,liang
SETB p0.0 ;F0为0,灯灭
SJMP LOOP
liang:CLR P0.0 ;F0为1,灯亮
SJMP LOOP
DELAY10MS:
PUSH 30H
PUSH 31H
MOV 30H,#20
MOV 31H,#108
NEXT:
DJNZ 31H,NEXT
DJNZ 30H,NEXT
POP 31H
POP 30H
RET
END
二、为了改进,提高CPU的效率,采用中断扫描消抖的方法
/*利用定时中断的方式,解决按键消抖
很好地解决了,程序的执行效率,提升了
按键检测的准确性。
*/
ORG 0000H
AJMP MAIN
;t0每1ms中断一次,10ms判断一次P3.2引脚
ORG 000BH
MOV TL0,#018H ;设置定时初值
MOV TH0,#0FCH ;设置定时初值
INC R1
RETI
MAIN:
INC TMOD
MOV TL0,#018H ;设置定时初值
MOV TH0,#0FCH ;设置定时初值
SETB ET0
SETB EA
SETB TR0
CLR p2.0
LOOP:
setb p3.2 ;设置输入
jb f0,LD2 ;按键按下标志位,按下设为1
mov c,p3.2 ;读引脚状态
jc LOOP ;判断是否有按下,没有按下转LOOP
setb f0 ;按键按下,置为f0
// setb tr0
LD2:CJNE R1,#20,loop1 ; 按键消抖
mov r1,#00
jnb p3.2,loop1 ;等待松手
cpl p0.0 ;键值处理
clr f0 ;标志清零
loop1:
nop ;此处可以插入其他代码,等待按键松手的过程中可以执行其它程序
AJMP LOOP
END
通过独立按键的学习,对单片机的控制进一不充满了信心,加油