阵列键盘
阵列键盘的产生是为了节省单片机的IO端口,利用循环扫描的方式逐一扫描键盘的状态(方法不唯一,这里以反转扫描法介绍)。
这里用反转法扫描。
这个图表的意思是当某个按键按下时对应的线路接通,比如,让5按下时,则b与2线连通。
所谓反转扫描,即先设定PA0-PA3为上拉电阻输入模式(没有按键按下时,IO端口为高电平),设置PA4-PA7为推挽输出模式,输出低电平0。再在设定PA0-PA3为推挽输出模式,输出低电平0,设置PA4-PA7为上拉电阻模式(没有按键按下时,IO端口为高电平)。
列如,当’A’按键按下时,由于刚开始PA0-PA3为输入模式,PA4-PA7为输出0,因此,此时3线为低电平0,由于A该行的任意一个按键按下,3线均为低电平,因此需要反转PA0-PA3和PA4-PA7的状态,同样的道理读取到C线为低电平,由此便可确定是’A’按键按下。
原理很简单,简单驱动函数如下:
void KEYPAD4x4_Init(void){ //微动开关的接口初始化
GPIO_InitTypeDef GPIO_InitStructure; //定义GPIO的初始化枚举结构
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitStructure.GPIO_Pin = KEYa | KEYb | KEYc | KEYd; //选择端口号(0~15或all)
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //选择IO接口工作方式 //上拉电阻
GPIO_Init(KEYPAD4x4PORT,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = KEY1 | KEY2 | KEY3 | KEY4; //选择端口号(0~15或all)
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //选择IO接口工作方式 //上拉电阻
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置IO接口速度(2/10/50MHz)
GPIO_Init(KEYPAD4x4PORT,&GPIO_InitStructure);
}
void KEYPAD4x4_Init2(void){ //微动开关的接口初始化2(用于IO工作方式反转)
GPIO_InitTypeDef GPIO_InitStructure; //定义GPIO的初始化枚举结构
GPIO_InitStructure.GPIO_Pin = KEY1 | KEY2 | KEY3 | KEY4; //选择端口号(0~15或all)
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //选择IO接口工作方式 //上拉电阻
GPIO_Init(KEYPAD4x4PORT,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = KEYa | KEYb | KEYc | KEYd; //选择端口号(0~15或all)
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //选择IO接口工作方式 //上拉电阻
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置IO接口速度(2/10/50MHz)
GPIO_Init(KEYPAD4x4PORT,&GPIO_InitStructure);
}
这两个函数是设置反转的函数,即设定IO端口为输入还是输出状态。
需要注意的是有下列组合:
KEYPAD4x4_Init();//初始化IO
GPIO_ResetBits(KEYPAD4x4PORT,KEY1|KEY2|KEY3|KEY4);
GPIO_SetBits(KEYPAD4x4PORT,KEYa|KEYb|KEYc|KEYd);
KEYPAD4x4_Init2();//IO工作方式反转
GPIO_SetBits(KEYPAD4x4PORT,KEY1|KEY2|KEY3|KEY4);
GPIO_ResetBits(KEYPAD4x4PORT,KEYa|KEYb|KEYc|KEYd);
具体的扫描函数如下,将扫描的状态值存入一个变量中,利用按位或和固件库函数的读取IO端口的函数
u8 KEYPAD4x4_Read (void){//键盘处理函数
u8 a=0,b=0;//定义变量
KEYPAD4x4_Init();//初始化IO
GPIO_ResetBits(KEYPAD4x4PORT,KEY1|KEY2|KEY3|KEY4);
GPIO_SetBits(KEYPAD4x4PORT,KEYa|KEYb|KEYc|KEYd);
if(!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEYa) || //查寻键盘口的值是否变化
!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEYb) ||
!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEYc) ||
!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEYd)){
delay_ms (20);//延时20毫秒
if(!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEYa) || //查寻键盘口的值是否变化
!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEYb) ||
!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEYc) ||
!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEYd)){
a = GPIO_ReadInputData(KEYPAD4x4PORT)&0xff;//键值放入寄存器a
}
KEYPAD4x4_Init2();//IO工作方式反转
GPIO_SetBits(KEYPAD4x4PORT,KEY1|KEY2|KEY3|KEY4);
GPIO_ResetBits(KEYPAD4x4PORT,KEYa|KEYb|KEYc|KEYd);
b = GPIO_ReadInputData(KEYPAD4x4PORT)&0xff;//将第二次取得值放入寄存器b
a = a|b;//将两个数据相或
switch(a){//对比数据值
case 0xee: b = 16; break;//对比得到的键值给b一个应用数据
case 0xed: b = 15; break;
case 0xeb: b = 14; break;
case 0xe7: b = 13; break;
case 0xde: b = 12; break;
case 0xdd: b = 11; break;
case 0xdb: b = 10; break;
case 0xd7: b = 9; break;
case 0xbe: b = 8; break;
case 0xbd: b = 7; break;
case 0xbb: b = 6; break;
case 0xb7: b = 5; break;
case 0x7e: b = 4; break;
case 0x7d: b = 3; break;
case 0x7b: b = 2; break;
case 0x77: b = 1; break;
default: b = 0; break;//键值错误处理
}
while(!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEY1) || //等待按键放开
!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEY2) ||
!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEY3) ||
!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEY4));
delay_ms (20);//延时20毫秒
}
return (b);//将b作为返回值
}
注意这种方法,其中有小细节错误。