矩阵键盘扫描的C语言实例.docx
《矩阵键盘扫描的C语言实例.docx》由会员分享,可在线阅读,更多相关《矩阵键盘扫描的C语言实例.docx(18页珍藏版)》请在冰点文库上搜索。
矩阵键盘扫描的C语言实例
矩阵键盘扫描的C语言实例
1、按键扫描(线反转)
//--------------------------------------------------------------------------------------------------
//函数名称:
program_SCANkey
//函数功能:
程序扫描键盘,
//有键按下完成按键处理,无键按下直接返回
//--------------------------------------------------------------------------------------------------
voidprogram_SCANkey()
{
unsignedcharkey_code;
if(judge_hitkey())//判断是否有键按下
{
delay(1000);//延时20ms左右,消除抖动干扰
if(judge_hitkey())//判断是否有效按键
{
key_code=scan_key();//获取键值
while(judge_hitkey());//等待按键释放
{
}
key_manage(key_code);//键盘扫描、键盘散转、按键处理
}
}
}
//--------------------------------------------------------------------------------------------------
//函数名称:
judge_hitkey
//函数功能:
//判断是否有键按下,有返回1,没有返回0
//列判断,还可以用行判断。
//--------------------------------------------------------------------------------------------------
bitjudge_hitkey()//判断是否有键按下,有返回1,没有返回0
{
unsignedcharscancode,keycode;
scancode=0x0F;//开始设定P1.0~P1.3输出全1(初值)即表明无键闭合
KEY=scancode;
keycode=KEY;//读取P1.0~P1.3的真实状态,从而确定有没有键被按下
if(keycode==0x0F)
return(0);//全1则无键闭合
else
return
(1);//否则有键闭合
}
//--------------------------------------------------------------------------------------------------
//函数名称:
scan_key
//函数功能:
//扫描键盘,返回键值(高四位代表行,低四位代表列)
//说明:
scancode扫描码,keycode键值,keycode_line行,keycode_row列
//过程:
先扫描行,确定那行的按键被按下。
再扫描列,确定那列的按键被按下,从而确定那个按键被按下。
//--------------------------------------------------------------------------------------------------
unsignedcharscan_key()//扫描键盘,返回键值(高四位代表行,低四位代表列)
{
unsignedcharscancode,keycode,keycode_line,keycode_row;
scancode=0xF0;//列置低,行置高
KEY=scancode;//输入扫描码,扫描行
keycode_line=KEY;//KEY的值是与键盘相连的P的状态值。
若没有按键按下KEY的值为0xF0,若有按键按下则KEY的值就不是0xF0
scancode=0x0F;//列置高,行置低
KEY=scancode;//输入扫描码,扫描列
keycode_row=KEY;//KEY的值是与键盘相连的P的状态值。
若没有按键按下KEY的值为0x0F,若有按键按下则KEY的值就不是0x0F
keycode=((keycode_line&0xF0)|(keycode_row&0x0F));
return(keycode);
}
2、按键扫描(逐行扫描)
//--------------------------------------------------------------------------------------------------
//函数名称:
kbscan键盘扫描子程序
//函数功能:
判断是否有键按下,有返回键值,没有返回0
//p1的高四位为列,低四位为行P1.7P1.6P1.5P1.4P1.3P1.2P1.1P1.0
//列4列3列2列1行4行3行2行1
//过程:
先根据列判断是否有键按下,没有返回0,有,则逐行扫描以确定按键所在的行,再确定按键所在列
//从而最终确定该按键。
//--------------------------------------------------------------------------------------------------
ucharkbscan(void)
{
ucharsccode,recode;
P1=0xf0;//置所有行为低电平,行扫描,列线输入(此时)
if((P1&0xf0)!
=0xf0)//判断是否有有键按下(读取列的真实状态,若第4列有键按下则P1的值会变成01110000),有往下执行
{
delays();//延时去抖动(10ms)
if((P1&0xf0)!
=0xf0)//再次判断列中是否是干扰信号,不是则向下执行
{
sccode=0xFE;//逐行扫描初值(即先扫描第1行)
while((sccode&0x10)!
=0)//行扫描完成时(即4行已经全部扫描完成)sccode为11101111停止while程序
{
P1=sccode;//输出行扫描码
if((P1&0xf0)!
=0xf0)//本行有键按下(即P1(真实的状态)的高四位不全为1)
{
recode=(P1&0xf0)|0x0f;//列
return(sccode&recode);//返回行和列
}
else//所扫描的行没有键按下,则扫描下一行,直到4行都扫描,此时sccode值为11101111退出while程序
{
sccode=(sccode<<1)|0x01;//行扫描码左移一位
}
}
}
}
else
{
return0;//无键按下,返回0
}
}
--------------------------------------------------------------------------------------------------------------------------
/*Main.c*/
#include"global.c"
voidSystemInit();
voidTimer1Init();
voidKickDog();
voiddelay();
unsignedintjudge_key();
unsignedintscan_key();
unsignedcharnumkey=0;
unsignedcharDATX,DATY;
main()
{
SystemInit();//系统初始化
MCRA=MCRA&0x80FF;//IOPB0-6设为IO口模式
PBDATDIR=0xBFC2;//所有LED=0,并置IOPB6为输入口
Timer1Init();//定时器初始化
asm("CLRCINTM");
while
(1)
{
//KeyLed();
if(judge_key()==1)
numkey++;
}
}
voidSystemInit()
{
asm("SETCINTM");/*关闭总中断*/
asm("CLRCSXM");/*禁止符号位扩展*/
asm("CLRCCNF");/*B0块映射为on-chipDARAM*/
asm("CLRCOVM");/*累加器结果正常溢出*/
SCSR1=0x83FE;/*系统时钟CLKOUT=20*2=40M*/
WDCR=0x006F;/*禁止看门狗,看门狗时钟64分频*/
KickDog();/*初始化看门狗*/
IFR=0xFFFF;/*清除中断标志*/
IMR=0x0002;/*打开中断2*/
}
voidTimer1Init()
{
EVAIMRA=0x0080;//定时器1周期中断使能
EVAIFRA=0xFFFF;//清除中断标志
GPTCONA=0x0000;
T1PR=2500;//定时器1初值,定时0.4us*2500=1ms
T1CNT=0;
T1CON=0x144E;//增模式,TPS系数40M/16=2.5M,T1使能
}
unsignedintjudge_key()
{
MCRC=MCRC&0x81FF;//
PFDATDIR=PFDATDIR|0x0070;
PFDATDIR=PFDATDIR&0x8FFF;//设置456输入高
PFDATDIR=PFDATDIR&0xFFF1;
PFDATDIR=PFDATDIR|0x0E00;//设置123输出低
if((PFDATDIR&0x0070)==0x0070)
return(0);
else
return
(1);
}
unsignedintscan_key()
{
if(judge_key()==1)
delay();
if(judge_key()==1)
{
MCRC=MCRC&0x81FF;//
PFDATDIR=PFDATDIR|0x0070;
PFDATDIR=PFDATDIR&0x8FFF;//设置456输入高
PFDATDIR=PFDATDIR&0xFFF1;
PFDATDIR=PFDATDIR|0x0E00;//设置123输出低
delay();
numkey=((PFDATDIR&0x0070)|(PFDATDIR&0x000E));
//delay();
//MCRC=MCRC&0x81FF;//
PFDATDIR=PFDATDIR&0xFF8F;//设置456输出低
PFDATDIR=PFDATDIR|0xE000;
PFDATDIR=PFDATDIR|0x000E;//设置123输入高
PFDATDIR=PFDATDIR&0xF1FF;
delay();
//numkey=((PFDATDIR&0x0070)|(PFDATDIR&0x000E));
numkey=numkey|(PFDATDIR&0x000E);
return(numkey);
}
}
voidc_int2()/*定时器1中断服务程序*/
{
if(PIVR!
=0x27)
{asm("CLRCINTM");
return;
}
scan_key();
EVAIFRA=EVAIFRA&0x80;
asm("CLRCINTM");
}
voiddelay()
{
inti;
for(i=0;i<10000;i++);
}
voidKickDog()/*踢除看门狗*/
{
WDKEY=0x5555;
WDKEY=0xAAAA;
}
矩阵键盘扫描程序集锦
2009-08-1811:
24
初学者写的最简单矩阵键盘扫描程序
这是站长初学者写的最简单、最详细、效率最高的矩阵键盘扫描程序,只用了四条常用命令(MOV/送数、JB/高电平转移、JMP/直接转移、RET/子程序返回),保证初学者一看就懂!
本程序已经在本站电子实验板上验证通过,占用CPU时间少,效率高,被选作单片机的测试程序!
矩阵按键扫描程序是一种节省IO口的方法,按键数目越多节省IO口就越可观,本程序的思路跟书上一样:
先判断某一列(行)是否有按键按下,再判断该行(列)是那一只键按下。
但是,在程序的写法上,站长采用了最简单的方法,使得程序效率最高。
本程序中,如果检测到某键按下了,就不再检测其它的按键,这完全能满足绝大多数需要,又能节省大量的CPU时间。
另外,本人认为键盘用延时程序来消除抖动,完全是浪费时间。
试想,如果不用中断执行(用中断执行需要更多的硬件资源)的方法来扫描键盘,每秒钟扫描20-100次,每次都要延时10-20MS的话,我们的单片机还有多少时间做正事呢?
其实,延时的这段时间,CPU可以做其它的事呀。
所以,本键盘扫描程序的前面后面都可以加入少少代码,既可以达到完美的消抖动效果,又可以扩展其它的功能(例如按键封锁、按键长按等按键功能复用!
)
本键盘扫描子程序名叫key,每次要扫描时用callkey调用即可。
以下子程序内容:
key:
movp0,#00001111b;上四位和下四位分别为行和列,所以送出高低电压检查有没有按键按下
jmpk10;跳到K10处开始扫描,这里可以改成其它条件转移指令来决定本次扫描是否要继续,例如减1为0转移或者位为1或0才转移,这主要用来增加功能,确认上一按键功能是否完成?
是否相当于经过了延时?
是否要封锁键盘?
goend:
jmpkend;如果上面判断本次不执行键盘扫描程序,则立即转到程序尾部,不要浪费CPU的时间
k10:
jbp0.0,k20;扫描正式开始,先检查列1四个键是否有键按下,如果没有,则跳到K20检查列2
k11:
movp0,#11101111b;列1有键按下时,P0.0变低,到底是那一个键按下?
现在分别输出各行低电平
jbp0.0,k12;该行的键不按下时,p0.0为高电平,跳到到K12,检查其它的行
movr1,#1;如果正好是这行的键按下,将寄存器R0写下1,表示1号键按下了
k12:
movp0,#11011111b
jbp0.0,k13
movr1,#2;如果正好是这行的键按下,将寄存器R0写下2,表示2号键按下了
k13:
movp0,#10111111b
jbp0.0,k14
movr1,#3;如果正好是这行的键按下,将寄存器R0写下3,表示3号键按下了
k14:
movp0,#01111111b
jbp0.0,kend;如果现在四个键都没有按下,可能按键松开或干扰,退出扫描(以后相同)
movr1,#4如果正好是这行的键按下,将寄存器R0写下4,表示4号键按下了
jmpkend;已经找到按下的键,跳到结尾吧
k20:
jbp0.1,k30;列2检查为高电平再检查列3、4
k21:
movp0,#11101111b;列2有健按下时,P0.0会变低,到底是那一行的键按下呢?
分别输出行的低电平
jbp0.1,k22;该行的键不按下时p0.0为高电平,跳到到K22,检查另外三行
movr1,#5;如果正好是这行的键按下,将寄存器R0写下5,表示5号键按下了(以后相同,不再重复了)
k22:
movp0,#11011111b
jbp0.1,k23
movr1,#6
k23:
movp0,#10111111b
jbp0.1,k24
movr1,#7
k24:
movp0,#01111111b
jbp0.1,kend
movr1,#8
jmpkend;已经找到按下的键,跳到结尾吧(以后相同,不要重复了)
k30:
jbp0.2,k40
k31:
movp0,#11101111b
jbp0.2,k32
movr1,#9
k32:
movp0,#11011111b
jbp0.2,k33
movr1,#10
k33:
movp0,#10111111b
jbp0.2,k34
movr1,#11
k34:
movp0,#01111111b
jbp0.2,kend
movr1,#12
jmpkend
k40:
jbp0.3,kend
k41:
movp0,#11101111b
jbp0.3,k42
movr1,#13
k42:
movp0,#11011111b
jbp0.3,k43
movr1,#14
k43:
movp0,#10111111b
jbp0.3,k44
movr1,#15
k44:
movp0,#01111111b
jbp0.3,kend
movr1,#16
kend:
ret
键盘扫描结束了,寄存器R1的值就直接表示了是那个键按下的,根据不同的键值去执行不同的程序,从而实现了十六个矩阵键盘扫描,同样原理,最多可以识别255个按键的矩阵扫描。
我们可以每次键盘扫描开始时检查R0的值是否为0,只有在为0才扫描键盘,不为0就证明刚刚扫描过键值,相应的按键工作还没有完成。
但是必须记得,每个按键命令执行完成后,要给R0写上0,表示可以扫描键盘。
本键盘扫描程序的优点在于:
不用专门的按键延时程序,提高了CPU效率,也不用中断来扫描键盘,节省了硬件资源。
另外,本键盘扫描程序,每次扫描占用CPU时最短,不论有键按下或者无键按下都可以在很短的时间完成一次扫描。
还有,本程序只使用几条最常用的汇编命令,MOV/JB/JMP/RET,而这几条命令是最常用、最易懂、最好学的命令!
有的键盘扫描程序还用与呀、或呀、移位呀、查表呀,我都还没有看懂。
当然,以上只是站长初学单片机的一点个人见解,欢迎广大单片机爱好者指正,希望大家将自己最认可的键盘扫描程序公布出来,让大家一起分享!
最后,五一电子祝愿大家学习进步!
工作顺利!
说明:
本站数显FM无线发射板中虽然不是用矩阵扫描,但是按键消抖动原理和上面相同,按键功能复用原理也和上面相同,用起来感觉很好!
在键盘的10MS延时过程中,CPU刚好可以去做几件事并在10MS左右做完。
所以,产品中凡是要用到按键扫描的,都可以让CPU去做别的事情,键盘延时消抖动唯一的好处就是,程序写起来会方便一点。
来自---------
4*4矩阵键盘扫描汇编程序(基于51单片机)
;//======================================================================
;//
;// 程序名称:
4-4keyscan.asm
;// 程序用途:
4*4矩阵键盘扫描检测
;// 功能描述:
扫描键盘,确定按键值。
程序不支持双键同时按下,
;// 如果发生双键同时按下时,程序将只识别其中先扫描的按键
;// 程序入口:
void
;// 程序出口:
KEYNAME,包含按键信息、按键有效信息、当前按键状态
;// 编写人:
黄伟,2007-12-11
;// 最后修改:
黄伟,2007-12-12
;//
;//======================================================================
PROC KEYCHK
KEYNAME DATA 40H ;按键名称存储单元
;(b7-b5纪录按键状态,b4位为有效位,
;b3-b0纪录按键)
KEYRTIME DATA 43H ;重复按键时间间隔
SIGNAL DATA 50H ;提示信号时间存储单元
KEY EQU P3 ;键盘接口(必须完整I/O口)
KEYPL EQU P0.6 ;指示灯接口
RTIME EQU 30 ;重复按键输入等待时间
KEYCHK:
;//=============按键检测程序=============================================
MOV KEY,#0FH ;送扫描信号
MOV A,KEY ;读按键状态
CJNE A,#0FH,NEXT1 ;ACC<=0FH
; CLR C ;Acc等于0FH,则CY为0,无须置0
NEXT1:
; SETB C ;Acc不等于0FH,则ACC必小于0FH,
;CY为1,无须置1
MOV A,KEYNAME
ANL KEYNAME,#1FH ;按键名称屏蔽高三位
RRC A ;ACC带CY右移一位,纪录当前按键状态
ANL A,#0E0H ;屏蔽低五位
ORL KEYNAME,A ;保留按键状态
;//=============判别按键状态,决定是否执行按键扫描========================
CJNE A,#0C0H,NEXT2 ;110按键稳定闭合,调用按键检测子程序
SJMP KEYSCAN
NEXT2:
CJNE A,#0E0H,NEXT3 ;111按键长闭合,重复输入允许判断
SJMP WAIT
NEXT3:
CJNE A,#0A0H,EXIT