单片机之矩阵按键状态机篇
0赞有网友在网络教室下的课程讨论中提问:矩阵键盘如果用状态机的方法来写,是不是每一个按键都要用到这四种状态?
我的回答是:肯定不是了,那样会累死人,呵呵。
准备下面直接加入附件,但是不好加,那就写一篇博客,具体源码如下:
/* ***************************************************** */
// 工 程 : 飞天开发板(MGMC-V2.0)
// 文件名 : MatrixKeyMain.c
// 处理器 : STC89C52RC
// 编译环境 : Keil4 C51
// 系统时钟 : 11.0592MHZ
// 版 本 : V1.0
// 生成日期 : 2014-02-25
// 修改日期 :
// 简单描述 : 本文件是状态机实现矩阵按键扫描程序
/* ***************************************************** */
#include <reg52.h>
/* ***************************************************** */
// 宏定义
/* ***************************************************** */
#define uInt16 unsigned int
#define uChar8 unsigned char
#define DATA P0 //数据口
#define KEYPORT P3 //键盘接入端口
#define NOKEY 255 //无键值标志
#define KEYMASK 0x0f //
/* ***************************************************** */
// 位定义
/* ***************************************************** */
sbit SEG_SELECT = P1^7; //段选控制端
sbit BIT_SELECT = P1^6; //位选控制端
/* ***************************************************** */
// 数组定义
/* ***************************************************** */
uChar8 code SEG_Tab[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00};//段选显示表格
/* ***************************************************** */
// 全局变量定义
/* ***************************************************** */
uChar8 g_ucKeyNum = 16; //键值
uChar8 TimeCount = 0; //时间计数
bit TimeOK; //5ms时间到标志
/* ***************************************************** */
// 函数名称:ScanKey()
// 函数功能:矩阵按键扫描
// 入口参数:无
// 出口参数:无
/* ***************************************************** */
uChar8 ScanKey(void)
{
static uChar8 KeyState = 0; //按键状态
static uChar8 KeyValue; //临时键值
static uChar8 KeyLine; //按键行值
uChar8 KeyReturn = NOKEY; //键值返回变量
uChar8 i; //循环变量
switch(KeyState) //状态判断
{
case 0: //初始状态
KeyLine = 0x10;
for (i = 1;i <= 4;i++)
{
P3 = ~KeyLine; //第一行送低电平
P3 = ~KeyLine;
KeyValue = KEYMASK & P3; //读取P3口列值
if (KeyValue == KEYMASK)
{
KeyLine <<= 1;
}
else
{
KeyState++;
break;
}
}
break;
case 1: //确认状态
if (KeyValue == (KEYMASK & P3))
{
switch(KeyLine | KeyValue)
{
case 0x87:KeyReturn = 15;break;
case 0x8b:KeyReturn = 11;break;
case 0x8d:KeyReturn = 7;break;
case 0x8e:KeyReturn = 3;break;
case 0x47:KeyReturn = 14;break;
case 0x4b:KeyReturn = 10;break;
case 0x4d:KeyReturn = 6;break;
case 0x4e:KeyReturn = 2;break;
case 0x27:KeyReturn = 13;break;
case 0x2b:KeyReturn = 9;break;
case 0x2d:KeyReturn = 5;break;
case 0x2e:KeyReturn = 1;break;
case 0x17:KeyReturn = 12;break;
case 0x1b:KeyReturn = 8;break;
case 0x1d:KeyReturn = 4;break;
case 0x1e:KeyReturn = 0;break;
}
KeyState++;
}
else
KeyState--;
break;
case 2: //完成态
P3 = 0x0f;
P3 = 0x0f;
if((KEYMASK & P3) == KEYMASK)
{
KeyState = 0;
}
break;
}
return KeyReturn;
}
/* ***************************************************** */
// 函数名称:Display()
// 函数功能:数码管刷新
// 入口参数:需显示的数字(ucVal)
// 出口参数:无
/* ***************************************************** */
void Display(uChar8 ucVal)
{
BIT_SELECT = 1;
DATA = 0x00;
BIT_SELECT = 0;
SEG_SELECT = 1;
DATA = SEG_Tab[ucVal];
SEG_SELECT = 0;
DATA = 0x00;
}
/* ***************************************************** */
// 函数名称:Timer0Init()
// 函数功能:
// 入口参数:无
// 出口参数:无
/* ***************************************************** */
void Timer0Init(void)
{
TMOD = 0x01;
TH0 = 0xFC;
TL0 = 0x66; //1ms计时
EA = 1;
ET0 = 1;
TR0 = 1;
}
/* ***************************************************** */
// 函数名称:main()
// 函数功能:扫描键值并显示键值
// 入口参数:无
// 出口参数:无
/* ***************************************************** */
void main(void)
{
uChar8 KeyTemp; //临时存放键值变量
Timer0Init();
while(1)
{
if (TimeOK)
{
KeyTemp = ScanKey();
if (KeyTemp != NOKEY)
{
g_ucKeyNum = KeyTemp;
}
}
}
}
/* ***************************************************** */
// 函数名称:Timer0_ISR()
// 函数功能:定时器0中断服务
// 入口参数:无
// 出口参数:无
/* ***************************************************** */
void Timer0_ISR(void) interrupt 1
{
TH0 = 0xFC;
TL0 = 0x66;
Display(g_ucKeyNum);
if(TimeCount >= 5)
{
TimeCount = 0;
TimeOK = 1;
}
else TimeCount++;
}
========= 残弈悟恩 ===========
