• STC15单片机-按键检测单击或长按(外部中断)


    按键检测(外部中断)

    STC15外部中断说明

    在这里插入图片描述

    程序

    文件结构

    在这里插入图片描述

    main.c -> 主函数文件,包含 main 函数等,当用外部中断翻转指示灯时 ,则不用调用函数,否则调用按键扫描函数翻转指示灯;

    Public.c -> 公共函数文件,包含 Delay 延时函数等;

    Sys_init -> 系统初始化函数,包含 GPIO 初始化函数等;

    LED.c -> LED 外设函数,包含 LED 打开、关闭函数等;

    Timer0.c -> 定时器函数,包含定时器初始化,中断函数等;

    KEY.c -> 按键函数,包含按键检测,中断函数等。

    外部中断0配置

    在LED闪烁(定时器)的工程中加上 KEY.c 和 KEY.h 文件,在Sys_Init.c文件中初始化外部中断0,在KEY.c中定义外部中断0中断处理函数,按键检测也是在KEY.c文件中实现

    配置方法跟STC89C52一样

    /*
    * @name   IE_Init
    * @brief  中断初始化
    * @param  None
    * @retval None   
    */
    static void IE_Init()
    {
        IT0 = 1;     //外部中断0选择下降沿触发
        EX0 = 1;     //打开外部中断0
        
        EA = 1;      //打开总中断
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    外部中断0中断处理函数

    /*
    * @name   INT0_isr
    * @brief  外部中断0处理函数
    * @param  None
    * @retval None   
    */
    void INT0_isr() interrupt 0
    {
        KEY.KEY_Flag = 1;
        //Run_LED.Run_LED_Flip();		//运行指示灯翻转
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    使用外部中断就可实现按键按下运行指示灯翻转的效果

    然后再实现按键检测,实现单击和长按的不同效果

    KEY.c:

    /* Includes ------------------------------------------------------------------*/
    #include 
    
    /* Private define-------------------------------------------------------------*/
    
    /* Private variables----------------------------------------------------------*/
    static void KEY_Detect();
    /* Public variables-----------------------------------------------------------*/
    KEY_t KEY1 = {FALSE,FALSE,FALSE,FALSE,KEY_Detect};
    /* Private function prototypes------------------------------------------------*/
    
    /*
    * @name   KEY_Detect
    * @brief  按键检测
    * @param  None
    * @retval None   
    */
    static void KEY_Detect()
    {
        uint8_t i;
        //单击检测
        if(KEY1.KEY_Flag == TRUE)        //外部中断改变标志位的值,说明按键被按下
        {
            KEY1.KEY_Flag = FALSE;       //标志位重新置0,为下次按键准备
            EX0 = 0;                    //关闭中断
            if(KEY1_State == 0)
            {
                Public.Delay_ms(5);         //虽然硬件已经有消抖功能,软件再做一次
                if(KEY1_State == 0)
                {
                    KEY1.Click = TRUE;       //单击标志位置1
                }
            }
        }
        //长按检测
        if(KEY1.Click == TRUE)
        {
            KEY1.Press = TRUE;               //如果有按键按下,默认会进行长按
            for(i = 0;i<200;i++)            //每次循环延时10ms,即延时2秒
            {
                Public.Delay_ms(10);
                if(KEY1_State == 1)          //如果这期间按键松开了,则达不到长按的条件
                {
                    KEY1.Press = FALSE;      //长按标志位清0
                    break;                  //提前结束延时
                }
            }
        }
    
        //按键功能
        //单击 -> 运行指示灯翻转
        //长按 -> 运行指示灯闪一下
        if(KEY1.Press == TRUE)
        {
            Run_LED.Run_LED_Flip();
            Public.Delay_ms(100);
            Run_LED.Run_LED_Flip();
        }
        else
        {
            if(KEY1.Click == TRUE)
            {
                Run_LED.Run_LED_Flip();
            }
        }
        KEY1.Click = FALSE;
        KEY1.Press = FALSE;
        EX0 = 1;                        //打开中断
    }
    
    /*
    * @name   INT0_isr
    * @brief  外部中断0中断处理函数
    * @param  None
    * @retval None   
    */
    void INT0_isr() interrupt 0
    {
        KEY1.KEY_Flag = TRUE;
        //Run_LED.Run_LED_Flip();
    }
    
    /********************************************************
      End Of File
    ********************************************************/
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85

    为什么在标志位清0后要关闭外部中断?

    因为在标志位清0时外部中断可能还会被触发,这可能是按键抖动引起的,标志位会重新被置1,在按键检测时会被重复判断

    KEY.h:

    头文件主要是按键引脚定义,结构体变量定义

    #ifndef __KEY_H_
    #define __KEY_H_
    
    //定义按键引脚
    #define KEY1_State P32
    
    //定义结构体类型
    typedef struct 
    {
        uint8_t volatile KEY_Flag;      //按键标志位
        uint8_t Click;                  //单击
        uint8_t Double_Click;           //双击
        uint8_t Press;                  //长按
        void (*KEY_Detect)();
    }KEY_t;
    
    /* extern variables-----------------------------------------------------------*/
    extern KEY_t KEY1;
    /* extern function prototypes-------------------------------------------------*/ 
    
    #endif
    /********************************************************
      End Of File
    ********************************************************/
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    main.c:

    主函数中调用KEY_Detect函数一直检测按键

    /******************************************************************************
      * @file    main.c 
      * @author  
      * @version V1.0
      * @date    2022-xx-xx
      * @Conpany 
      * @project STC15实战项目
    *******************************************************************************/
    
    /* Includes ------------------------------------------------------------------*/
    #include 
    
    /* Private define-------------------------------------------------------------*/
    
    /* Private variables----------------------------------------------------------*/
    
    /* Public variables-----------------------------------------------------------*/
    
    /* Private function prototypes------------------------------------------------*/
    
    /*
    	* @name   main
    	* @brief  主函数
    	* @param  void	
    	* @retval int      
    */
    int main(void)
    {	
    	//系统初始化
    	Hradware.Sys_Init();
    	//系统主循环
    	while(1)
    	{
    		//按键检测
    		KEY1.KEY_Detect();
    	}
    }
    /********************************************************
      End Of File
    ********************************************************/
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
  • 相关阅读:
    【Node.js实战】一文带你开发博客项目(API 对接 MySQL)
    stm32逆向入门
    mvc-servlet
    回溯框架总结
    Linux环境python脚本后台运行
    Linux生产者消费者与信号量
    Filebeat 采集 k8s Pod 和 Events 日志实战操作
    【Seata】04 - Seata TCC 模式 Demo 调用流程分析
    运维知识点-MySQL从小白到入土
    利用轻量一键申请多域名通配符免费证书(Trustasia)
  • 原文地址:https://blog.csdn.net/weixin_46251230/article/details/126659466