第14章 按键控制实验

2024/12/22 STM32
第14章 按键控制实验

一、按键介绍

pAxEobF.png

按键就是一种电子开关使用时轻轻按开关按钮就可以使开关接通,当松开手的时候,开关断开。说白了按键就是用来实现一个电路的通路以及断开操作的开关。

如何接线

假设我们接的是1,3,此时电路一直是通路,当我们按下按键和不按下按键都是同一个结果,因为1,3相连引脚初始是导通的,那我们不能实现按键操作。所以我们应该接1,2引脚,同样的我们也可以接1,4引脚

按键抖动

  1. 通常的按键所用开关为机械弹性开关,当机械触点断开、闭合时,电压信号如图:

pAxE5uT.png

  1. 当按键按下立刻变为低电平,松开的时候立刻变为高电平,这是理想状态的波形。实际上,机械开关在安下或者松开的时候有一个抖动,等到一定时间后他就会稳定,抖动时间通常是10 ~ 20ms
  2. 需要消除抖动的波形,抖动过程中产生低电平,会导致设备误操作,所以需要对进行按键滤波。
  3. 按键的滤波方法:
    • 硬件消抖:通过RC的滤波电路,通过充放电,实现时间的滤除
    • 软件消抖:使用延时

二、硬件设计

pAxEIDU.png

开发板上一共有4个按键:

  • KEY_UP:PA0,按键按下检测到有效电平是3.3V,高电平有效
  • KEY0:PE4,按键按下检测到低电平有效
  • KEY1:PE3,按键按下检测到低电平有效
  • KEY2:PE2,按键按下检测到低电平有效

三、软件设计

程序主要框架:

  1. 初始化按键使用的端口及时钟
  2. 按键检测处理
  3. 按键控制处理

创建文件

  1. 在APP文件夹下创建KEY文件夹,用来存放按键文件
  2. 在KEY文件夹下创建key.h和key.c文件
  3. 进行按键初始化时,和LED、蜂鸣器时类似的,但是需要用到GPIO的输入功能,当按键按下的时候,检测端口引脚是高电平还是低电平

key.c文件

#include "key.h"
#include "SysTick.h"

void KEY_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	// 使用或运算使能多个时钟
	RCC_APB2PeriphClockCmd(KEY_UP_PORT_RCC | KEY_012_PORT_RCC, ENABLE);
	
	// 配置成输入不需要设置速度
	// KEY_UP高电平有效,先给引脚配置一个默认电平低电平,引脚默认输入低点平,当按键按下电路导通,输入就会变成高电平
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;	
	GPIO_InitStructure.GPIO_Pin = KEY_UP_PIN;
	
	GPIO_Init(KEY_UP_PORT, &GPIO_InitStructure);
	
	// KEY_012低电平有效,先给引脚配置一个默认电平高电平,引脚默认输入高点平,当按键按下电路导通,输入就会变成低电平
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;	
	GPIO_InitStructure.GPIO_Pin = KEY0_PIN | KEY1_PIN | KEY2_PIN;
	
	GPIO_Init(KEY_012_PORT, &GPIO_InitStructure);
}

// 按键扫描,检测哪一个按键按下
// mode用于对按键进行单次检测或者连续检测
// mode = 0,单次检测按键,mode = 1,连续检测按键,类似于遥控器的音量调节,连续按+或-
u8 KEY_Scan(u8 mode)
{
	static u8 key = 1;	// key用来实现按键是否连续检测
	if(mode == 1) key = 1;
	
	if(key == 1 && (KEY_UP == 1 || KEY0 == 0 || KEY1 == 0 || KEY2 == 0))	// 说明按键按下,检测到了高电平
	{
		delay_ms(10);	// 消抖
		key = 0;
		if(KEY_UP == 1)	// 如果是高电平,代表按键确实是按下了
			return KEY_UP_PRESS;
		if(KEY0 == 0)
			return KEY0_PRESS;
		if(KEY1 == 0)
			return KEY1_PRESS;
		if(KEY2 == 0)
			return KEY2_PRESS;
	}
	
	// 按键松开检测,按键松开时key == 0
	else if(key == 0 && (KEY_UP == 0 && KEY0 == 1 && KEY1 == 1 && KEY2 == 1))	// 确保4个按键都是松开的,所以用&&
	{
		key = 1;
	}
	return 0;	// 按键没有按下就返回0
}

key.h文件

#ifndef __KEY_H
#define __KEY_H

#include "system.h"

void KEY_Init(void);
u8 KEY_Scan(u8 mode);

#define KEY_UP_PORT_RCC		RCC_APB2Periph_GPIOA
#define KEY_UP_PIN			GPIO_Pin_0
#define KEY_UP_PORT			GPIOA

#define KEY_012_PORT_RCC 	RCC_APB2Periph_GPIOE
#define KEY0_PIN			GPIO_Pin_4
#define KEY1_PIN			GPIO_Pin_3
#define KEY2_PIN			GPIO_Pin_2
#define KEY_012_PORT		GPIOE

#define KEY_UP				PAin(0)
#define KEY0				PEin(4)
#define KEY1				PEin(3)
#define KEY2				PEin(2)

// 返回值,用来获取是哪一个按键按下
#define KEY_UP_PRESS		1
#define KEY0_PRESS			2
#define KEY1_PRESS			3
#define KEY2_PRESS			4

#endif

main.c文件

#include "LED.h"       // 包含 LED 模块的头文件
#include "system.h"
#include "SysTick.h"
#include "beep.h"
#include "key.h"

// 主函数
int main()
{
	u8 key = 0;	// 判断哪个按键按下
	u8 i = 0;	//让LED1指示灯闪烁,确保程序在执行
	
	SysTick_Init(72);
    LED_Init(); // 初始化 LED1 和 LED2
	BEEP_Init();
	KEY_Init();

    // 主循环
    while(1)
    {
		key = KEY_Scan(0);
		
		switch(key)
		{
			case KEY_UP_PRESS: LED2 = 0; break;
			case KEY0_PRESS: BEEP = 1; break;
			case KEY1_PRESS: LED2 = 1; break;
			case KEY2_PRESS: BEEP = 0; break;
		}
		i ++;
		if(i % 20 == 0)	// 每经过200ms,让LED1翻转一次
			LED1 = !LED1;
		delay_ms(10);
    }
	
}

文档信息

搜索

    Table of Contents