这里写目录标题
- 1、矩阵按键
- 2、代码片段分析
1、矩阵按键
通过将4x4矩阵按键的每一行依次设为低电平,同时保持其它行为高电平,然后读取所有列的电平状态,可以检测到哪个按键被按下。如果某列变为低电平,说明对应行和列的按键被按下。这样逐行扫描即可确定按键的位置。
2、代码片段分析
/*********************************************************************@Function : 矩阵键盘行列读写操作@Parameter : ReadIo :读输入的IOWirteIo :写输出的IO@Return : 行列IO输出状态
**********************************************************************/
uint8_t GPIO_KEY_RW(uint16_t ReadIo,uint16_t WirteIo)
{uint16_t Wdata=0,Rdata=0; /* 写操作 */KeyBordSetOut(KEY_ALL); //设置IOif(WirteIo==0x0f00)GPIO_SetBits(GPIOE,KEY_LINE); //写行else GPIO_ResetBits(GPIOE,KEY_LIST); //写列 Wdata = GPIO_ReadOutputData(GPIOE);//读输出 Wdata &= WirteIo; //取有效区域/* 读操作 */KeyBordSetIn(ReadIo); //设置IO Rdata = GPIO_ReadInputData(GPIOE); //读输入Rdata &= ReadIo; //取有效区域/* 状态返回 */Rdata |= Wdata; //合并两次读取的数据return (uint8_t)(Rdata>>8); //移位返回
}
初始化:
Wdata 和 Rdata 初始化为 0。
写操作:
检查 WirteIo 是否为 0x0f00(二进制:0000111100000000):
如果是,则设置 GPIOE 中对应 KEY_LINE 的位(具体位取决于 KEY_LINE 的定义)。
如果不是,则复位 GPIOE 中对应 KEY_LIST 的位(具体位取决于 KEY_LIST 的定义)。
读取 GPIOE 的输出数据到 Wdata。
Wdata 与 WirteIo 进行与操作,保留有效区域的数据。
读操作:
使用 ReadIo 设置IO方向。
读取 GPIOE 的输入数据到 Rdata。
Rdata 与 ReadIo 进行与操作,保留有效区域的数据。
状态返回:
将 Wdata 和 Rdata 进行或操作,合并两次读取的数据。
返回 Rdata 右移8位后的值。
假设按下第一个按键
假设按下的是第一个按键,具体的步骤如下:
初始化:
Wdata = 0
Rdata = 0
写操作:
WirteIo == 0x0f00 假设为真,则设置 GPIOE 对应 KEY_LINE 的位。
读取 GPIOE 输出数据:
假设 GPIOE 输出数据为 0000111100000000(二进制)。
Wdata &= WirteIo:
Wdata = 0000111100000000 & 0000111100000000 = 0000111100000000
读操作:
设置IO方向,具体操作取决于 KeyBordSetIn 函数。
读取 GPIOE 输入数据:
假设按下第一个按键时,GPIOE 输入数据为 0000000100000000(二进制)。
Rdata &= ReadIo:
Rdata = 0000000100000000 & ReadIo(假设 ReadIo 为 0000000100000000),结果 Rdata = 0000000100000000
状态返回:
Rdata |= Wdata:
Rdata = 0000000100000000 | 0000111100000000 = 0000111100000000
返回值:
将 Rdata 右移8位后返回:Rdata >> 8 = 00001111
所以函数返回值为 0x0F(二进制:00001111)
/*********************************************************************@Function : 矩阵键盘键值扫描@Parameter : N/A@Return : 键值
**********************************************************************/
uint8_t KeyBoardScan(void)
{uint8_t KeyValue=0,Key=0;uint8_t a = 0;/* 检测键盘是否有按键按下,0x0f表示所有列都未按下 */if(GPIO_KEY_RW(KEY_LIST,KEY_LINE)!=0x0f){/* 测试列状态 */Key = GPIO_KEY_RW(KEY_LIST,KEY_LINE); // 读取列的状态/* 判断列状态并映射为按键值 */switch(Key){case(0x1F): // 第一列所有行都按下KeyValue = 1; // 对应键值为1break;case(0x2F): // 第二列所有行都按下KeyValue = 2; // 对应键值为2break;case(0x4F): // 第三列所有行都按下KeyValue = 3; // 对应键值为3break;case(0x8F): // 第四列所有行都按下KeyValue = 4; // 对应键值为4break;}/* 测试行状态 */Key = GPIO_KEY_RW(KEY_LINE,KEY_LIST); // 读取行的状态/* 判断行状态并映射为按键值 */switch(Key){case(0x0E): // 第一行所有列都按下KeyValue = KeyValue; // 保持当前列的键值不变break;case(0x0D): // 第二行所有列都按下KeyValue = KeyValue + 4; // 当前列的键值加4,对应第二行break;case(0x0B): // 第三行所有列都按下KeyValue = KeyValue + 8; // 当前列的键值加8,对应第三行break;case(0x07): // 第四行所有列都按下KeyValue = KeyValue + 12; // 当前列的键值加12,对应第四行break;}/* 按键松手检测 */while((a < 50) && (Key != 0x00)) // 循环检测按键是否松手,最多检测50次{delay_ms(5); // 延时5毫秒Key = GPIO_KEY_RW(KEY_LINE,KEY_LIST); // 再次读取行的状态a += 1; // 计数器加1}}/* 返回键值 */return KeyValue;
}