请先阅读上篇:
短按,长按,按键释放,三种模式的按键扫描程序(软件消抖动)
上面的程序适用于单个按键,那是不是也可以适用于矩阵键盘呢?
答案是肯定的。
接下来在这里做一个简单的扩展,具体框架不用改变,所以具体的框架内容和思路在这里不详述了,自行参考上篇文章,这里就说说扩展矩阵键盘的需要改动的地方。
重点:
对于此按键盘函数的框架来说,其实单个按键与矩阵键盘程序的差别仅仅在于读取按键的方式不同。所以这里的程序只需要更改读取按键值的部分即可。
1.单个按键的读取按键值程序
CurrReadKey = P0 & 0x00ff; //获取当前的键值
2.矩阵键盘的读取按键值程序
这里以4*4键盘为例
原理图如下:
将原理图中的P1看成是P0(由于赖所以直接从度娘那里盗的图),下面程序是以P0为例。
//读取按键的行数
P0 = 0xf0;
KeyRow = P0;
//读取按键的列数
P0 = 0x0f;
KeyColumn = P0;
//读取行列数,就是当前键值了
CurrReadKey = Key_Row|Key_Column;
3.只需要将单个按键的读取键值程序改为矩阵键盘的读取键值的程序即可,程序如下:
KeyScan.c文件如下:
//======================================================
//KeyScan.c
//======================================================
//注意:该宏定义,定义在keyscan.h文件中
//#define KEYDEBOUNCE 0x05 //消抖动,按键扫描次数。如果连续5次都是扫描的都是相同键值,则认为是有效键值,否则是误触发
unsigned int g_uiCurrKey; //当前按键值
unsigned int g_uiLastKey; //上次按键值
unsigned int g_uiKeyScanCount; //按键扫描计数,作用:消抖动
unsigned int g_uiKeyDown; //键被按下,返回的键值。 作用:单次按键,单次返回有效键值;按住不放,也只返回被按下的一个键值
unsigned int g_uiKeyRelease; //键被释放后,返回的键值。 作用:只有按下的按键被释放后,才返回按下的键值
unsigned int g_uiKeyContinue; //键连续按键,重复返回的键值。 作用:只要按住不放,就会重复地返回相同键值
//P0口的低八位作为按键
//没有按键时,返回的是0xff,
void Int_Key_Scan(void)
{
static unsigned short LastReadKey; //上次从IO口读取的键值 ,注意是静态变量
unsigned short CurrReadKey; //当前从IO口读取的键值
//---------------------- 需要修改的地方 --------------------------------------//
unsigned short KeyRow,KeyColumn;
//读取按键的行数
P0 = 0xf0;
KeyRow = P0;
//读取按键的列数
P0 = 0x0f;
KeyColumn = P0;
//读取行列数,就是当前键值了
CurrReadKey = Key_Row|Key_Column; //获取当前的键值
//-----------------------------------------------------------------------//
if(CurrReadKey == LastReadKey) //如果当前读取的键值与上次从IO口读取的键值相同
{
if(g_uiKeyScanCount >= KEYDEBOUNCE) //首先判断是否大于等于debounce的设定值(即是,是否大于等于设定的采样次数)
{
//按住不放,多次响应
g_uiCurrKey = CurrReadKey; //如果是,将当前的读取值判定为有效按键值(如果是,在采样周期中,都是这个值,则判定为有效按键值)
//按住不放只响应一次
if(g_uiPreKeyValue == g_uiCurrKey)
{
g_uiKeyDown = 0xff; //没有键值
}
else
{
g_uiKeyDown = g_uiCurrKey; //如果不同,按键有效,(就是第一次有效值时)
}
//按键释放时,按键值才有效
if(g_uiCurrKey == 0xff) //当有效按键值从非0到0的状态时(即是,从有按键到无按键,表示已经释放了),表示之前按键已经释放了
{
g_uiKeyRelease = g_uiPreKeyValue;
}
g_uiLastKey = g_uiCurrKey; //记录上次有效按键值
}
else //如果否,则debounce加一(如果否,则继续采样键值)
{
g_uiKeyScanCount++;
}
}
else //如果当前读取的键值与上次从IO口读取的键值不同,说明按键已经变化
{
g_uiKeyDown = 0xff; //放开按键后第一次进入扫描程序,清零g_uiKeyDown.作用:消除一个BUG(你猜BUG是什么?)
g_uiKeyScanCount = 0; //清零之前的按键的debounce计数
LastReadKey = CurrReadKey; //将当前读取的键值记录为上次读取的按键值
}
}
KeyScan.h文件如下:
//======================================================
//KeyScan.h
//======================================================
//宏定义
#define KEYDEBOUNCE 0x05 //消抖动,按键扫描次数。如果连续5次都是扫描的都是相同键值,则认为是有效键值,否则是误触发
//声明变量
extern unsigned int g_uiCurrKey; //当前按键值
extern unsigned int g_uiLastKey; //上次按键值
extern unsigned int g_uiKeyScanCount; //按键扫描计数,作用:消抖动
extern unsigned int g_uiKeyDown; //键被按下,返回的键值。 作用:单次按键,单次返回有效键值;按住不放,也只返回被按下的一个键值
extern unsigned int g_uiKeyRelease; //键被释放后,返回的键值。 作用:只有按下的按键被释放后,才返回按下的键值
extern unsigned int g_uiKeyContinue; //键连续按键,重复返回的键值。 作用:只要按住不放,就会重复地返回相同键值
//函数声明
void Int_Key_Scan(void);
4.实例程序
这里就以单次按键有效为例,按键释放有效与长按多次有效 写法一样。
仅仅修改switch中的case值即可。
main.c如下所示:
//======================================================
//main.c
//======================================================
#include "reg51.h"
#include "KeyScan.h"
sbit LED = P1.0; //定义LEDIO口
void main(void)
{
P0 = 0xff;
LED = 0; //点亮LED
while(1)
{
Int_Key_Scan(); //按键扫描程序
//第一种:KeyDown的使
//单按时和长按时,都只返回一次有效键值(无需等到按键释放,就可以返回有效键值)
switch(g_uiKeyDown)
{
case 0xEE:
//P0.0按键程序
LED = !LED;
break;
case 0xED:
//P0.1按键程序
//...
break;
case 0xEB:
//P0.2按键程序
//...
break;
case 0xE7:
break;
case 0xDE:
break;
case 0xDD:
break;
case 0xDB:
break;
case 0xD7:
break;
case 0xBE:
break;
case 0xBD:
break;
case 0xBB:
break;
case 0xB7:
break;
case 0x7E:
break;
case 0x7D:
break;
case 0x7B:
break;
case 0x77:
break;
case 0xFF:
//没有按键程序
//...
break;
}
}
}
Pillar Peng
Friday, February 26, 2016 11:48
友情链接: