STM32 之按键长短按设计
一、引言
在基于 STM32 的嵌入式系统开发中,按键是一种常见的输入设备。除了简单的按键按下和释放检测,按键的长短按功能可以为系统提供更多的交互方式。例如,短按可以实现普通的功能选择,长按则可以触发一些特殊操作,如系统设置、复位等。本文将详细介绍如何在 STM32 上实现按键的长短按检测,并给出相应的代码示例。
二、硬件连接
假设我们使用 STM32F103C8T6 作为主控芯片,按键连接到 PA0 引脚。按键的一端连接到 PA0,另一端接地,同时 PA0 引脚需要上拉电阻连接到电源,这样在按键未按下时,PA0 引脚为高电平;当按键按下时,PA0 引脚变为低电平。
三、实现思路
实现按键长短按检测的基本思路是通过定时器对按键按下的时间进行计时。当检测到按键按下时,启动定时器开始计时;当按键释放时,停止计时,并根据计时时间判断是短按还是长按。具体步骤如下:
按键状态检测:通过读取按键引脚的电平状态,判断按键是否按下。
计时开始:当检测到按键按下时,启动定时器开始计时。
计时停止:当检测到按键释放时,停止定时器计时。
长短按判断:根据计时时间判断是短按还是长按。如果计时时间小于设定的短按时间阈值,则为短按;如果计时时间大于等于设定的长按时间阈值,则为长按。
四、代码实现
1. 初始化代码
#include "stm32f10x.h"
// 按键引脚定义
#define KEY_PIN GPIO_Pin_0
#define KEY_PORT GPIOA
// 定时器定义
#define TIMER TIM2
// 短按时间阈值(单位:ms)
#define SHORT_PRESS_TIME 200
// 长按时间阈值(单位:ms)
#define LONG_PRESS_TIME 1000
// 定时器初始化
void TIM2_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_TimeBaseStructure.TIM_Period = 999; // 定时器周期
TIM_TimeBaseStructure.TIM_Prescaler = 71; // 定时器预分频器
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIMER, &TIM_TimeBaseStructure);
TIM_Cmd(TIMER, DISABLE); // 初始时关闭定时器
}
// 按键引脚初始化
void KEY_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = KEY_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(KEY_PORT, &GPIO_InitStructure);
}
// 初始化函数
void Init(void)
{
KEY_Init();
TIM2_Init();
}
2. 按键检测和长短按判断代码
// 按键状态枚举
typedef enum {
KEY_STATE_RELEASED,
KEY_STATE_PRESSED,
KEY_STATE_SHORT_PRESSED,
KEY_STATE_LONG_PRESSED
} KeyState;
// 按键状态变量
KeyState keyState = KEY_STATE_RELEASED;
// 计时变量
uint16_t pressTime = 0;
// 按键检测函数
void KEY_Detect(void)
{
static uint8_t keyPressed = 0;
if (GPIO_ReadInputDataBit(KEY_PORT, KEY_PIN) == 0) { // 按键按下
if (!keyPressed) {
keyPressed = 1;
pressTime = 0;
TIM_SetCounter(TIMER, 0); // 重置定时器计数器
TIM_Cmd(TIMER, ENABLE); // 启动定时器
keyState = KEY_STATE_PRESSED;
}
} else { // 按键释放
if (keyPressed) {
keyPressed = 0;
TIM_Cmd(TIMER, DISABLE); // 停止定时器
if (pressTime < SHORT_PRESS_TIME) {
keyState = KEY_STATE_RELEASED;
} else if (pressTime < LONG_PRESS_TIME) {
keyState = KEY_STATE_SHORT_PRESSED;
} else {
keyState = KEY_STATE_LONG_PRESSED;
}
}
}
}
// 定时器中断处理函数
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIMER, TIM_IT_Update) != RESET) {
TIM_ClearITPendingBit(TIMER, TIM_IT_Update);
pressTime++;
}
}
3. 主函数代码
int main(void)
{
Init();
// 使能定时器中断
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_ITConfig(TIMER, TIM_IT_Update, ENABLE);
while (1) {
KEY_Detect();
switch (keyState) {
case KEY_STATE_SHORT_PRESSED:
// 处理短按事件
// 例如,点亮一个 LED
// GPIO_SetBits(GPIOC, GPIO_Pin_13);
keyState = KEY_STATE_RELEASED;
break;
case KEY_STATE_LONG_PRESSED:
// 处理长按事件
// 例如,关闭一个 LED
// GPIO_ResetBits(GPIOC, GPIO_Pin_13);
keyState = KEY_STATE_RELEASED;
break;
default:
break;
}
}
}
五、代码解释
初始化部分:Init 函数中调用 KEY_Init 和 TIM2_Init 分别对按键引脚和定时器进行初始化。
按键检测部分:KEY_Detect 函数用于检测按键的状态,当按键按下时启动定时器计时,当按键释放时停止计时并根据计时时间判断是短按还是长按。
定时器中断部分:TIM2_IRQHandler 是定时器的中断处理函数,每产生一次定时器中断,pressTime 变量加 1,用于记录按键按下的时间。
主函数部分:在主函数中,不断调用 KEY_Detect 函数进行按键检测,并根据按键状态进行相应的处理。
六、注意事项
消抖处理:实际应用中,按键可能会产生抖动现象,导致按键状态不稳定。可以通过软件消抖或硬件消抖的方式来解决。软件消抖可以在按键检测时添加一定的延时,避免误触发。
定时器配置:定时器的周期和预分频器需要根据系统时钟频率进行合理配置,以确保计时的准确性。
通过以上的设计和代码实现,我们可以在 STM32 上实现按键的长短按检测功能,为系统提供更丰富的交互方式。
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/duierrorshuobu/article/details/145445331
|