C51联盟 —— 矩阵键盘

版权声明: https://blog.csdn.net/JRK_CSDN/article/details/87444489

需要理解

Q:

  • 按键消抖时间在20ms左右
  • CLK为12MHz的51单片机的指令周期大约是2us(1ms约可执行500条指令)(意在说明不影响程序正常运行,例如数码管刷新效果可以维持下去)

S:

  • 用定时器产生1ms中断,维持键盘“实时”扫描
  • 沿用 行列扫描 的思维,形成扫描循环(即 释放当前输出引脚,拉低下次的输出引脚)

U:

  • 一个定时器中断
  • 8个I/O接口
  • 约5ms的执行时间

A:

## Config ##

## 注意:该驱动扫描为行索引,即每次扫描 一行 ,每 1ms 扫描一次
	全键盘4ms扫描完成,按键经4次(即 16ms)确认后判为按下(KeySta变为0,触发KeyAction)
	回弹后,16ms恢复状态(KeySta变为1)

KEY_OUT_1 = P*^*;	//扫描输出
KEY_OUT_2 = P*^*;
KEY_OUT_3 = P*^*;
KEY_OUT_4 = P*^*;

KEY_IN_1 = P*^*;	//扫描输入
KEY_IN_2 = P*^*;
KEY_IN_3 = P*^*;
KEY_IN_4 = P*^*;

//“实时”状态缓冲区
u8 KeySta[4][4] = {  {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}  };
 		
u8 code KeyCodeMap[4][4] = {
 {'1', '2', '3', 0x19},
 {'4', '5', '6', 0x18},
 {'7', '8', '9', 0x17},
 {'0', 0x1B,0x0D,0x16}
};   //''为字符,标准ASCII码,'1'即为0x31,两种写法均可
void KeyScan()		//在定时器中断中调用,达到1ms扫描一列
{
  
  u8 i;
  static u8 keyout = 0;	
  static u8 key_buff[4][4] = {	
   {0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF},
   {0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF}
  };	//需要扫描4次,也就是4次移位:0XFF → 0XFE → 0XFC → 0XF8 → 0XF0

switch(keyout)		//释放输出引脚,拉低下一扫描输出引脚(推荐先释放,毕竟是规范)
 {
  case 0: KEY_OUT_4 = 1; KEY_OUT_1 = 0; break;
  case 1: KEY_OUT_1 = 1; KEY_OUT_2 = 0; break;
  case 2: KEY_OUT_2 = 1; KEY_OUT_3 = 0; break;
  case 3: KEY_OUT_3 = 1; KEY_OUT_4 = 0; break;
  default: break;
 }

 key_buff[keyout][0] = (key_buff[keyout][0] << 1) | KEY_IN_1;
 key_buff[keyout][1] = (key_buff[keyout][1] << 1) | KEY_IN_2;
 key_buff[keyout][2] = (key_buff[keyout][2] << 1) | KEY_IN_3;
 key_buff[keyout][3] = (key_buff[keyout][3] << 1) | KEY_IN_4;

 for (i=0; i<4; i++)  //每行4个按键,所以循环4次
 {
    if ((key_buf[keyout][i] & 0x0F) == 0x00)	//低电平优先,为0即为按下
     {   //连续4次扫描值为0,即4*4ms内都是按下状态时,可认为按键已稳定的按下
            Key_Sta[keyout][i] = 0;
     }
    else if ((key_buf[keyout][i] & 0x0F) == 0x0F)
     {   //连续4次扫描值为1,即4*4ms内都是弹起状态时,可认为按键已稳定的弹起
            Key_Sta[keyout][i] = 1;
     }
 }

 keyout++;                //输出索引递增
 keyout = keyout & 0x03;  //索引值加到4即归零
void KeyDriver()	//主循环调用
{
  
  u8 i, j;
  static u8 backup[4][4] = {  {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}  };	
  //数电-锁存器思维,保存上一状态进行比较
  
  for(i=0; i<4; i++)
  {
     for(j=0; j<4; j++)
     {
     	if(backup[i][j] != KeySta[i][j])
    	  {
      		if(backup[i][j] != 0)
      		{
       	 	  KeyAction(KeyCodeMap[i][j]);	//动作函数,暂未定义
      		}
    	  }
    	backup[i][j] = KeySta[i][j];
     }
  } 
} 

猜你喜欢

转载自blog.csdn.net/JRK_CSDN/article/details/87444489
C51