蓝桥杯嵌入式按键长短按移植

蓝桥杯嵌入式按键长短按移植

1、外设占用,基本定时器1个,配置为10ms中断

初始化后,打开中断。

HAL_TIM_Base_Start_IT(&htim4);//打开定时器中断

2、按键代码

key.c:

#include "key.h"
#include "oled.h"

struct keys g_key[4] = {0,0,0,0};



/**
 * @brief 按键扫描函数,需要10ms执行一次
 * 
*/
void key_scan(void)
{
    //读取本次扫描电平状态
    g_key[0].state_pin = HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin);
    g_key[1].state_pin = HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin);
    g_key[2].state_pin = HAL_GPIO_ReadPin(KEY3_GPIO_Port,KEY3_Pin);
    g_key[3].state_pin = HAL_GPIO_ReadPin(KEY4_GPIO_Port,KEY4_Pin);
    
    //轮询按键消抖
    for(int i=0;i<4;i++)
    {
        switch(g_key[i].state_step)
        {
            case 0://首次按下
            {
                if(g_key[i].state_pin == 0)
                {
                    g_key[i].state_step = 1;    //跳转到消抖状态
                    g_key[i].time_press = 0;    //清零计时
                }
            }
            break;
            
            case 1://10ms后按键仍按下,说明电平已稳定,完成消抖
            {
                if(g_key[i].state_pin == 0)
                {
                    // g_key[i].flag_press = 1;    //记录短按生效
                    g_key[i].state_step = 2;    //跳转到松手检测
                }
                else
                    g_key[i].state_step = 0;    //否则视为抖动,重新检测
            }
            break;
            
            case 2://读取到松手,本次扫描结束
            {
                if(g_key[i].state_pin == 1)//松手
                {
                    
                    if(g_key[i].time_press < 100)//小于1s视为短按
                    {
                        g_key[i].flag_press = 1;//短按松手生效
                    }
                    else if(g_key[i].time_press >= 100)//大于1s视为长按
                    {
                        g_key[i].flag_press_long = 1;//长按松手生效
                    }
                    g_key[i].state_step = 0;        //回到最初状态
                }
                else
                {
                    g_key[i].time_press++;//未松手就计时
//                    if(g_key[i].time_press >= 100)
//                        g_key[i].flag_press_long = 1;//长按未松手生效,放在这里会由bug,按完不松手会与key_proc里的清零一直冲突,相当于长按一直生效
                }
            }
            break;
        }
    }
}




/**
 * @brief 按键动作处理函数,响应按键动作
 * 
 */
void key_proc(void)
{
    static uint8_t a = 0;
    static uint8_t b = 0;
    if(g_key[0].flag_press == 1)//按键1动作处理
    {
        OLED_ShowNum(0,0,a++,3,16,1);
        OLED_Refresh();

        g_key[0].flag_press = 0;//记住用完后一定要清零,才能继续使用
    }

    if(g_key[0].flag_press_long == 1)//按键1动作处理
    {
        HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);

        g_key[0].flag_press_long = 0;//记住用完后一定要清零,才能继续使用
    }

    if(g_key[1].flag_press == 1)//按键2动作处理
    {
        OLED_ShowNum(0,16,b++,3,16,1);
        OLED_Refresh();

        g_key[1].flag_press = 0;//记住用完后一定要清零,才能继续使用
    }

    if(g_key[1].flag_press_long == 1)//按键2动作处理
    {
        HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);

        g_key[1].flag_press_long = 0;//记住用完后一定要清零,才能继续使用
    }
}

key.h:

#ifndef __KEY_H
#define __KEY_H

#include "main.h"

struct keys
{
    uint8_t state_step;       //判断进程
    uint8_t state_pin;        //按键电平状态
    uint8_t flag_press;       //按键按下标志位
    uint16_t time_press;      //记录按下时间*10ms
    uint8_t flag_press_long;  //长按标志位
};


extern struct keys g_key[];

void key_scan(void);
void key_proc(void);
#endif

定时器中断:

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if(htim->Instance == TIM4)//10ms按键扫描
    {
        key_scan();
    }
}

main.c:

while (1)
  {
      key_proc();
  }
### 蓝桥杯嵌入式系统长短按键的设计与实现 #### 独立按键检测机制 为了改进原有按键程序中存在的优先性和多键操作局限,在新的设计方案中采用了独立的按键检测方式。这种方式允许各个按键能够单独响应用户的输入动作而不互相干扰,从而解决了多个按键同时按下无法识别的问题[^1]。 #### 定时器用于硬件消抖处理 针对按键过程中可能出现的机械颤动现象,利用定时器来完成硬件级别的去抖动工作。具体来说就是在每次检测到按键状态变化之后启动一定时间长度(通常几十毫秒)的时间延迟;如果在这段时间内按键保持稳定,则认为是一次有效的触发事件[^2]。 #### 实现长短按逻辑判断 对于区分长按还是短按的操作需求,可以在按键扫描函数内部引入额外的状态变量来进行跟踪记录。当首次发现某个特定按键被按下时开始计时,并持续监测该按键是否仍然处于闭合状态直到超过预设阈值即定义为一次长时间按压;反之则视为短暂点击释放行为结束后的正常情况下的单击操作。 ```c // main.c 中的部分代码片段展示如何管理按键标志位和延时参数 u8 KEY_Flag = 0; char num = 0; u32 TimingDelay = 0; void Key_Scan(void){ static uint8_t key_down_flag = 0, long_press_flag = 0; if (KEY_GetState(KEY1_PIN) == RESET){ // 检测到按键按下 if (!key_down_flag){ key_down_flag = 1; TimingDelay = SystemCoreClock / 1000 * 50; // 设置50ms防抖时间 while(TimingDelay && KEY_GetState(KEY1_PIN) == RESET); //等待并检查是否有松开 if(!TimingDelay){ // 如果超出了设定的防抖周期还没有放开就是有效按下 if(KEY_GetState(KEY1_PIN) == RESET){ long_press_flag = 1; while(long_press_flag && KEY_GetState(KEY1_PIN) == RESET); if(!long_press_flag){ /* 处理长按 */ }else{ /* 处理短按 */ } } } } } else { key_down_flag = 0; long_press_flag = 0; } } ``` 上述C语言代码展示了基于STM32系列微控制器平台上的一个简化版按键扫描流程实例,其中包含了基本的防抖措施以及简单的长短按分类逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值