消除抖动有软件和硬件两种方法
软件方法就是在首次检测到低电平时加延时,通常延时5-10ms,让抖动先过去,然后再来检测是否仍为低电平,如果仍然是,说明确实按下。
硬件方法就是加RC滤波电路,硬件方法会增加成本,通常不采用。
本开发板的按键电路如下:
key up连接到+3.3V,是为了使用STM32的PA0引脚的唤醒功能。PA0片内配置成下拉电阻,平常为低电平,当按键按下时,检测到下拉电阻上有高电平,即表示按键按下。
K1-K3连到PE2-PE4,片内配置成上拉电阻,平常为高电平,按下按键为低电平。
按键控制实验:
使用开发板上的4个按键控制D2和D3,D1指示灯
闪烁用于提示系统运行。程序框架如下:
(1)使能按键端口时钟、初始化GPIO。
(2)按键检测
(3)主函数控制
main.c
#include "system.h"
#include "led.h"
#include "SysTick.h"
#include "beep.h"
#include "DigitalTube.h"
#include "key.h"
int main()
{
u8 key,i=0;
SysTick_Init(72);
LED_Init();
// BEEP_Init();
// DigitalTube_Init();
key_Init();
while(1)
{
key=KEY_Scan(1);
switch(key)
{
case KEY_UP: led2=!led2;break;
case KEY_DOWN: led3=!led3;break;
case KEY_LEFT: led4=!led4;break;
case KEY_RIGHT: led5=!led5;break;
}
i++;
if(i%20 ==0)
{
led1=!led1;//LED1闪
}
delay_ms(10);
}
}
LED1闪,不使用直接在while里延时的方式 ,而是通过一个i做中间变量的方式 ,是因为假设直接使用延时,因为想看到灯闪,延时的时间就需要较长,而在延时的时间里,CPU等于延在那空等,这个时候按动按键,按键的检测可能反应就不够快!
key.c
#include "key.h"
#include "SysTick.h"
void key_Init()
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOE,ENABLE);//同时打开PA和PE端口时钟
GPIO_InitStructure.GPIO_Pin=KEY_UP_Pin;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPD; //配置成输入、下拉电阻模式
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; //输入模式的频率配不配置不影响
GPIO_Init(KEY_UP_Port,&GPIO_InitStructure);//初始化KEY_UP_Pin
GPIO_InitStructure.GPIO_Pin=KEY_LEFT_Pin|KEY_DOWN_Pin|KEY_RIGHT_Pin;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU; //配置成输入、上拉电阻模式
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; //输入模式的频率配不配置不影响
GPIO_Init(KEY_Port,&GPIO_InitStructure);//初始化KEY_LEFT_Pin|KEY_DOWN_Pin|KEY_RIGHT_Pin
}
u8 KEY_Scan(u8 mode) mode =0--单次扫描,mode =1--连接扫描
{
static u8 key=1;//key用来判断按键是否连续按下;定义成static可以保证程序中断恢复时仍然保持上一次的值
if(key==1&&(K_UP==1||K_DOWN==0||K_LEFT==0||K_RIGHT==0))//检测是否有按键按下
{
key=0;
delay_ms(10);
if(K_UP==1)
{
return KEY_UP;
}
else if (K_DOWN==0)
{
return KEY_DOWN;
}
else if (K_LEFT==0)
{
return KEY_LEFT;
}
else if (K_RIGHT==0)
{
return KEY_RIGHT;
}
}
else if (K_UP==0&&K_DOWN==1&&K_LEFT==1&&K_RIGHT==1)//检测是否松开按键
{
key=1;
}
if(mode==1)//如果调用Key_Scan传进来的mode=1,则强制key始终等于1,这等于取消了上条的松开按键检测
{
key=1;
}
return 0;
}
key.h
#ifndef _key_H
#define _key_H
#include "system.h"
#define KEY_UP_Pin GPIO_Pin_0
#define KEY_UP_Port GPIOA
#define KEY_LEFT_Pin GPIO_Pin_2
#define KEY_DOWN_Pin GPIO_Pin_3
#define KEY_RIGHT_Pin GPIO_Pin_4
#define KEY_Port GPIOE
//使用位带的方式读取引脚电平
#define K_UP PAin(0)
#define K_DOWN PEin(3)
#define K_LEFT PEin(2)
#define K_RIGHT PEin(4)
//直接使用库函数的方式读取引脚电平
//#define K_UP GPIO_ReadInputDataBit(KEY_UP_Port,KEY_UP_Pin)
//#define K_DOWN GPIO_ReadInputDataBit(KEY_Port,KEY_DOWN_Pin)
//#define K_LEFT GPIO_ReadInputDataBit(KEY_Port,KEY_LEFT_Pin)
//#define K_RIGHT GPIO_ReadInputDataBit(KEY_Port,KEY_RIGHT_Pin)
#define KEY_UP 1
#define KEY_DOWN 2
#define KEY_LEFT 3
#define KEY_RIGHT 4
void key_Init(void);
u8 KEY_Scan(u8 mode);
#endif
以上代码经实际上机实验,测试通过!