残弈悟恩

单片机之矩阵按键状态机篇

0
阅读(6114)

有网友在网络教室下的课程讨论中提问:矩阵键盘如果用状态机的方法来写,是不是每一个按键都要用到这四种状态?

我的回答是:肯定不是了,那样会累死人,呵呵。

准备下面直接加入附件,但是不好加,那就写一篇博客,具体源码如下:

/* ***************************************************** */
// 工  程   : 飞天开发板(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++;        
}
 ========= 残弈悟恩 ===========