背景

只要使用单片机,按键检测基本上是一定要实现的功能。按键检测要好用,最重要的是实时和去抖。初学者往往会在主循环调用按键检测程序(实时)并利用延时去抖(准确)。这种在主循环内延时的做法对整个程序非常不友好,也非常不高效。因此,本篇就我自己实现的一个检测按键并可判断按键是否长短按的程序做个介绍和记录。

正文

在硬件连接上,按键一端连接在普通IO口上,另一端接地,IO配置为内部弱上拉。

在软件上,先配置一个5ms定时器并打开中断,每进入该定时中断则置位一次标志位“key_handle”。接着在主循环调用一个“scan_key()”函数,判断“key_handle”标志位是否在定时器内被置位,若被置位则将该位复位并读取连接按键的IO口值。

此时,“scan_key()”函数内分为按键按下和松开两个分支:

  • 按键按下,则计数值“longkey”每隔5ms自加一次,因为这个分支每隔5ms才会进入执行一次;

  • 按键放开,则先判断“longkey”的值,若“longkey”的值换算出来代表按键按下时间在10ms-1s内,(10ms是去抖值,1s是与短按与长按的分界点。)则判断按键为短按;若“longkey”的值大于1s,则判断按键为长按。并将按键状态赋值给按键状态变量“keybuf”。同时,由于此时按键已经放开,因此“longkey”的值要置位“0”等待用户下次按下按键并执行从“0”开始的自加操作。

若程序又一次进入按键检测代码段,说明所有功能块代码已经获知key状态,有对key感兴趣的代码段也肯定已经进行过相应处理,因此此时要及时将“keybuf”置为无按键按下状态以此来同步实际按键状态。

实际代码如下:

void scan_key(void)
{
unsigned char key_status; if((longkey == 0) && (keybuf != _KEYNULL)){
// 在keybuf被标记为长按或短按后,若是按键已经松开,
// 则在主循环跑完一次后,及时将按键状态标记为无按键按下。
keybuf = _KEYNULL;
}
if(key_handle == _ON) { //5ms进入一次
key_handle = _OFF; // 复位5ms标志位
key_status = GPIO_ReadInputDataBit(KEYRESET_GPIO_PORT, KEYRESET_GPIO_PIN);
if(key_status == 0) { //按下按键
longkey++;
}
else { // 松开按键
if((longkey >= 3) && (longkey <= 100) ){ // 15ms - 1s
keybuf = _SHORTKEY;
} else if(longkey >= 200) { // 2s
keybuf = _LONGKEY;
} else {
keybuf = _KEYNULL;// 若为扰动,按键状态也该为无按键按下
}
longkey = 0;
}
}
}

补充:

Tony~Liu讨论了下,发现其实还有效率更高,占用CPU更少的按键检测办法。

在硬件上,按键连接在具有外部中断的IO口上,按键连接在该IO口上的脚外部上拉,按键另一端接地。

在软件上,连接按键的IO口配置为双边沿中断,同时配置一个1ms定时器中断。当按键按下时,触发外部中断,在外部中断内判断IO口电平,以此确定此为上升沿还是下降沿。下降沿则代表按键按下,开始计时,上升沿则代表按键松开,停止计时。上升沿中断时,在中断内置位“key_handle”,主循环在判断到“key_handle”被置位后,则开始判断计时器时间,若是时间在10ms-1s内,(10ms是去抖值,1s是与短按与长按的分界点。)则判断按键为短按;若时间大于1s,则判断按键为长按。具体实施也很简单,在此就不再贴代码,只是说说这种思想。

至此,记录完毕

记录时间:2017-1-19

记录地点:深圳WZ

STM32f103按键检测程序实现长按短按的更多相关文章

  1. 第33章 TIM—电容按键检测—零死角玩转STM32-F429系列

    第33章     TIM—电容按键检测 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/fir ...

  2. 长连接 短连接 RST报文

    https://baike.baidu.com/item/短连接 短连接(short connnection)是相对于长连接而言的概念,指的是在数据传送过程中,只在需要发送数据时,才去建立一个连接,数 ...

  3. 第12章 GPIO输入—按键检测

    第12章     GPIO输入—按键检测 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/fi ...

  4. 第12章 GPIO输入-按键检测—零死角玩转STM32-F429系列

    第12章     GPIO输入—按键检测 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/fi ...

  5. nRF51822外设应用[2]:GPIOTE的应用-按键检测

    版权声明:本文为博主原创文章,转载请注明作者和出处.    作者:强光手电[艾克姆科技-无线事业部] 1. nRF51822寄存器类型 nRF51822的寄存器和一般的单片机有所差别,nRF51822 ...

  6. 第13章 GPIO输入—按键检测

    本章参考资料:<STM32F76xxx参考手册>.库帮助文档<STM32F779xx_User_Manual.chm>. 按键检测使用到GPIO外设的基本输入功能,本章中不再赘 ...

  7. STM32F103 串口-IAP程序升级

    STM32F103 串口-IAP程序升级 通常情况下我们给STM32系列的单片机烧录程序文件的时候,使用SWD.J-link或者通过设置BOOT引脚后,使用串口进行程序下载,这样的方式直接一次性将程序 ...

  8. Scheme语言实例入门--怎样写一个“新型冠状病毒感染风险检测程序”

    小学生都能用的编程语言 2020的春季中小学受疫情影响,一直还没有开学,孩子宅在家说想做一个学校要求的研究项目,我就说你做一个怎么样通过编程来学习数学的小项目吧,用最简单的计算机语言来解决小学数学问题 ...

  9. 按键检测GPIO输入

    1. 项目 通过按键控制开关LED灯,按下按键灯亮,再按一下灯灭. 2. 代码 mian.c #include "stm32f10x.h" //相当于51单片机中的 #includ ...

随机推荐

  1. Go语言的切片slice基本操作

    感觉比数组好用,首选. package main import ( "fmt" ) //main is the entry of the program func main() { ...

  2. hdu5081

    题意有点绕,不过读懂了之后并不难 以Si结尾容易想到ac自动机,建好ac自动机并将fail指针反向即可得到一棵树 那么操作1就是将若干个子树的并中的节点全部权值+1 操作2就是将求若干个节点到根的路径 ...

  3. Nodejs解决所有跨域请求

    Nodejs解决所有跨域请求 app.use(function(req, res, next) { res.setHeader('Access-Control-Allow-Origin', '*'); ...

  4. dokcer常用命令

    文章来自于 CSDN docker常用命令详解 docker常用命令分类 常用命令 docker run -d --name express-docker-demo --restart=always ...

  5. Windows7 SP1旗舰版精简版最终版本

    2016年6月9号,老毛子@lopatkin大神针对Win7 SP1旗舰版精简版进行了最终更新,此次主要是之前小问题的修复和调整.该版为Windows 7 SP1 简体中文旗舰版最新版,包含2016年 ...

  6. HDU 变形课 1181【DFS/BFS】

    变形课 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others) Total Submissi ...

  7. 洛谷——P1017 进制转换

    P1017 进制转换 题目描述 我们可以用这样的方式来表示一个十进制数: 将每个阿拉伯数字乘以一个以该数字所处位置的(值减1)为指数,以10为底数的幂之和的形式.例如:123可表示为 1\times ...

  8. 【数论】【欧拉函数】【筛法求素数】【乘法逆元】【快速幂取模】bzoj2186 [Sdoi2008]沙拉公主的困惑

    http://www.cnblogs.com/BLADEVIL/p/3490321.html http://www.cnblogs.com/zyfzyf/p/3997986.html 翻了翻题解,这两 ...

  9. Problem M: 第几天——C语言初学者百题大战之十八

    #include<stdio.h> int main() { int a,b,c,s; scanf("%d-%d-%d",&a,&b,&c); ...

  10. Spring的Aop 注解配置

    1,导包 2,准备目标对象 package com.songyan.anno; public interface UserService { void save(); void delete(); v ...