前面我们讲了IO的通用输出的配置--点灯,今天我们讲讲按键输入。
依旧是学习思路:
如何让芯片内核判断到按键是否按下?
如果按键未按下,内核检测IO口是低电平,如果按下,则检测高电平。
如何检测IO口的电平?
因为是通用输入模式,我们只需要读取数据寄存器对应位的值,就可以知道IO口的电平状态。
按键初始化函数大致框架
{
//时钟使能
//端口模式配置--------通用输入
//上下拉-----------------浮空
}
注意:
由于按键是机械按键,有抖动,不能直接读IDR的位
所以要消抖 再读IDR寄存器
所以我们在写按键扫描函数时应该有一个延时消抖的过程。
u8 key_scan(void)
{
If(按键按下 并且 标志位是1)
{
延时消抖
If(按键真的按下)
{
赋值键值
标志位锁定 //赋值0
}
}
If(按键抬起了)
{
解锁标志位; //重新赋值1
}
返回键值;
}
static void delay_ms(u32 ms)//延时程序
{
u32 i = 168 / 4 * 1000 * ms;
while(i)
{
i--;
}
}
按键初始化函数
/***********************************************
*函数名 :Key_Init
*函数功能 :对按键所用IO口初始化配置
*函数参数 :无
*函数返回值:无
*函数描述 :KEY1-----PA0
KEY2----PE2
KEY3----PE3
KEY4----PE4
************************************************/
void Key_Init(void)
{
//时钟使能
RCC->AHB1ENR |=(1<<0);//--------------A
RCC->AHB1ENR |=(1<<4);//--------------E
//端口模式寄存器配置
GPIOA->MODER &= ~(3<<0);
GPIOE->MODER &= ~((3<<4)|(3<<6)|(3<<8));
//上下拉配置
GPIOA->PUPDR &= ~(3<<0);
GPIOE->PUPDR &= ~((3<<4)|(3<<6)|(3<<8));
}
按键扫描函数
/***********************************************
*函数名 :Key_Scan
*函数功能 :按键扫描
*函数参数 :u8
*函数返回值:无
*函数描述 :
************************************************/
u8 Key_Scan(void)
{
u8 key =0xff;
static u8 key_flag = 1;
if((KEY1||!KEY2||!KEY3||!KEY4) && key_flag )
{
//延时消抖
delay_ms(12);
if(KEY1)
{
//锁定标志位
key_flag=0;
//赋值键值
key=1;
}
else if(!KEY2)
{
//锁定标志位
key_flag=0;
//赋值键值
key=2;
}
else if(!KEY3)
{
//锁定标志位
key_flag=0;
//赋值键值
key=3;
}
else if(!KEY4)
{
//锁定标志位
key_flag=0;
//赋值键值
key=4;
}
}
//按键抬起
if(!KEY1 && KEY2 && KEY3 && KEY4 )
{
key_flag=1;//解锁标志位
}
return key;
}
对于机械按键我们还有很多不同的应用,譬如
两个按键一起按
/******************************************
*函数名 :key_scan_key12
*函数功能 :按键1和按键2一起按
*函数参数 :无
*函数返回值:u8
*函数描述 :两个按键一起按实际是两个按键
按下,之间的间隔时间不能超过设定的窗口
*********************************************/
u8 key_scan_key12(void)
{
static u8 key_flag = 1;
static u32 cont = 0;
u8 key = 0xff;
//判断其中一个按键按下
if((KEY1|| !KEY2) && key_flag)
{
cont++;
//两个按键都按下并且时间差<=250000
if((KEY1 && !KEY2) && cont<=250000)
{
delay_ms(10);
if(KEY1 && !KEY2)
{
key = 99;
key_flag = 0;
}
}
}
//消除恶意一直按KEY1,按按键1/2后超过一定时间再按按键1/2无效
if(cont > 250000)
{
cont = 255000;
}
//如果两个按键抬起就解锁
if(!KEY1 && KEY2 )
{
key_flag = 1;
cont = 0;
}
return key;
}
长按:
/******************************************
*函数名 :key1_len_scan
*函数功能 :按键1长按 短按扫描
*函数参数 :无
*函数返回值:u8
*函数描述 :短按返回1 长按返回11
*********************************************/
u8 key1_len_scan(void)
{
u8 key_val = 0xff;
static u8 key_falg = 1; //定义长按标志位变量
static u32 cont = 0;
if(KEY1) //如果按键1按下
{
cont++; //开始计数
if(cont > 250) cont = 300; //防止无限加越界
delay_ms(10); //消抖
}
//如果按键1抬起 并且时间不超过100 就是短按
if(!KEY1 && cont>0 && cont<100)
{
key_val = 1; //赋值键值1
cont = 0; //清零
}
//如果时间超过250 并且 标志位1 就是长按
if(cont >= 250 && key_falg)
{
key_val = 11; //赋值键值11
key_falg = 0; //标志位锁定
}
if(!KEY1 && cont >= 250) //如果长按的按键抬起
{
key_falg = 1; //标志位解锁
cont = 0; //清零
}
return key_val; //返回键值
}