单片机实验说明<四>矩阵键盘与LCD基本使用

it2025-03-31  10

实验四 矩阵键盘识别设计

设计要求:

对4×4矩阵式键盘电路的键值进行编码,编程实现在LCD液晶显示器上显示每个按键的“0-F”序号

电路设计:

 软件代码:

#include "hml/hml.h" #define uchar unsigned char #define uint unsigned int #define lcden P1_2 #define lcdrs P1_0 #define rw P1_1 /* IO引脚分配定义 */ #define KEY_IN_1 P2_4 //矩阵按键的扫描输入引脚1 #define KEY_IN_2 P2_5 //矩阵按键的扫描输入引脚2 #define KEY_IN_3 P2_6 //矩阵按键的扫描输入引脚3 #define KEY_IN_4 P2_7 //矩阵按键的扫描输入引脚4 #define KEY_OUT_1 P2_0 //矩阵按键的扫描输出引脚1 #define KEY_OUT_2 P2_1 //矩阵按键的扫描输出引脚2 #define KEY_OUT_3 P2_2 //矩阵按键的扫描输出引脚3 #define KEY_OUT_4 P2_3 //矩阵按键的扫描输出引脚4 #define LSA P1_5 //LED位选译码地址引脚A #define LSB P1_6 //LED位选译码地址引脚B #define LSC P1_7 //LED位选译码地址引脚C unsigned char disBuf=0; uchar table1[] = "Welcome To CSLG!"; uchar table2[] = "0123456789ABCDEF"; uchar table3[] = " "; uchar num; const unsigned char KeyCodeMap[4][4] = { //矩阵按键到标准键码的映射表 { '0', '1', '2', '3' }, // { '4', '5', '6', '7' }, // { '8', '9', 'a', 'b' }, // { 'c', 'd', 'e', 'f' } // }; unsigned char KeySta[4][4] = { //全部矩阵按键的当前状态 {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1} }; /* 函数声明 */ void KeyScan(); void KeyDriver(); void KeyAction(unsigned char keycode); /* 按键驱动函数,检测按键动作,调度相应动作函数,需在主循环中调用 */ void KeyDriver() { unsigned char i, j; static unsigned char 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++) //循环检测4*4的矩阵按键 { 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]; //刷新前一次的备份值 } } } } /* 按键扫描函数,需在定时中断中调用,推荐调用间隔1ms */ void KeyScan() { unsigned char i; static unsigned char keyout = 0; //矩阵按键扫描输出索引 static unsigned char keybuf[4][4] = { //矩阵按键扫描缓冲区 {0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF} }; //将一行的4个按键值移入缓冲区 keybuf[keyout][0] = (keybuf[keyout][0] << 1) | KEY_IN_1; keybuf[keyout][1] = (keybuf[keyout][1] << 1) | KEY_IN_2; keybuf[keyout][2] = (keybuf[keyout][2] << 1) | KEY_IN_3; keybuf[keyout][3] = (keybuf[keyout][3] << 1) | KEY_IN_4; //消抖后更新按键状态 for (i=0; i<4; i++) //每行4个按键,所以循环4次 { if ((keybuf[keyout][i] & 0x0F) == 0x00) { //连续4次扫描值为0,即4*4ms内都是按下状态时,可认为按键已稳定的按下 KeySta[keyout][i] = 0; } else if ((keybuf[keyout][i] & 0x0F) == 0x0F) { //连续4次扫描值为1,即4*4ms内都是弹起状态时,可认为按键已稳定的弹起 KeySta[keyout][i] = 1; } } //执行下一次的扫描输出 keyout++; //输出索引递增 keyout &= 0x03; //索引值加到4即归零 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; } } void KeyAction(unsigned char keycode) { disBuf = keycode; } void delay(uint z) { uint x, y; for(x = z; x > 0; x--) for(y = 110; y > 0; y--); } void write_com(uchar com) { lcdrs = 0; P0 = com; delay(5); lcden = 1; delay(5); lcden = 0; } void write_data(uchar date) { lcdrs = 1; P0 = date; delay(5); lcden = 1; delay(5); lcden = 0; } void init() { rw = 0; lcden = 0; write_com(0x38); write_com(0x0e); write_com(0x06); write_com(0x01); } void main() { init(); write_com( 0x00 | 0x80 ); for(num = 0; num < 16; num++) { write_data(table1[num]); delay(100); } write_com( 0x40 | 0x80 ); for(num = 0; num < 16; num++) { write_data(table2[num]); delay(100); } write_com( 0x40 | 0x80 ); for(num = 0; num < 16; num++) { write_data(table3[num]); delay(100); } while(1) { KeyScan(); KeyDriver(); write_com( 0x40 | 0x80 ); write_data(disBuf); } }

思考题

1. LCD 显示改为数码管显示(选做); 2. 若要实现数字键 0~9 按下后,直接在 LCD 上显示数字,如何修改程序?


 

zhangrelay 认证博客专家 不合格高校讲师 LoveRobot,Go!!!!人工智能和机器人粉,从事机器人工程专业本科教学和科研工作,研究方向包括多机器人仿真技术,控制与协作,机器人系统软硬件开发等。
最新回复(0)