STM32学习和实践笔记(14):按键控制实验-LMLPHP

消除抖动有软件和硬件两种方法

软件方法就是在首次检测到低电平时加延时,通常延时5-10ms,让抖动先过去,然后再来检测是否仍为低电平,如果仍然是,说明确实按下。

硬件方法就是加RC滤波电路,硬件方法会增加成本,通常不采用。

本开发板的按键电路如下:

STM32学习和实践笔记(14):按键控制实验-LMLPHP

key up连接到+3.3V,是为了使用STM32的PA0引脚的唤醒功能。PA0片内配置成下拉电阻,平常为低电平,当按键按下时,检测到下拉电阻上有高电平,即表示按键按下。

K1-K3连到PE2-PE4,片内配置成上拉电阻,平常为高电平,按下按键为低电平。

按键控制实验:

使用开发板上的4个按键控制D2D3,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

以上代码经实际上机实验,测试通过!

04-18 15:10