[开源]好用的STM32多个独立按键扫描驱动

基于STM32HAL库的独立按键驱动程序,支持消抖,识别长短按,裸机和FreeRTOS,实测稳定消除抖动

部署使用

使用FreeRTOS,新建一个按键任务,延时10ms循环执行:

/* USER CODE END Header_KeyTask */
void KeyTask(void const * argument)
{
  /* USER CODE BEGIN KeyTask */
  /* Infinite loop */
  for(;;)
  {
    key_scan(); /* 按键扫描 */
    osDelay(10);
  }
  /* USER CODE END KeyTask */
}

使用裸机,定时器中断模式,10ms一次定时器中断,cubemx已配置好多定时器中断周期

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)     /* 定时器重装载中断回调函数 */
{
    if(htim == &htim7) 
    {
        key_scan();  /* 按键扫描 */
    }
    
}

代码部分

key.c 全部代码

/**
 ****************************************************************************************************
 * @file        key.c
 * @author      盾迷
 * @version     V1.0
 * @date        2024-11-1
 * @brief       独立按键扫描驱动代码,支持长按短按
 ****************************************************************************************************
 */
 
#include  "key.h"

/* 定义按键端口(只有这部分需要修改)
    例如这样,一共三个按键,PA0 PA1 PC3,则需要填写为:
    GPIO_TypeDef* ports[] = {GPIOA, GPIOA, GPIOC}; 
    uint16_t pins[] = {GPIO_PIN_0, GPIO_PIN_1, GPIO_PIN_3}; 
    上下一一对应,按键顺序从左到右
*/

GPIO_TypeDef* ports[] = {USER_KEY_GPIO_Port, KEY1_GPIO_Port, KEY2_GPIO_Port}; 
uint16_t pins[] = {USER_KEY_Pin, KEY1_Pin, KEY2_Pin}; 


/* 程序部分 */
#define KEYS_COUNT (sizeof(pins) / sizeof(pins[0]))     /* 读取按键数量 */
keys key[KEYS_COUNT];   /* 定义结构体数组存放数据 */

void shortkey(uint8_t key)   /* 短按事件(需要更多按键直接添加case) */
{
    switch(key) 
	{
		case 0:/* 按键1短按事件 */
		{
            HAL_GPIO_TogglePin(LED_R_GPIO_Port,LED_R_Pin);
		}
		break;
		case 1:/* 按键2短按事件 */
		{
            HAL_GPIO_TogglePin(LED_G_GPIO_Port,LED_G_Pin);
		}
		break;
        case 2:/* 按键3短按事件 */
		{
            HAL_GPIO_TogglePin(LED_B_GPIO_Port,LED_B_Pin);
		}
		break;
    }
}

void longkey(uint8_t key)   /* 长按事件(需要更多按键直接添加case) */
{
    
    switch(key)
	{
		case 0:/* 按键1长按事件 */
		{
			HAL_GPIO_TogglePin(LED_R_GPIO_Port,LED_R_Pin);
		}
		break;
		case 1:/* 按键2长按事件 */
		{
            HAL_GPIO_TogglePin(LED_G_GPIO_Port,LED_G_Pin);
		}
		break;
        case 2:/* 按键3长按事件 */
		{
            HAL_GPIO_TogglePin(LED_B_GPIO_Port,LED_B_Pin);
		}
		break;
    }
}


/* 按键扫描部分 */
void key_scan()
{
    uint8_t i=0;
    /* 数据位循环读取GPIO引脚高低电平 */
    for(i=0;i<KEYS_COUNT;i++)
    {
        key[i].key_dat=HAL_GPIO_ReadPin(ports[i],pins[i]);
    }
    
    /* 每一轮开始判断短按是否触发 */
    for(i=0;i<KEYS_COUNT;i++)
    {
        if(key[i].key_judge ==0 && key[i].key_flag==1)
        {
            /* 触发短按事件并清除标志位 */
            shortkey(i);
            key[i].key_flag=0;
        }
    }
    /* 状态位判断 */
    for(i=0;i<KEYS_COUNT;i++)
	{
		switch(key[i].key_judge)    /* 按键判断位,判断按键是否按下,总共判断三次消除抖动 */
		{
			case 0:
			{
				if(key[i].key_dat==0)   /* 如果按键按下 */
				{
					key[i].key_judge=1;     /* 按键按下判断位配置为1,进入下一次判断 */
					key[i].key_time=0;      /* 时间清零 */
				}
			}
			break;
			case 1:
			{
				if(key[i].key_dat==0)       /* 重复判断按键按下,消除抖动 */
				{
					key[i].key_judge=2;
				}
				else
				{
					key[i].key_judge=0;     /* 如果按键未按下,判断位归零。再重复消抖操作 */
				}
			}
			break;
			case 2:
			{
				if(key[i].key_dat==1)        /* 按键未按下,判断位归零。再重复消抖操作 */
				{
					key[i].key_judge=0;
				}
				else               
				{
					key[i].key_time++;      /* 按键按下,时间位不断自加1 */
					if(key[i].key_time<100)
					{
						key[i].key_flag=1;  /* 时间位小于100,短按标志置1 */
					}
					else
					{
						key[i].key_longflag=1;  /* 时间位大于100,长按标志置1 */
                        /* 触发长按事件并清除标志位 */
                        longkey(i);
                        key[i].key_longflag=0;
                        key[i].key_time=0;
                        key[i].key_judge=3;
					}
				}
			}
			break;
            case 3:     /* 执行长按后第一轮扫描,清除短按标志位,防止误触发 */
			{
				if(key[i].key_dat==1)
				{
					key[i].key_flag=0;      /* 清除短按标志位 */
                    key[i].key_judge=0;     /* 复位状态 */
					key[i].key_time=0;      /* 时间清零 */
				}
			}
			break;
            default:    /* 出错时清除短按标志位,防止误触发 */
               	if(key[i].key_dat==1)
				{
					key[i].key_flag=0;      /* 清除短按标志位 */
                    key[i].key_judge=0;     /* 复位状态 */
					key[i].key_time=0;      /* 时间清零 */
				}
            }	
        }
}

key.h 全部代码

/**
 ****************************************************************************************************
 * @file        key.h
 * @author      盾迷
 * @version     V1.0
 * @date        2024-11-1
 * @brief       独立按键扫描驱动代码,支持长按短按
 ****************************************************************************************************
 */

#ifndef _KEY_H_
#define _KEY_H_
 
#include "main.h"
 
typedef struct 
{
	unsigned char key_dat;//按键数据标志位
	unsigned char key_judge;//按键按下的判断位
	unsigned char key_flag;//按下标志位
	unsigned char key_longflag;//长按标志位
	unsigned char key_time;//按键时间标志位
}keys;
void key_scan(void);
 
 
#endif 

评论

  1. 叁叁柒肆
    Windows Edge 130.0.0.0
    1 月前
    2024-11-01 22:44:40

    test

    • 博主
      叁叁柒肆
      Windows Chrome 130.0.0.0
      1 月前
      2024-11-02 10:28:19

      我也test

  2. 叁叁柒肆
    Windows Edge 130.0.0.0
    1 月前
    2024-11-02 10:41:49

    test

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇