|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
键盘是由若干按钮组成的开关矩阵,它是单片机系统中最常用的输入设备,用户能通过键盘向计算机输入指令、地址和数据。一般单片机系统中采和非编码键盘,非编码键盘是由软件来识别键盘上的闭合键,它具有结构简单,使用灵活等特点,因此被广泛应用于单片机系统。按钮开关的抖动问题2 @% m, G( V5 q. b1 B, f% ~ N% k
组成键盘的按钮有触点式和非触点式两种,单片机中应用的一般是由机械触点组成的。在下图中,当开
) b. E; y5 H [7 u# H3 X* v<键盘结构图>
) t* L& ]5 |' I: O' ?
8 D4 \: l5 g3 _4 P1 Y$ @4 e& k! b8 N- Z 图1 ) M" F/ U! s4 F
| ; Y3 F$ O4 g! Z# ]7 h. g
图2 ; U6 z6 E3 ~. V- }$ r
| 关S未被按下时,P1。0输入为高电平,S闭合后,P1。0输入为低电平。由于按钮是机械触点,当机械触点断开、闭合时,会有抖动动,P1。0输入端的波形如图2所示。这种抖动对于人来说是感觉不到的,但对计算机来说,则是完全能感应到的,因为计算机处理的速度是在微秒级,而机械抖动的时间至少是毫秒级,对计算机而言,这已是一个“漫长”的时间了。前面我们讲到中断时曾有个问题,就是说按钮有时灵,有时不灵,其实就是这个原因,你只按了一次按钮,可是计算机却已执行了多次中断的过程,如果执行的次数正好是奇数次,那么结果正如你所料,如果执行的次数是偶数次,那就不对了。
) ^. F$ w; Z- v8 ~ @" t5 S为使CPU能正确地读出P1口的状态,对每一次按钮只作一次响应,就必须考虑如何去除抖动,常用的去抖动的办法有两种:硬件办法和软件办法。单片机中常用软件法,因此,对于硬件办法我们不介绍。软件法其实很简单,就是在单片机获得P1。0口为低的信息后,不是立即认定S1已被按下,而是延时10毫秒或更长一些时间后再次检测P1。0口,如果仍为低,说明S1的确按下了,这实际上是避开了按钮按下时的抖动时间。而在检测到按钮释放后(P1。0为高)再延时5-10个毫秒,消除后沿的抖动,然后再对键值处理。不过一般情况下,我们常常不对按钮释放的后沿进行处理,实践证明,也能满足一定的要求。当然,实际应用中,对按钮的要求也是千差万别,要根据不一样的需要来编制处理程序,但以上是消除键抖动的原则。
) f) e# [) \4 ^0 l) _9 S键盘与单片机的连接6 j3 i: I/ X9 Q. C8 U. k
+ B q% E/ z5 d( D# f# Z% t <键盘连接> ' x) Q- I) d& S$ b
图3 / k; l' K9 X% K e9 I! W/ ?
| 7 C x Q) @+ b+ ?; m' K
<单片机与键盘接口图>
$ V4 ?) J2 ^% _! j- g; R 图4
7 s: x) y* B7 ?3 f4 L9 T. V | 1、通过1/0口连接。将每个按钮的一端接到单片机的I/O口,另一端接地,这是最简单的办法,如图3所示是实验板上按钮的接法,四个按钮分别接到P3.2 、P3.3、P3.4和P3.5。对于这种键各程序能采用持续查询的办法,功能就是:检测是否有键闭合,如有键闭合,则去除键抖动,判断键号并转入对应的键处理。下面给出一个例程。其功能很简单,四个键定义如下:- B7 l% i0 P5 @7 U+ B. f! ]$ r
P3.2:开始,按此键则灯开始流动(由上而下), Y. [* C h( q# G; f2 n
P3.3:停止,按此键则停止流动,所有灯为暗
5 S! v# j/ {' \8 Y7 fP3.4:上,按此键则灯由上向下流动
0 ]$ r* L, E4 u' y" OP3.5:下,按此键则灯由下向上流动' D1 z4 G. l3 P5 k D: Z v
UpDown EQU 00H ;上下行标志
4 d7 f8 g4 ?7 Q4 |9 H$ s# E2 @StartEnd EQU 01H ;起动及停止标志
- V& }1 G; G- p7 kLAMPCODE EQU 21H ;存放流动的数据代码+ S: \. J; P' A2 t$ y- O8 E7 d" a
ORG 0000H, ^' h" \, {+ }0 B1 x9 p2 p z
AJMP MAIN# s% p; ?+ e. O6 |
ORG 30H
% B, E* ^4 F% T! i7 @' ?" eMAIN:
9 k% U9 z& g# J9 z& z8 G7 YMOV SP,#5FH& y @8 i7 X+ j5 P, @) V. ^
MOV P1,#0FFH1 H/ E& K, X* a, n$ \1 \, L1 G9 }
CLR UpDown ;启动时处于向上的状态
$ b1 g" O8 P# r% s9 {9 L* V2 kCLR StartEnd ;启动时处于停止状态
: i; k6 M: E9 RMOV LAMPCODE,#0FEH ;单灯流动的代码- u" h2 ?5 M6 s: V* A: A5 ]
LOOP:
I* [9 ?6 i# g9 GACALL KEY ;调用键盘程序% c6 O4 d6 e$ J2 @5 p
JNB F0,LNEXT ;如果无键按下,则继续
( O$ ~; n4 A/ v. ~6 I0 O1 Y oACALL KEYPROC ;不然调用键盘处理程序
8 u% B9 ^; J6 Q+ F6 u' ?LNEXT:1 D, F2 v) J. m2 v4 {. B$ h0 c ?
ACALL LAMP ;调用灯显示程序
% S' A1 l5 I$ s- s2 _5 i$ wAJMP LOOP ;反复循环,主程序到此结束$ Q9 T" C! w( ^3 \
DELAY:
+ s- ~# s |5 z, H5 WMOV R7,#100
, L4 {6 T4 S! F x3 c1 y6 N `1 [D1: MOV R6,#100
8 d6 P) R: @3 @ B; TDJNZ R6,$0 S3 U3 N# x2 y. j3 J/ z5 V' ^
DJNZ R7,D1
# ` |4 B( `# L! I( r) gRET7 Y% m# d0 V' N/ S8 C4 P/ {8 y
;----------------------------------------延时程序,键盘处理中调用
% o1 u( [4 Y& }$ P d M) H1 s9 w- mKEYPROC:. N4 i. j6 N3 {
MOV A,B ;从B寄存器中获取键值/ x- ^6 s% x' r$ b6 s: N
JB ACC.2,KeyStart ;分析键的代码,某位被按下,则该位为1(因为在键盘程序中已取反)
* w% Z" H4 y9 C- R9 q% X" J% Q5 zJB ACC.3,KeyOver
8 V. v9 z# G/ N9 \3 J4 n; Z' ?JB ACC.4,KeyUp# E7 } S8 E; G; f; J3 P) q
JB ACC.5,KeyDown# }" x6 h# X5 k. q( i! q* T
AJMP KEY_RET w# r: c: n7 I1 F: X9 |3 |9 w
KeyStart:
" b, r$ a3 h+ z zSETB StartEnd ;第一个键按下后的处理
2 e5 S @5 P& ?3 ^$ r( x$ H! KAJMP KEY_RET
7 N% e" r4 E* [& C& eKeyOver:8 v4 [% U% b5 p$ U% R
CLR StartEnd ;第二个键按下后的处理2 `& Q+ @8 p- @4 A' w. N
AJMP KEY_RET
$ Z7 N# _' p' S- U" }0 G+ r% l5 TKeyUp: SETB UpDown ;第三个键按下后的处理, H3 ?9 B( X! ^) b5 ^8 q
AJMP KEY_RET
+ J1 {1 d7 n# z+ u# G m4 {KeyDown:
8 d6 J. E$ n0 q! S( R. Q3 E1 aCLR UpDown ;第四个键按下后的处理. e6 \/ m# R4 y; R* v: ^
KEY_RET:RET
) m1 O; G: R1 u( P' q) _KEY:
: \6 d* H' ~5 P1 E+ _: T. ]0 s3 YCLR F0 ;清F0,表示无键按下。, P1 o; f2 k+ X* _
ORL P3,#00111100B ;将P3口的接有键的四位置1
/ A2 y* [, q5 E6 D0 ~MOV A,P3 ;取P3的值
) x8 M9 Y _5 c PORL A,#11000011B ;将其余4位置1
6 m. `5 |3 g d, U4 ~4 q; q' ~* bCPL A ;取反, y7 m: x* f$ _6 H, U G
JZ K_RET ;如果为0则一定无键按下
) L I/ {" O" [9 k0 O; M4 h! C) KACALL DELAY ;不然延时去键抖
8 o" Z2 }' l# P" K! W0 \; M: RORL P3,#00111100B
5 ^* \: `; A, Z, ^/ u9 j) c; DMOV A,P32 `! ?: c) j. {6 M, t
ORL A,#11000011B
: m$ w" n1 ^$ ^1 Y5 pCPL A" D& e3 E2 V0 |& O$ d6 G
JZ K_RET$ u d# z, R ]# r7 H4 D
MOV B,A ;确实有键按下,将键值存入B中) X5 q; z' G7 K
SETB F0 ;设置有键按下的标志
) t% S; a6 V/ e7 S; c0 }; D YK_RET:+ K4 } K" P: I; X( k7 ^# }) I
ORL P3,#00111100B ;此处循环等待键的释放
( Y Y: N# N0 f7 s- DMOV A,P3
, }( I- y5 a, J5 F6 JORL A,#11000011B, x# |' H/ ^6 `$ E1 v- \
CPL A
# H! O L& {6 L+ QJZ K_RET1 ;直到读取的数据取反后为0说明键释放了,才从键盘处理程序中返回% Q1 w) l) f/ @) l7 Z* r5 ]
AJMP K_RET
' t1 S: `) M3 gK_RET1:# N; _/ g, n; ^6 T3 W3 f" I
RET
: A4 O0 Y$ o+ B" VD500MS: ;流水灯的延迟时间/ ?' F. U$ u& s& k
PUSH PSW0 F, D# e1 }% I7 D8 R; G
SETB RS0
. [: p$ ^. F9 ?* SMOV R7,#200
% s7 P6 C. a; LD51: MOV R6,#2503 I% r- Z( o: T
D52: NOP" r5 ^5 [% f% S) T3 k. _. a
NOP1 O& [& _6 p/ K' Q0 c+ s8 _6 D
NOP
4 t/ J+ Y% g N& PNOP7 [5 ?8 l1 p# {, P; i) \3 g0 Y& t
DJNZ R6,D52
* K" W( N4 ~- _! A, ]4 nDJNZ R7,D51% y% ~- Y5 K: d4 C* c' Z- _, l
POP PSW
3 P1 U* J) M6 F& xRET
1 I/ |& K! v+ I, G! wLAMP:8 ?$ ^* d" G) {" s9 ?# z5 x: D
JB StartEnd,LampStart ;如果StartEnd=1,则启动
' A6 }3 t7 W4 M/ B% s1 gMOV P1,#0FFH' K+ ~9 e* t2 q9 o% A
AJMP LAMPRET ;不然关闭所有显示,返回
, v6 q/ Y6 u6 r6 V- OLampStart:
6 b3 `6 y. o9 d8 ?: e+ D+ fJB UpDown,LAMPUP ;如果UpDown=1,则向上流动
) r( v( b V3 JMOV A,LAMPCODE! W1 I6 R$ S! u
RL A ;实际就是左移位而已) D' i9 I9 ^( t5 |+ _! _9 A
MOV LAMPCODE,A- B* x6 u2 ^* |' |
MOV P1,A
$ ?9 S) P% g/ G y$ j2 ~3 i7 W. T0 XLCALL D500MS* C0 e, p4 l* V, i4 F0 S
AJMP LAMPRET' M, o8 i3 x& z7 E/ x8 ?
LAMPUP:
1 w" I; |) Z1 zMOV A,LAMPCODE
+ s! ]0 K- P. G" z# xRR A ;向下流动实际就是右移
3 N& B1 ?/ X) ~8 Z; pMOV LAMPCODE,A) {2 c% H p$ m- @8 {* j% P5 U
MOV P1,A
; B. C6 A( `4 O$ V" J7 S" @LCALL D500MS5 S4 k6 u2 V: k% F. N# J
LAMPRET:- R2 C: x6 C( B- w
RET
4 A; H# ~! I4 x( v1 c. p8 ?3 _END$ G9 v# K( _, i) | Y2 I
以上程序功能很简单,但它演示了一个单片机键盘处理程序的基本思路,程序本身很简单,也不很实用,实际工作中还会有好多要考虑的因素,比如主循环每次都调用灯的循环程序,会造成按钮反应“迟钝”,而如果一直按着键不放,则灯不会再流动,一直要到松开手为止,等等,大家能仔细考虑一下这些问题,再想想有什么好的解决办法。
5 G4 Q9 K5 C+ e( M _2、采用中断方式:如图4所示。各个按钮都接到一个与非上,当有任何一个按钮按下时,都会使与门输出为低电平,从而引起单片机的中断,它的好处是不用在主程序中持续地循环查询,如果有键按下,单片机再去做对应的处理
. @5 X3 K4 S5 n7 y, C |
|