#include <reg52.h> typedef unsigned char uint8_t; sbit keyRow0 = P3^0; sbit keyRow1 = P3^1; sbit keyRow2 = P3^2; sbit keyRow3 = P3^3; sbit keyCol0 = P3^7; sbit keyCol1 = P3^6; sbit keyCol2 = P3^5; sbit keyCol3 = P3^4; code uint8_t keyNo[4][4] = { {7, 11, 15, 19}, {6, 10, 14, 18}, {5, 9, 13, 17}, {4, 8, 12, 16} }; pdata uint8_t keyState[4][4] = { //全部矩阵按键的当前状态 {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1} }; extern void keyAction(uint8_t keyCode); void keyDriver() { //在主循环中调用 uint8_t i, j; static uint8_t 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 (keyState[i][j] != backup[i][j]) { //如果这个按键当前的状态和上一次的状态不同 if (keyState[i][j] == 0) //如果当前的状态是按下去了(在按键的前沿触发执行程序) keyAction(keyNo[i][j]); backup[i][j] = keyState[i][j]; //备份当前的状态 } } void keyScan() { //每执行一次扫一行,每一个按键的采样周期为4个定时器周期 static uint8_t i = 0; //按键扫描的行索引 static uint8_t keyBuf[4][4] = { //每一个按键的流水时序采样状态,保存8个样本点 {0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF} }; uint8_t j; //按键扫描的列索引 P3 = ~(1 << i); //选择当前行(0有效) keyBuf[i][0] = (keyBuf[i][0] << 1) | keyCol0; //流水保存采样结果 keyBuf[i][1] = (keyBuf[i][1] << 1) | keyCol1; keyBuf[i][2] = (keyBuf[i][2] << 1) | keyCol2; keyBuf[i][3] = (keyBuf[i][3] << 1) | keyCol3; for (j = 0; j < 4; j++) { //读取当前行各按键的采样信息,由此更新按键的当前状态 if ((keyBuf[i][j] & 0x0F) == 0x00) //取最近的4个样本点,这里一定要加括号,否则编译会出问题 keyState[i][j] = 0; else if ((keyBuf[i][j] & 0x0F) == 0x0F) keyState[i][j] = 1; } i = (i + 1) & 0x03; //切换至下一个行索引,为下一次扫描做好准备 }