【前言】
如果需要通过按键来实现用户的交互,就需要创建一个高效的按键处理。这一篇我在FreeRTOS的多任务系统下,实现一个基于状态机的按键处理程序。
【实现目标】
在MAX32625MBED开发板中,有两个按键SW2与SW3,需要实现按下按键并松开后,在串口打印出按键按下的信息。
【原理图】
在MAX32625MBED的原理图中,两个按键分别接到了P2.2与P2.3中,并有上拉电阻,在松开状态时,为高电平。


【注】 在MAX32625PICO开发板上是没有这两个物理按键的,如果实现需要自行拉入两个按键。
【程序代码】
1、在工程中添加两个文件,分别为key.c/h,key.c代码如下:
#include "key.h"
#include "gpio.h"
#include "max32625.h"
#include "FreeRTOS.h"
#include "task.h"
#include "stdio.h"
// 按键引脚定义
#define SW2_PIN PIN_2
#define SW2_PORT PORT_2
#define SW3_PIN PIN_3
#define SW3_PORT PORT_2
// 按键状态机
typedef enum
{
KEY_STATE_IDLE,
KEY_STATE_PRESSED,
KEY_STATE_RELEASED
} key_state_t;
static key_state_t sw2_state = KEY_STATE_IDLE;
static key_state_t sw3_state = KEY_STATE_IDLE;
// 按键消抖时间(毫秒)
#define DEBOUNCE_TIME_MS 20
gpio_cfg_t sw2_cfg = {SW2_PORT, SW2_PIN, GPIO_FUNC_GPIO, GPIO_PAD_INPUT_PULLUP};
gpio_cfg_t sw3_cfg = {SW3_PORT, SW3_PIN, GPIO_FUNC_GPIO, GPIO_PAD_INPUT_PULLUP};
void key_init(void)
{
GPIO_Config(&sw2_cfg);
GPIO_Config(&sw3_cfg);
}
// 获取按键单击状态(非阻塞式)
key_event_t key_get_click(void)
{
static TickType_t last_sw2_time = 0;
static TickType_t last_sw3_time = 0;
static uint8_t sw2_last = 1;
static uint8_t sw3_last = 1;
uint8_t sw2_current = GPIO_InGet(&sw2_cfg);
uint8_t sw3_current = GPIO_InGet(&sw3_cfg);
TickType_t now = xTaskGetTickCount();
key_event_t event = KEY_NONE;
// SW2状态处理
if (sw2_current != sw2_last)
{
if ((now - last_sw2_time) > pdMS_TO_TICKS(DEBOUNCE_TIME_MS))
{
if (sw2_current == 0)
{ // 按下
sw2_state = KEY_STATE_PRESSED;
}
else
{ // 松开
if (sw2_state == KEY_STATE_PRESSED)
{
sw2_state = KEY_STATE_RELEASED;
event = KEY_SW2_CLICK;
}
}
last_sw2_time = now;
}
sw2_last = sw2_current;
}
// SW3状态处理
if (sw3_current != sw3_last)
{
if ((now - last_sw3_time) > pdMS_TO_TICKS(DEBOUNCE_TIME_MS))
{
if (sw3_current == 0)
{ // 按下
sw3_state = KEY_STATE_PRESSED;
}
else
{ // 松开
if (sw3_state == KEY_STATE_PRESSED)
{
sw3_state = KEY_STATE_RELEASED;
event = KEY_SW3_CLICK;
}
}
last_sw3_time = now;
}
sw3_last = sw3_current;
}
return event;
}
// 示例使用(在任务中调用)
void vTaskKeyScan(void *pvParameters)
{
key_init();
while (1)
{
key_event_t event = key_get_click();
switch (event)
{
case KEY_SW2_CLICK:
printf("SW2 Clicked\n");
break;
case KEY_SW3_CLICK:
printf("SW3 Clicked\n");
break;
default:
break;
}
vTaskDelay(pdMS_TO_TICKS(10)); // 10ms扫描间隔
}
}
// 创建任务函数
void vCreateKeyScanTask(void)
{
xTaskCreate(vTaskKeyScan, "KeyScanTask", 512, NULL, tskIDLE_PRIORITY + 1, NULL);
}key.h
#ifndef __KEY_H
#define __KEY_H
typedef enum
{
KEY_NONE,
KEY_SW2_CLICK,
KEY_SW3_CLICK
} key_event_t;
void key_init(void);
key_event_t key_get_click(void);
void vCreateKeyScanTask(void);
#endif最后在main.c的任务创建中调用vCreateKeyScanTask。就完成任务的创建。
【实现效果】
分别按下两个按键,在串口中输出内容如下:

【总结】
结合freertos的多任务操作系统,实现多按键的状态获取,可以为今后的用户交互做好准备。

我要赚赏金
