矩阵按键
单片机用来控制按键时,为节省IO口的使用,常常将按键搞成矩阵按键,这里用的是5个IO,搞为2*3=6个按键,IO为G0,G1,G2,G3,G4 ,可自行更改。使用多个IO口原理相同
大概思路
- 初始化IO,将行IO设置为推挽输出,列IO设置为上拉输入(初始化为高电平)
- 将行IO设置输出低电平0
- 检测列IO是否为1,如果不是,则有按键按下(注意消抖)
- 有按键按下时,行 列 转变,将列IO设置为推挽输出,行IO设置为上拉输入。列IO输出低电平0,检测行IO哪个为低电平即可确定哪个按键按下
- 检测按键是否松开
- 返回哪个按键按下
代码
头文件没有的记得删除
#include "key.h"
#include "delay.h"
#include <led.h>
#include "oled.h"
extern u8 KeyValue;
u8 KEY_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
u8 cord_h=0XFF,cord_l=0XFF; // h为行,l为列
u8 Val = 0xFF;
u8 k1;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);//使能时钟
/*行线推挽输出 */
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_2MHz;
GPIO_Init(GPIOG,&GPIO_InitStructure);
/* 列线上拉输入 */
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN;
GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4;
GPIO_Init(GPIOG,&GPIO_InitStructure);
/*行线输出低电平 */
GPIO_WriteBit(GPIOG, GPIO_Pin_0|GPIO_Pin_1, Bit_RESET);
delay_us(100);
/* 读列线值,将各位数值(0或1)放到 cord_l低3位*/
cord_l&=(u8)((GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_4)<<2)|
(GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_2)<<1)|
(GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_3)<<0));
if(cord_l!=0X07) //低三位不为1时有按键按下
{
delay_ms(10); //消抖
cord_l&=(u8)((GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_4)<<2)|
(GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_2)<<1)|
(GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_3)<<0));
if(cord_l!=0X07)
{
/* 确认按下,行 列 转变 */
/* 列线输出*/
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4;
GPIO_Init(GPIOG,&GPIO_InitStructure);
/* 行线输入 */
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN;
GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_2MHz;
GPIO_Init(GPIOG,&GPIO_InitStructure);
/* 输出低电平 */
GPIO_WriteBit(GPIOG, GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4, Bit_RESET);
delay_ms(2);
/*读入行线值,放到cord_h的高四位的后两位*/
cord_h&=(u8)((GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_1)<<5)|
(GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_0)<<4));
Val=(cord_h|cord_l); // 两数相或,判断Val数值即可知道哪个按键按下,看下面图片
//判断按键是否松开
k1=(u8)((GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_1)<<5)|
(GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_0)<<4)|
(GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_4)<<2)|
(GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_2)<<1)|
(GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_3)<<0)
);
while(k1!=0x30)
{
k1=(u8)((GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_1)<<5)|
(GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_0)<<4)|
(GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_4)<<2)|
(GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_2)<<1)|
(GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_3)<<0)
);
}
return Val;
}
}
return Val;
}
void KEY_Scan(u8 a) //读按键返回值(Val)
{
switch (a) //case 里面的数值已有改动,不一定对,需自行计算
{
case(0x13):KeyValue=1;OLED_ShowNum(0,0,KeyValue,4,2);break;
case(0x15):KeyValue=2;OLED_ShowNum(0,0,KeyValue,4,2);break;
case(0x16):KeyValue=3;OLED_ShowNum(0,0,KeyValue,4,2);break;
case(0x23):KeyValue=4;OLED_ShowNum(0,0,KeyValue,4,2);break;
case(0x25):KeyValue=5;OLED_ShowNum(0,0,KeyValue,4,2);break;
case(0x26):KeyValue=6;OLED_ShowNum(0,0,KeyValue,4,2);break;
default : break;//无按键按下
}
}
注意
用时需改变IO及case里面的数值