单片机键盘扫描程序

单片机键盘扫描程序,第1张

23的键盘,太简单了,不值得用循环,特别是双重循环。

最简明、高效的程序如下:

sbit P10 = P1^0;

sbit P11 = P1^1;

sbit P12 = P1^2;

sbit P13 = P1^3;

sbit P14 = P1^4;

char scan_key(void)

{

P13 = 0;

if (!P10) return 0;

if (!P11) return 1;

if (!P12) return 2;

P13 = 1;

P14 = 0;

if (!P10) return 3;

if (!P11) return 4;

if (!P12) return 5;

}

本程序,使用的变量最少,也不涉及其它接口。

代码最少,执行效率最高。

(1);P33小键盘按下P13亮再按05秒灭。

org 0000h

ajmp main0

org 0080h

MAIN0:

CLR 21H ;清标志

main:

mov c,p33 ;检测按键

jc main

MOV R6,#200 ;设定延时

MOV R7,#200

TT0:

JNB 21H,TT2 ;检测灯状态

tt:

mov c,p33 ;检测按键

jnc tt1

JNB 20H,MAIN ;检测时间标志

CLR 20H

AJMP TT3

TT2:

mov c,p33 ;检测按键

jnc tt2

TT3:

CPL 21H ;改变灯状态

cpl p13

ajmp main

TT1: NOP ;延时但不是子程序

NOP

NOP

NOP

NOP

NOP

DJNZ R6,TT

MOV R6,#200

DJNZ R7,TT

MOV R7,#200

SETB 20H

AJMP TT

end

(2)数码管数据 p0,数码管控制p2 独立按键p1口 ,;对独立键进行按键次数计数,三位数码管显示。

;K1按下后,进行加1计数

;K2按下后,进行减1计数。

;K3按下后,进行加5计数。

;K4按下后,清计数单元,数码管显示0。

;按住键可以快速计数。

K1 BIT P14

K2 BIT P15

K3 BIT P16

K4 BIT P17

K_OLD EQU 30H

K_NEW EQU 31H

K_COUNT EQU 32H

DISSTART EQU 40H ;显示单元首地址

LED_DATA EQU P0 ;数码管数据口定义

;---------------------------------------------------------

ORG 0000H

JMP MAIN

ORG 0080H

;---------------------------------------------------------

MAIN:

MOV SP,#60H

MOV P1,#0FFH

MOV P0,#0FFH

MOV K_OLD,#00H

MOV K_COUNT,#00H

MAIN1:

CALL CONVT

CALL PLAY

CALL KEY_PROG

JMP MAIN1

KEY_PROG:

CALL K_SCAN ;键扫描

MOV A,K_NEW

CJNE A,K_OLD,KEY_P1

JMP KEY_P_END

KEY_P1:

MOV R4,#20

KEY_P2:

CALL CONVT ;用显示程序来进行键延时

CALL PLAY

DJNZ R4,KEY_P2

CALL K_SCAN ;再判断键是否按下

MOV A,K_NEW

CJNE A,K_OLD,KEY_P3

JMP KEY_P_END

KEY_P3:

JB ACC0,LOOP1 ;K1按下

JB ACC1,LOOP2 ;K2按下

JB ACC2,LOOP3 ;K3按下

JB ACC3,LOOP4 ;K4按下

JMP KEY_P_END

LOOP1:

INC K_COUNT ;键计数加1

JMP KEY_P_END

LOOP2:

DEC K_COUNT ;键计数减1

JMP KEY_P_END

LOOP3:

INC K_COUNT ;键计数加5

INC K_COUNT

INC K_COUNT

INC K_COUNT

INC K_COUNT

JMP KEY_P_END

LOOP4:

MOV K_COUNT,#00H ;键计数单元清零

KEY_P_END:

RET

;---------------------------------------------------------

;代码变换 (HEX TO BCD)

;---------------------------------------------------------

CONVT:

MOV A,K_COUNT

MOV B,#100

DIV AB

MOV DISSTART+2,A ;百位存放在DISSTART+2

MOV A,#10

XCH A,B

DIV AB

MOV DISSTART+1,A ;十位存放在DISSTART+1

MOV DISSTART,B ;个位存放在DISSTART

RET

;---------------------------------------------------------

; 键扫描子程序

;---------------------------------------------------------

K_SCAN:

MOV P1,#0FFH

MOV K_NEW,#00H

MOV A,P1

CPL A

ANL A,#0F0H

SWAP A

MOV K_NEW,A

RET

;---------------------------------------------------------

;延时子程序

;---------------------------------------------------------

DELAY:

MOV R6,#200

DEL:

MOV R7,#0FFH

DJNZ R7,$

DJNZ R6,DEL

RET

;---------------------------------------------------------

PLAY:

MOV R0,#DISSTART ;获得显示单元首地址

MOV R1,#07FH ;从第一个数码管开始

MOV R2,#03H ;共显示3位数码管

DISP1:

MOV A,@R0 ;获得当前位地址

MOV DPTR,#TAB_NU ;获得表头

MOVC A,@A+DPTR ;查表获得显示数据

MOV LED_DATA,A ;显示数据

MOV P2,R1 ;开始显示当前位

MOV A,R1 ;准备显示下一位

RR A

MOV R1,A ;下一位

INC R0 ;取下一个单元地址

LCALL DELAY2MS ;延时 2 MS

DJNZ R2,DISP1 ;重复显示下一个

MOV P2,#0FFH ;关闭显示

RET ;显示完成,返回

;---------------------------------------------------------

;延时子程序

;---------------------------------------------------------

DELAY2MS:

MOV R6,#10

DEL1:

MOV R7,#100

DJNZ R7,$

DJNZ R6,DEL1

RET

TAB_NU:

db 28h,7eh,0a2h,62h,74h,61h,21h,7ah,20h,60h ;字形代码表

;

END

两个例子我想够你明白的了。详细的解释,代表性的例子,可慢慢学习

原理图是错的,理解你的意思,有按键时高,无按键时低。

ORG 0000H

LJMP MAIN

ORG 0030H

MAIN:

MOV A,P0

JZ MAIN

MOV B,A

LCALL DELAY

MOV A,P0

CJNE A,B,MAIN

NEXT:

MOV A,P0

CJNE A,B,NEXT1

SJMP NEXT

NEXT1:

MOV A,B

;现在A里面就是键值,你可以按要求转移到想去的位置。

DELAY:

MOV R2,#20

DELAY1:

MOV R3,#250

DJNZ R3,$

DJNZ R2,DELAY1

RET

END

代码很好写,但是关键是你的数码管属于硬件

也就是说,至少要知道 *** 作你数码管的API才行啊。

或者说要怎样传送数据给你的数码管,你的数码管需要接受怎样的数据。

键盘扫描很简单,给你个代码。

要求引用头文件

#include <iostream>

using namespace std;

#include <conioh>//kbhit API头文件

#include <timeh>

#include <windowsh>

#define ESC 0x1b

void loop()

{

int i;

if( kbhit() ) //判断是否有键盘按键按下。

{

char ch;

ch = getch(); //获取按下的键值

if( ESC == ch )//判断是否是你要的键,我以ESC为例

{

cout<<"ESC"<<endl;

system("pause");

}

}

while( !kbhit() )//没有按键是的 *** 作

{

balabalabala

}

}

int main()

{

loop();

}

0x10折成二进制是00010000,高四位是列,那么程序就是逐列扫描的了,这是从最低列扫起,用它作为掩码,只留下一位。

P1 = 0xf0; // 发全0行扫描码,这句就是让所有的列先置高,行置低,是初始值,建议你把电路图对着看,可以在脑子里假设一个钮按下的状态再分析程序。

if ((P1&0xf0)!=0xf0) // 若有键按下,这句如果为真,就说明至少有一列中有键按下了,但是它是区别不出来是哪一列的,只能证明有键按下,当然就更分不出来是哪行了。

scancode = 0xfe; //这句是给扫描码置一个初值,0xfe就是二进制的11111110,接着看后边。

while((scancode&0x10)!=0) // 逐行扫描,刚才说过,这个0x10就是二进制的00010000,和扫描码11111110做与之后留下00010000,那么这时如果在最低列中有键按下,表达式就为假了,没有键按下时才会为真,也就是继续扫描。这种方式不能处理多个键按下的情形,会低位优先,因为一旦有键按下了就不再扫后边的了。而此时注意scancode本身中是行的值。

P1 = scancode; // 输出行扫描码,注意扫描码中的值并未改变,是11111110。

if ((P1&0xf0)!=0xf0) // 本行有键按下,这个判断中对P1做与,如果没有键按下,那么P1应该是和scancode中的值一样的,和0xf0做与之后就是留下高四位得到11110000,一旦有按下的键,相应的位会被拉低,肯定就不等于11110000了,比如说11100000,那么表达式就为真了。

tmpcode = (P1&0xf0)|0x0f; //这句将P1与上的值与0x0f做或运算,得到低4位为全1的列扫描码。

return((~scancode)+(~tmpcode)); //由于其它的位都被填了1,每次招描的结果都只有1个0,取反输出就得到了只有一个1的码。

else scancode = (scancode<<1)|0x01; // 行扫描码左移一位,这样就是将scancode中的11111110变成11111100,而且还要或上0x01保持最低位被补1变成11111101,依次后边会变成11111011和11110111,完成四个行的扫描。

重复上述过程完成所有的扫描。

C51 P1端口 4X4键盘说明

这是一个用C51单片机P1端口制作的4X4键盘,p1端口低4位是键盘列扫描线,高4位是键盘行扫描线,

列扫描线是输出,行扫描线是输入。

下面就程序作一个说明

()表示注意点

1、首先判断整个键盘有无按下键,只要行扫描线输入不为全1,(1111)即有键按下;

P1 = 0xf0;if((P1&0xf0)!=0xf0) 如果无按键按下,全1,则返回return -1;

如果有键按下则延时,再次判断有无按键按下,Delay();if((P1&0xf0)!=0xf0)如果无按键按下则返回return -1。

有键按下则继续,这个过程就是判键消抖,避免多次读键值,或者因为按键抖动到读键值的时候无键按下,发生错误,列扫描线是输出全0,P1 = 0xf0。

2、进入读键值了,与上面不同,每一次判断,列扫描线只有一根输出为0,即P1=0xfe,0xfd,0xfb,0xf7;

首先列扫描线P10,sCode = 0xfe;如果行扫描线全1,则本列无键按下,扫描下一列

sCode = _crol_(sCode,1); sCode左移一位,即0xfd,如此扫描4次,行扫描线都全0,则无键按下,

返回return -1;

如果行扫描线不全0,就是有键按下,现在可以读键值了

kCode = ~P1; //P1=EE,ED

for(i=0;i<16;i++)

{

if(kCode == KeyCodeTable[i])

return i;

}

1首先kCode = ~P1;p1值取反行扫描线可能的是1,2,4,8;同样列扫描线对应值1,2,4,8

合起p1有16个值,就是KeyCodeTable[i]表的x11,0x12,0x14,0x18,0x21,0x22,0x24,0x28,

0x41,0x42,0x44,0x48,0x81,0x82,0x84,0x88

如果 if(kCode == KeyCodeTable[i]) 成立,对应的 i 值就是键号。

2返回i值就是键号,return i;。

uchar Keys_Scan()

{

uchar sCode,kCode,i,k;

P1 = 0xf0;

if((P1&0xf0)!=0xf0) //扫描列

{

Delay();

if((P1&0xf0)!=0xf0)//消抖

{

sCode = 0xfe;

for(k=0;k<4;k++)

{

P1 = sCode;//查找低位

if((P1&0xf0)!=0xf0)//只有等于才执行else P1和0xf0作与为0xf0 与 同真为真,一假为假

{

kCode = ~P1; //P1=EE,ED

for(i=0;i<16;i++)

{

if(kCode == KeyCodeTable[i])

return i;

}

}

else

sCode = _crol_(sCode,1);

}

}

}

return -1;

}

以上就是关于单片机键盘扫描程序全部的内容,包括:单片机键盘扫描程序、朋友们帮忙写个51单片机的按键小程序汇编的、用汇编语言 用独立式键盘扫描 消抖等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/zz/10131563.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-05
下一篇2023-05-05

发表评论

登录后才能评论

评论列表(0条)

    保存