STM32-蓝桥杯嵌入式之三行按键检测(按键的长、短,单击、双击)

目录

  • STM32-蓝桥杯嵌入式之三行按键检测(按键的长、短,单击、双击)
    • 一、检测按键下降沿分析
    • 二、检测按键上升沿分析
    • 三、按键检测程序的核心代码
    • 三、按键检测单击与双击的核心代码

首先先说说异或,异或即相同为0不同为1,可以通过使用异或来判断某一状态发生改变,思路:如果当前状态和上一状态一样,即没有发生改变,那么当前状态和上一状态相异或得到的结果就是0,否则得到的结果不是0,所以通过异或可以用于检测按键的状态发生改变。

后面附上了按键检测程序的核心代码,现在来过一遍:

key_Value |= GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0) | (GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_8) << 1) | \(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1) << 2) | (GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_2) << 3);
key_Value = key_Value ^ 0xff;      // key1按下,key_state = 0x01,如果没有按键按下,则key_Value = 0

上面这一段程序的作用是检测当前按键的状态,首先key_Value这个变量将按键的状态读取出来,
假设key1按键按下,最后转换得到的key_Value = 0x01,
假设key2按键按下,最后转换得到的key_Value = 0x02,
假设key3按键按下,最后转换得到的key_Value = 0x04,
假设key4按键按下,最后转换得到的key_Value = 0x08,

//Key_Trg = (!key_Value) * (key_Value ^ key_State); // 检测按键的下降沿Key_Trg = key_Value & (key_Value ^ key_State); // 检测按键的上降沿// 情况1:key1按键第一次按下,此时key_State,Key_Trg = 0x01// 情况2:key1按键持续按下,第二次扫描的时候,此时key_State = 0x01,Key_Trg = 0// 情况3:如果没有按键按下,则key_Value = 0,Key_Trg = 0// 由以上的分析可以看出,Key_Trg只有在按键的下降沿那一时刻有值。

上面这一段代码就是检测按键的上升沿和下降沿,这里就用到了我们之前说到的异或,程序中(key_Value ^ key_State)这一段代码通过异或得到了哪一个按键的状态发生了变化

一、检测按键下降沿分析

Key_Trg = key_Value & (key_Value ^ key_State);通过当前按键的状态key_Value去和 (key_Value ^ key_State)相与,

  1. 此时我们假设key1当前时刻被按下,那么key_Value 此时就应该等于0x01,显然此时的按键状态发生了变化,由之前的松开变成了按下状态,那么(key_Value ^ key_State)的值就等于0x01,所以最终结果是0x01,表示当前时刻按键被按下。
  2. 如果按键持续被按下是个什么情况呢,按键被持续按下,那么按键的状态就没有发生变化,由我们上面的分析可知,(key_Value ^ key_State)就为0,那么 key_Value & (key_Value ^ key_State)的值就应该为0啦

二、检测按键上升沿分析

Key_Trg = (!key_Value) * (key_Value ^ key_State);

这一段程序可以用来检测按键的上升沿,为什么要把key_Value取反,然后乘上状态的改变呢?下面来分析分析。
我们知道一个按键的上升沿,就是按键由按下变成松开,首先按键的状态肯定改变了对吧,同样可以用 (key_Value ^ key_State)来记录改变状态的按键,我们要的是按键被释放的状态发生改变的按键,被释放的时候key_Value 应该是为0的,如果被按下key_Value 是不为0的,所以我们要的是key_Value = 0时刻发生变化的按键,所以我们通过将key_Value 取反,如果按键松开,取反后就是1,1乘以发生变化的按键得到的就是变化的按键啦,到此我们的问题就解决了。但是我在写程序的后,最开始写的(!key_Value) &(key_Value ^ key_State),为什么这样子不行呢?经过一阵的深思熟虑过后终于找到根源所在,如果(!key_Value)的值只能是0或者1,变化成二进制不就是0b00000001或者0b00000000了吗?然后与上(key_Value ^ key_State),那么我们就最多只能取出最低位,而将其他的位全部清零了,所以如果这样写的话,最多就只能检测出key1,所以是行不通滴…

三、按键检测程序的核心代码

void Key_Read(void)
{uint8_t key_Value = 0xF0;key_Value |= GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0) | (GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_8) << 1) | \(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1) << 2) | (GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_2) << 3);key_Value = key_Value ^ 0xff;       // key1按下,key_state = 0x01,如果没有按键按下,则key_Value = 0//Key_Trg = (!key_Value) * (key_Value ^ key_State); // 检测按键的下降沿Key_Trg = key_Value & (key_Value ^ key_State); // 检测按键的上降沿// 情况1:key1按键第一次按下,此时key_State,Key_Trg = 0x01// 情况2:key1按键持续按下,第二次扫描的时候,此时key_State = 0x01,Key_Trg = 0// 情况3:如果没有按键按下,则key_Value = 0,Key_Trg = 0// 由以上的分析可以看出,Key_Trg只有在按键的下降沿那一时刻有值。key_State = key_Value;// key_State即保存的是扫描过后的按键的值
}

按键扫描程序的代码

void Key_Scan(void)  // 在主程序中10ms调用一次
{Key_Read();if(Key_Trg == 0x01)   // key1下降沿{LED_Ctrl(0x10,ENABLE);}else if(Key_Trg == 0x02)    // key2下降沿{LED_Ctrl(0x20,ENABLE);}else if(Key_Trg == 0x04)    // key3下降沿{LED_Ctrl(0x40,ENABLE);}else if(Key_Trg == 0x08)    // key4下降沿{LED_Ctrl(0x80,ENABLE);}if(key_State == 0x01)   // key1长按检测{key_pressed_time+=10;if(key_time != 0xffff && ++key_time >= 50)    // 由于是10ms调用一次按键检测,所以计数到50就是500ms,按键按下达到500ms就认为是长按键{key_time = 0xffff;  // 防止重复进入次程序,在松开按键的时候,将key_time置零         }}if(key_State == 0 && Key_Trg == 0){key_pressed_time = 0;key_time = 0;LED_Ctrl(0xF0,DISABLE);}
}

三、按键检测单击与双击的核心代码


如上图,编号①表示第一次按键按下,编号②表示第二次按键按下。我们如果要检测按键的双击与单击,我们肯定就要知道两次按键之间的间隔时间,也就是t,表示第一次按键的上升沿(即松开的时刻)与第二次按键的下降沿(即按键按下的时刻)之间的时间,如果时间在指定的范围内,则判断为双击,否则超时判断为单击

// 按键状态读取函数
void Key_Read(void)
{uint8_t key_Value = 0xF0;key_Value |= GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0) | (GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_8) << 1) | \(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1) << 2) | (GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_2) << 3);key_Value = key_Value ^ 0xff;       // key1按下,key_state = 0x01,如果没有按键按下,则key_Value = 0Key_Trg_Rising = (!key_Value) * (key_Value ^ key_State); // 检测按键的下降沿Key_Trg_Falling = key_Value & (key_Value ^ key_State); // 检测按键的上降沿// 情况1:key1按键第一次按下,此时key_State,Key_Trg = 0x01// 情况2:key1按键持续按下,第二次扫描的时候,此时key_State = 0x01,Key_Trg = 0// 情况3:如果没有按键按下,则key_Value = 0,Key_Trg = 0// 由以上的分析可以看出,Key_Trg只有在按键的下降沿那一时刻有值。key_State = key_Value;// key_State即保存的是扫描过后的按键的值
}
// 按键扫描函数
void Key_Scan(void)
{Key_Read();    // 读一次按键的状态if(key1PressNumber == 1)   // 检测到一次按键的上升沿,开始计时{key1Time += 10;            // 由于按键程序是10ms扫描一次,所以这里加10msif(key1Time >= 150)  // 如果超过1500ms,表示按键是单击,初始化双击检测{// begin// 在这里添加按键单击的代码LCD_DisplayStringLine(Line8,(unsigned char *)"SINGLE              ");// endkey1Time = 0;key1PressNumber = 0;}}if(Key_Trg_Rising == 0x01)   // 按键的上升沿,即按键松开{if(key1PressNumber == 0)   // 表示按键是第一次按键的上升沿{key1PressNumber = 1;     // 做个标记}}if(Key_Trg_Falling == 0x01)  // 检测到按键的下降沿{LED_Ctrl(0x10,ENABLE);     if(key1PressNumber == 1)  // 如果已经捕获到了一次按键的上升沿,并且现在还没有超时,那么这就是一个双击的动作{// begin// (在这里添加双击需要处理的程序)// endLCD_DisplayStringLine(Line8,(unsigned char *)"DOUBLE              "); key1Time = 0;key1PressNumber = 0;     // 初始化按键双击相关的变量}        }else if(Key_Trg_Falling == 0x02){LED_Ctrl(0x20,ENABLE);}else if(Key_Trg_Falling == 0x04){LED_Ctrl(0x40,ENABLE);}else if(Key_Trg_Falling == 0x08){LED_Ctrl(0x80,ENABLE);}if(key_State == 0x01){key_pressed_time+=10;if(key_time != 0xffff && ++key_time >= 50){key_time = 0xffff; // 防止重复进入次程序,在松开按键的时候,将key_time置零         }}if(key_State == 0 && Key_Trg_Falling == 0)    // 按键松开{key_pressed_time = 0;key_time = 0;LED_Ctrl(0xF0,DISABLE);}
}

STM32-蓝桥杯嵌入式之三行按键检测(按键的长、短,单击、双击)相关推荐

  1. 蓝桥杯嵌入式 ---- “空手套白狼“ 之 按键长按 短按

    文章目录 前言 一.原理图 二.由原理图得到的信息 三.按键初始化 四.按键的应用方法 五.按键在主函数的应用方法 ----长按 & 短按 前言 本文是基于嵌入式开发板CT117E,stm32 ...

  2. STM32蓝桥杯嵌入式PWM输出

    文章目录 前言 一.原理图 二.定时器输出PWM原理 三.cubemx的配置 四.代码编写 五.波形查看 总结 前言 本篇文章将为大家讲解定时器的PWM输出,PWM可以说是一个比较重要的考点希望大家能 ...

  3. 突击蓝桥杯嵌入式(四)——滴答定时器、按键的三行代码消抖、LCD与ADC

    突击蓝桥杯嵌入式(四)--滴答定时器.按键的三行代码消抖.LCD与ADC 1.滴答定时器定时运行 我们利用滴答定时器,让LED每隔1s闪烁一次 //首先我们定义一个变量 __IO uint32_t u ...

  4. stm32入门学什么板子_“蓝桥杯”嵌入式stm32开发入门(1)概述

    声明:笔者绝不是给"蓝桥杯"打广告,而是笔者曾经参加过蓝桥杯嵌入式设计与开发比赛,想借此机会总结并分享自己的学习中的点点滴滴. 此系列教程将以蓝桥杯官方指定的开发板和接口板来深入浅 ...

  5. 蓝桥杯嵌入式STM32 G431 HAL库开发速成指南(1)LED

    本教程适用于报名参加蓝桥杯嵌入式用新开发板(G431)且想要快速开发的小白,不具体讲解复杂的原理,只讲Cubemx初始化配置以及在KEIL里面使用相应的库函数功能对外设进行编程. CUBEMX配置流程 ...

  6. 蓝桥杯嵌入式(G431RBT6):按键

    文章目录 前言 一.单击按键 二.按键长短按 总结 前言 按键可以说是蓝桥杯嵌入式组必考的内容,按键简单,但却很重要.板子上的功能都是围着按键展开的. 本文主要讲解按键长短按,定义了一个结构体,用来存 ...

  7. 蓝桥杯嵌入式1--滴答定时器,输入输出模式,LED,按键

    蓝桥杯嵌入式1--滴答定时器,输入输出模式,LED,按键 滴答定时器 输入输出模式 LED 按键 滴答定时器 滴答定时器是放在stm32内核中的一个定时器,用户不可以随便操作滴答定时器的寄存器,滴答定 ...

  8. 蓝桥杯嵌入式第七届省赛——“模拟液位检测告警系统”旧板标准库

    一.赛题分析 模拟液位检测告警系统,涉及到KEY.ADC.EEPROM.LED.USART.LCD等模块.本届赛题相对简单,各个模块均可在往期文章中找到配置方法和编写说明.如: 蓝桥杯嵌入式--第六届 ...

  9. 【蓝桥杯嵌入式(G431-HAL库)】Led 与按键

    [备赛蓝桥杯嵌入式(G431-HAL库)]Led 与按键 实训平台:STM32G431RBT6 辅助工具:STM32CubeMx 01 基本简介 Led和按键是GPIO口输入和输出的应用. Led考察 ...

最新文章

  1. pangolin最新版 v2.5.2.975
  2. PreparedStatement和CallableStatement都可以调用存储过程
  3. Golang面向API编程-interface(接口)
  4. 如何将手机投屏到电脑_手机如何投屏到电脑上?详细教程看这里,手机投屏
  5. Linux eBPF 程序构成与通信原理
  6. 从入门到入土:在kali中安装Nessus详细操作
  7. 《快速开发》通过Maven创建WebService项目Hello World!
  8. 经典常用判断字符串是否有值
  9. linux中pak命令,Linux常用包管理及命令
  10. 超市称秤小票用计算机怎么算,电脑收银系统如何连接电子条码秤
  11. 三年级计算机帮助我们学本领,三年级作文学本领40
  12. 华为交换机根据已知一个IP查他对应的MAC地址和交换机端口命令
  13. CSS 让元素内子元素翻转排序
  14. 速学TypeScript-精简划重点手册-上册
  15. 给俺的 CSDN 博客加背景音乐 - 高大尚的《心经》背景音乐
  16. 四轴笔记----无线透传模块|无线图传|遥控和接收机|无线数传
  17. 华为mate40计算机,华为Mate40 Pro+电脑,工作事半功倍就差这一步
  18. 基于密码的移动办公安全能力体系构建
  19. 安卓在GooglePlay上线后同时平板也能搜到
  20. 频繁撤单有风险?--这些委托类型让您享受“撤单豁免权”

热门文章

  1. 网页布局(layout布局)
  2. Windows10下安装MXNet-走过的那些坑
  3. 贴片电阻代理商教您贴片电阻丝印阻值怎么看
  4. 【Shader特效】—— 音符跳动
  5. 软件设计报告 房地产中介系统及java源代码_javaweb房产中介管理系统(我2013年的毕业设计,含开题报告、中期检查、毕业论文、答辩PPT、文献综述等一系列文档)...
  6. MySQL 语句中执行优先级——and比or高
  7. 双移线驾驶员模型,多项式双移线模拟 采用多项式搭建双移线期望路径,基于郭孔辉单点预瞄理论,搭建双移线simulink驾驶员模型
  8. 最新沪深300股票一览
  9. 史诗级学术骗局!一博士狂编 200 多篇论文,被揭发后畏罪自杀....
  10. 运用计算机意味着公司朝,计算机与信息技术基础(第4版)第1章教程范本.pptx