消除抖动有软件和硬件两种方法
软件方法就是在首次检测到低电平时加延时,通常延时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_PinGPIO_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 4void key_Init(void);
u8 KEY_Scan(u8 mode);#endif
以上代码经实际上机实验,测试通过!