MCU短按长按的功能

这篇具有很好参考价值的文章主要介绍了MCU短按长按的功能。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

.外设:一个io口、一个定时器。
为了降低上手的门槛,本文仅使用一个IO口作演示。

实现思路
使用定时器,定时20ms来读取简化的按键状态机。
这里简化了状态机,大家只需明白三个概念。

状态:数量为有限个,记录按键状态。可根据条件切换。对应的代码中,用switch case来匹配不同的状态
条件:就是一些简单的判断。对应的代码,用if来判断按键按下或释放,判断时间计数的长短
事件:在特定的状态和条件下,产生的事件。代码只有三个事件:Null(空闲)SingleClick(短按)LongPress(长按)
思路图解:

MCU短按长按的功能

3. 长按、单击 定义
长按事件:按下时间大于1s,释放后响应。(不支持连按,若需要连按,进行简单修改即可)
单击事件:按下时间小于1s, 释放后响应。

4.代码分析
4.1 外设准备

4.2 类型、变量定义
4.2.1按键事件
枚举型名称:KEY_EventList_TypeDef
本文实现短按长按功能,故只有三种事件:无事件、短按事件、长按事件
对应代码,即:空闲、单击、长按

typedef enum _KEY_EventList_TypeDef 
{
    KEY_Event_Null            = 0x00, // 空闲
    KEY_Event_SingleClick  = 0x01, // 单击
    KEY_Event_LongPress    = 0x02 // 长按
}KEY_EventList_TypeDef;

4.2.2 按键电平、动作
因为有的电路按下时,引脚为低电平;有的按下时,引脚却为高电平。这里将电平、动作分开,更方便移植。
枚举型名称:KEY_PinLevel_TypeDef
即:高、低电平。

// 按键引脚的电平
typedef enum

    KKEY_PinLevel_Low = 0,
    KEY_PinLevel_High
}KEY_PinLevel_TypeDef;

枚举型名称:KEY_Action_TypeDef
按键只有按下和没按下俩个动作:
即:按下、释放

// 按键动作,
typedef enum

    KEY_Action_Press = 0,
    KEY_Action_Release
}KEY_Action_TypeDef;

4.2.3 按键状态
枚举型名称:KEY_StatusList_TypeDef
思路图解的分析,分为如下几个状态。
即:空闲、消抖、确认按下、确认长按

// 按键状态
typedef enum _KEY_StatusList_TypeDef 
{
    KEY_Status_Idle     = 0, // 空闲
    KEY_Status_Debounce ,    // 消抖
    KEY_Status_ConfirmPress    ,    // 确认按下    
    KEY_Status_ConfirmPressLong,    // 确认长按
}KEY_StatusList_TypeDef;

4.2.4 按键配置结构体
按键配置信息的结构体名称:KEY_Configure_TypeDef
打包好按键的基本属性。

typedef struct _KEY_Configure_TypeDef 
{
    uint16_t                        KEY_Count;                 // 按键长按时长计数
    KEY_Action_TypeDef             KEY_Action;                // 按键动作,按下或释放
    KEY_StatusList_TypeDef         KEY_Status;                // 按键状态
    KEY_EventList_TypeDef          KEY_Event;                 // 按键事件
    KEY_PinLevel_TypeDef           (*KEY_ReadPin_Fcn)(void);  // 读引脚电平函数
}KEY_Configure_TypeDef;


成员解释:

KEY_Count:计数,记一个数为20ms。
KEY_Action:按键动作,按下或者释放。
KEY_Status:记录按键的状态值。
KEY_Event:记录按键触发的事件。
KEY_ReadPin_Fcn:读取按键电平值的函数指针。方便移植。
4.3 变量、函数、宏定义
4.3.1宏定义
KEY_LONG_PRESS_TIME :
短按、长按的时长分界线。大于–>长按,小于–>短按。
KEY_PRESSED_LEVEL:
按键被按下的实际电平,我的电路里,按键按下引脚接地。所以为低电平。
/**************************************************************************************************** 
*                             长按、单击 定义
* 长按事件:按下时间大于 KEY_LONG_PRESS_TIME,释放后响应。(不支持连按,需要连按响应可自己配置)
* 单击事件:按下时间小于 KEY_LONG_PRESS_TIME 释放后响应。
****************************************************************************************************/
// 长按时长的宏定义
#define KEY_LONG_PRESS_TIME    50  // 20ms*50 = 1s
#define KEY_PRESSED_LEVEL      0   // 按键被按下时的电平

4.3.2 变量定义
KeyCfg:全局变量,打包了按键的各个属性。

/**************************************************************************************************** 
*                            按键配置信息的全局结构体变量
****************************************************************************************************/
KEY_Configure_TypeDef KeyCfg={
        
        0,                        // 按键长按时长计数
        KEY_Action_Release,        // 按键动作,按下或释放 
        KEY_Status_Idle,        // 按键状态
        KEY_Event_Null,         // 按键事件
        KEY_ReadPin             // 读引脚电平函数
};

4.3.3函数定义
局部函数:

//读取引脚的电平
static KEY_Action_TypeDef KEY_ReadPin(void) 
{
  return (KEY_Action_TypeDef)GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0);
}

// 获取按键动作,按下或释放,保存到结构体
static void KEY_GetAction(void) 
{
    if(KeyCfg.KEY_ReadPin_Fcn() == KEY_PRESSED_LEVEL)
    {
        KeyCfg.KEY_Action = KEY_Action_Press;
    }
    else
    {
        KeyCfg.KEY_Action =  KEY_Action_Release;
    }
 
}


KEY_ReadPin:读取PA_0的电平状态。
KEY_GetAction:将读取到的电平状态转换为实际的按下或释放的动作。
状态处理函数
KEY_ReadStateMachine:编写,思路完全按照前文手绘的思路图像
首先读取按键的动作,再在switch case 里面匹配引脚的状态,case下用if判断按键动作或按下的时长,对状态、事件进行赋值。

void KEY_ReadStateMachine(void)
{

    
    KEY_GetAction();
    
    switch(KeyCfg.KEY_Status)
    {
        //状态:没有按键按下
        case KEY_Status_Idle:
            if(KeyCfg.KEY_Action == KEY_Action_Press)
            {
                KeyCfg.KEY_Status = KEY_Status_Debounce;
                KeyCfg.KEY_Event = KEY_Event_Null;
            }
            else
            {
                KeyCfg.KEY_Status = KEY_Status_Idle;
                KeyCfg.KEY_Event = KEY_Event_Null;
            }
            break;
            
        //状态:消抖
        case KEY_Status_Debounce:
            if(KeyCfg.KEY_Action == KEY_Action_Press)
            {
                KeyCfg.KEY_Status = KEY_Status_ConfirmPress;
                KeyCfg.KEY_Event = KEY_Event_Null;
            }
            else
            {
                KeyCfg.KEY_Status = KEY_Status_Idle;
                KeyCfg.KEY_Event = KEY_Event_Null;
            }
            break;    
            
        //状态:确认按下
        case KEY_Status_ConfirmPress:
            if( (KeyCfg.KEY_Action == KEY_Action_Press) && ( KeyCfg.KEY_Count >= KEY_LONG_PRESS_TIME))
            {
                printf("KEY_Status_ConfirmPressLong\r\n");
                KeyCfg.KEY_Count = 0;
                KeyCfg.KEY_Status = KEY_Status_ConfirmPressLong;
                KeyCfg.KEY_Event = KEY_Event_Null;
                
            }
            else if( (KeyCfg.KEY_Action == KEY_Action_Press) && (KeyCfg.KEY_Count < KEY_LONG_PRESS_TIME))
            {
                printf("继续按下 %d\r\n",KeyCfg.KEY_Count);
                KeyCfg.KEY_Count++;
                KeyCfg.KEY_Status = KEY_Status_ConfirmPress;
                KeyCfg.KEY_Event = KEY_Event_Null;
            }
            else
            {
                printf("突然gg,按短了 %d\r\n",KeyCfg.KEY_Count);
                KeyCfg.KEY_Count = 0;
                KeyCfg.KEY_Status = KEY_Status_Idle;
                KeyCfg.KEY_Event = KEY_Event_SingleClick;

            }
            break;    

            
        //状态:确认长按
        case KEY_Status_ConfirmPressLong:
            printf("KEY_Status_ConfirmPressLong\r\n");
            if(KeyCfg.KEY_Action == KEY_Action_Press) 
            {   // 一直等待其放开
                printf("一直按着 KEY_Status_ConfirmPressLong\r\n");
                KeyCfg.KEY_Status = KEY_Status_ConfirmPressLong;
                KeyCfg.KEY_Event = KEY_Event_Null;
                KeyCfg.KEY_Count = 0;
            }
            else
            {
                KeyCfg.KEY_Status = KEY_Status_Idle;
                KeyCfg.KEY_Event = KEY_Event_LongPress;
                KeyCfg.KEY_Count = 0;
            }
            break;    
        default:
            break;
    }

}


5.1定时器中断:
直接调用KEY_ReadStateMachine()函数即可,将读取到的事件保存到KeyCfg.KEY_Event变量。

extern KEY_Configure_TypeDef KeyCfg;
//定时器3中断服务程序
void TIM3_IRQHandler(void)   //TIM3中断
{

    if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)  //检查TIM3更新中断发生与否
    {
        TIM_ClearITPendingBit(TIM3, TIM_IT_Update  );  //清除TIMx更新中断标志 
            KEY_ReadStateMachine();  //调用状态机
            
            if(KeyCfg.KEY_Event == KEY_Event_SingleClick)
            {
                printf("单击\r\n");//事件处理
            }
            if(KeyCfg.KEY_Event == KEY_Event_LongPress)
            {
                printf("长按\r\n");//事件处理
            }
        }
}

5.2 main函数
这里main函数十分简洁。初始化即可。
实际应用时,事件处理的代码不建议放在定时器里面。

int main(void)
{    
    uart_init(115200); // 用于查看输出
    TIM3_Int_Init(200-1,7200-1); //调用定时器使得20ms产生一个中断
    //按键初始化函数
    KEY_Init();
    
    while(1);

}     文章来源地址https://www.toymoban.com/news/detail-428559.html

到了这里,关于MCU短按长按的功能的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 短按开机/长按关机的电路和代码实现思路

    在我们实际的项目中,我们做的设备或者自己的DIY一个东西的时候,经常要实现的一个功能是:通过一个按键实现短按开机,长按关机。下面我就给大家简单介绍一下其中一种的实现方法,包含电路和代码的实现 首先是电路图: 先给大家介绍一下上面几个网络标号的意义:

    2024年02月12日
    浏览(62)
  • (软件02)单片机按键处理,区分短按与长按

    本文目录     本篇前言     代码思路     实操练习 本篇前言         今天接着上篇与大家继续分享软件方面关于按键事件的处理,上篇软件01篇已提到整个软件框架时基的处理,其中提到了关于按键的处理,这篇将具体地介绍按键处理的思路与实例。         话不

    2024年02月03日
    浏览(29)
  • Android 开关机POWER键 长按短按代码分析

    路径:frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java

    2024年02月11日
    浏览(38)
  • 单个按钮实现长按开关机,短按可以当普通按钮控制单片机

    在看郭天祥老师的课程时学到的电路,之后发现这种控制原理很流行。 核心思路有两个: 1、用两个二极管隔离开q1和io_check,两端都可以响应按钮的状态,从而实现按钮复用。 2、用d2和q2,实现了与的功能,两者任意一个对地短路都可以保持mcu供电。 使用步骤: 1、长按sw

    2024年01月18日
    浏览(27)
  • STM32 -- 实现按键的长按与短按检测(其他单片机可移植)

    目录 资源获取 一 前言 二 思路  三 实现代码 1.主要代码 四 完整代码 Key.h Key.c 该改进版本(1ms太繁琐了,我改成了25ms检测一次)   1.定时器部分 2.按键检测部分  五、参考 欢迎关注微信公众号--星之援工作室 发送(长短按检测) 今天在逛博客的时候,偶然看到了一

    2024年02月12日
    浏览(26)
  • 蓝桥杯单片机 | 特训案例【进阶02】长按与短按控制数码管显示

    新建工程,以 I/O模式 编写代码,在CT107D单片机综合训练平台上,实现以下功能: 1、系统上电后,关闭蜂鸣器和继电器,关闭全部指示灯,数码管最右边两位显示计数初始值28,其余数码管关闭。 2、利用 定时器0 实现 10ms 的间隔定时,将其作为长定时的基本单位,用于记录

    2023年04月09日
    浏览(40)
  • 蓝桥杯单片机学习日记3-矩阵键盘的使用,线反转法,三步消抖,按键长按与短按

    此片文章用于记录蓝桥杯单片机的学习 篮球杯单片机上的矩阵按键原理图如下:   使用矩阵键盘时,要将跳线帽J5跳至KBD模式。   值得注意的是,若开发板上的单片机使用的为STC15,那么以上原理图适用。如果单片机为IAP15,则在上述原理图中,要将P36换成P42,P37换成P44。  

    2023年04月10日
    浏览(36)
  • MCU常用外设总线

      本文主要讲单片机外设的功能,即这些外设是什么,可以用来干什么,了解了之后我们就可以通过相应的寄存器配置来驱动这些外设。本文带大家深入了解一下这些外设的工作原理,知道了功能之后,对应任意一个MCU都可以找相应功能的寄存器。因为寄存器名字可以不同

    2024年01月22日
    浏览(23)
  • stm32之16.外设定时器——TIM3

       ----------- 源码 其他外设定时器使用方法 打开对应时钟供电  

    2024年02月10日
    浏览(40)
  • # HAL库STM32常用外设教程(四)—— 定时器 基本定时

    1、STM32F407ZGT6 2、STM32CubeMx软件 3、keil5 内容简述: 通篇文章将涉及以下内容,如有错误,欢迎指出 : 1、基础定时器特性 2、基础定时器的结构和功能 3、基础定时器HAL库驱动程序 (1)CubeMx配置 (2)TIM驱动程序   STM32F407有2个高级控制定时器(TIM1、TIM8)、8个通用定时器和

    2024年02月02日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包