三行按键扫描详细解析

news2025/1/18 6:29:25

三行按键扫描基础

核心算法:

unsigned char trg;
unsigned char cont;
void KeyRead( void )
{
    unsigned char readDate = P3^0xff; // 第一行
    trg = readDate & (ReadData ^ cont); // 第二行
    cont = readDate; // 第三行
}

用定时器每隔10ms执行一次按键扫描读取函数

第一行:

P3端口数据并且取反,然后保存到ReadData

第二行:

用来计算触发变量的

第三行:

用来计算连续变量

基础知识

  1. 一位数x异或一用来取反一个数

x ^ 1 = ~x

1 ^ 1 = 0

0 ^ 1 = 1

  1. 一位数x异或零不变

x ^ 0 = x

1 ^ 0 = 1

0 ^ 0 = 0

  1. 一位数x与一用于判断x的值

if((x & 1) == 0) x为0

if((x & 1) == 1) x为1

  1. 一位数x与零用于清零

x & 0 = 0

1 & 0 = 0

0 & 0 = 0

  1. 一位数x或一用于置一

x | 1 = 1

1 | 1 = 1

0 | 1 = 1

  1. 一位数x或零用于判断x的值

if((x | 0) == 1) x为1

if((x | 0) == 0) x为0

模拟状态

初始时候

Cont = 0x00

当没有按键

P30xff

ReadData 读端口并且取反 等于0x00

Trg = ReadData & (ReadData ^ Cont)

Trg = 0x00 & (0x00 ^ 0x00) = 0x00

Cont 等于ReadData,为0x00

结果:

ReadData0x00

Trg0x00

Cont0x00

P30按键按下

P30xfe

ReadData 读端口并且取反 等于0x01

Trg = ReadData & (ReadData ^ Cont)

Trg = 0x01 & (0x01^0x00) = 0x01

Cont 等于ReadData,为0x01

结果:

ReadData0x01

Trg0x01 Trg只会在这个时候对应位的值为1,其它时候都为0

Cont0x01

P30按键按下不松开(长按)

P30xfe

ReadData 读端口并且取反 等于0x01

Trg = ReadData & (ReadData ^ Cont)

Trg= 0x01 & (0x01^0x01) = 0x00

Cont 等于ReadData,为0x01

结果:

ReadData0x01;这个不会变,因为按键没有松开

Trg = 0x00 只要按键没有松开,Trg值永远为 0x00

Cont0x01 只要按键没有松开,Cont值永远为 0x01

P30按键按下松开

P30xff

ReadData 读端口并且取反 等于0x00

Trg = ReadData & (ReadData ^ Cont)

Trg= 0x00 & (0x00^0x01) = 0x00

Cont 等于ReadData,为0x00

结果:回到初始状态

ReadData0x00

Trg0x00

Cont0x00

总结

ReadDataTrgCont
无按下0x000x000x00都为0
第一次扫描P30按下0x010x010x01都为0x01
之后扫描P30按下0x010x000x01
之后扫描P30松开0x000x000x00恢复初始

Trg(triger) 电平从1到0的跳变(下降沿),在对应按键相应位为一

补充一句如果想要判断上升沿 (~ReadData) & (ReadData^ Cont)

Cont(continue)Cont代表的长按键,按着不放Cont的相应位为一

ReadData ^ Cont 解释:

这一次读取结果异或上之前读取结果

如果有变化相应位为一,如果没变化相应位为零

如果没有松手所有位都为零

Trg = ReadData & (0x00)

松手时

Trg = ReadData & (0x01)

这时候就要Trg的值取决于ReadData 设计思路根据基础知识与1判0

只有当读取到按键按下Trg才不等于0

三行按键扫描的改进

产生抖动情况分析

这里我们假设的是抖动时长不超过10ms

在这里插入图片描述

改进程序:

uchar cnt = 0,lastTrg = 0;
void KeyRead( void )
{
    uchar trg = 0,readDate = 0;
    
    //如果我们要读取的只有P30-P33--通过|0xF0消除P34-P37影响
    readDate = (P3|0xF0)*Oxff; 
    trg = (readDate^cnt) & readDate;
    cnt = readDate;
    
    //判断上一次是否产生下降沿,并且当前状态是按键按下状态
    //lastTrg^trg & lastTrg这样写也是为了排除其他位影响
    //如果不是当前位,这个结果都为0
    if((lastTrg^trg & lastTrg) && readDate)
    {
        //执行按键按下的程序
    }
    
}

三行按键扫描的具体应用

单次触发

void KeyProc(void)
{
    if ( trg & 相应位置一 ) //  与1判0
    {
        //处理函数
    }
}

长按和连按

#define KEY 0x02 // 按键
void KeyProc(void)
{
	static keyCnt = 0if (cont & KEY) // 如果按键被按着不放
    {
        //短按处理函数
        //连按连加
        keyCnt ++; // 计数加1
        if (keyCnt > 100) // 10ms*100 = 1S 
        {
        	keyCnt = 0;
            //长按处理函数
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/335252.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++:类和对象(上)

文章目录1 面向过程与面向对象的初步认识2 类的引入3 类的定义4 类的访问限定符及封装4.1 访问限定符4.2 封装5 类的实例化6 类对象模型6.1 如何计算类的大小6.2 类对象的存储方式猜测7 this指针7.1 this指针的引出7.2 this指针的特性8 C语言和C栈(Stack&#xff09…

J-Tech Talk|如何使用Grafana Cloud Alert进行实时监控

J-Tech Talk由 Jina AI 社区为大家带来的技术分享围绕 Python 的相关话题工程师们将深入细节地讲解具体的问题分享 Jina AI 在开发过程中所积累的经验在新一代基于云原生的微服务架构中,不管是业务还是基础设施,服务的可观测性 至关重要!它涵…

git、gitee、github关系梳理及ssh不对称加密大白话解释

温馨提示:本文不会讲解如何下载、安装git,也不会讲解如何注册、使用gitee或GitHub,这些内容网上一大把,B站上的入门课程也很多,自己看看就好了。 本文仅对 git、gitee、github的关系梳理及ssh公钥私钥授权原理用白话讲…

whistle 一个神奇的前端调试工具(抓包\代理工具)

在进行前端开发过程中,我们常常需要对一些接口进行处理,以及当后端接口没有弄好需要我们mock一些假数据,针对这些场景,我们就可以使用whistle 来解决。首先,我们要知道能满足我们需求的工具有很多,例如&…

第十五章 栅格数据重分类、栅格计算器、插值分析

文章目录第十五章 栅格数据分析第一章 栅格数据重分类第一节 栅格数据重分类第二节 栅格重分类的使用第三节 重分类的使用中的空值使用第四节 重分类的案例:分类统计面积第五节 坡度矢量分级图生成第二章 栅格计算器第一节 栅格计算器介绍第二节 栅格计算器使用第三…

操作系统题目收录(六)

1、某系统采用基于优先权的非抢占式进程调度策略,完成一次进程调度和进程切换的系统时间开销为1us。在T时刻就绪队列中有3个进程P1P_1P1​、P2P_2P2​和P3P_3P3​,其在就绪队列中的等待时间、需要的CPU时间和优先权如下表所示。若优先权值大的进程优先获…

Revit怎么生成电线和电器配件,管道附件?

一、Revit中如何自动生成电线 首先框选所有的照明设备,使用过滤器命令,只选中照明设备,如图1所示。 框选之后会出现创建电力系统的界面,选择如图2所示电力的命令。 出现图3中所示选择弧形导线或者带倒角导线,即可以自动…

【数字孪生百科】每周认识一个数字孪生要素 —— 玫瑰图(Rose Diagram)

简介玫瑰图(Rose Diagram),也称之为南丁格尔玫瑰图,极坐标区域图,鸡冠花图,是一种圆形的直方图,是由弗罗伦斯・南丁格尔所发明,用以表达军医院季节性的死亡率的一种图表。由于半径和…

零入门kubernetes网络实战-12->基于DNAT技术使得外网可以访问本宿主机上veth-pair链接的内部网络

视频地址(稍后上传) 本篇文章测试如何让veth pair链接的内网网络可以被本局域网的其他宿主机访问到? 1、测试环境介绍 一台centos虚拟机 # 查看操作系统版本 cat /etc/centos-release # 内核版本 uname -a uname -r # 查看网卡信息 ip a s eth02、网络拓扑 3、操…

银行零售如何更贴近客户?是时候升级你的客户旅程平台了

随着数字化战略推进,各大银行持续加大对线上多渠道的建设投入,客户触达也愈发移动化、智能化。与此同时,手机银行飞速发展产生并累积了大量客户行为数据,呈多样化、海量化等特点,将在用户体验、客户经营、手机银行运营…

SaaS的阴暗面:网络攻击武器化、平民化

你不一定懂编程,甚至都看不懂几行代码,但依然能成为杀伤力十足的黑客,这就是现阶段不少网络攻击的特点:不需要掌握娴熟的技术或代码,仅仅利用成熟的武器化工具,就能通过简单的“一键操作”,对目…

【Java基础】018 -- 面向对象阶段项目上(拼图小游戏)

目录 拼图小游戏(GUI) 一、主界面分析 1、练习一:创建主界面1 2、练习二:创建主界面2(JFrame) 3、练习三:在游戏界面中添加菜单(JMenuBar) ①、菜单的制作 4、添加图片&a…

传奇开服架设要具备什么条件

传奇开服架设要具备什么条件 新手如果想开服的话因具备哪些条件?我来为您解答 1.传奇SF开服的话你要清楚 具体的有哪些步骤 需要的哪些东西 自己一定要先了解清楚!因为这行的话 PZ比我们IDC服务器商都还要多。 {开服的话一定要了解清楚开传奇的一个具…

python(15)--函数设计

前言 函数是可重用的程序代码块。 函数的作用,不仅可以实现代码的复用,还可以保证修改函数的代码时,所有调用该函数的地方都能得到体现。目前我已知函数的作用是:对代码实现了封装、函数调用、传递参数、返回计算结果等。 正文 …

可控硅原理(单向可控硅和双向可控硅)

晶闸管(Thyristor)又叫可控硅,按照其工作特性又可分单向可控硅(SCR)、双向可控硅(TRIAC)。其中双向可控硅又分四象限双向可控硅和三象限双向可控硅。同时可控硅又有绝缘与非绝缘两大类,如ST的可控硅用BT名称后的“A”、与“B”来区分绝缘与非绝缘。 …

SpringCloud(18):Sentinel流控降级入门

Sentinel本地应用流控降级实现分为三步: 创建本地应用搭建本地Sentinel控制台本地应用接入本地Sentinel控制台1 本地应用创建 整体流程分析 创建springboot项目在项目的pom.xml文件中引入sentinel-core的依赖坐标创建TestController,定义使用限流规则…

java面向对象

3.面向对象 3.1 类和对象 public class Main{public static void main(String[] args) { /* 1.面向对象学习的三条主线1.1 类的结构:属性、方法、构造器、代码块、内部类1.2 面向对象的三大特征:封装性、继承性、多态性1.3 其他关键字:this…

当我把ChatGPT机器人拉到微信群里,群友都玩疯了!!!

大家好呀,我是飘渺!最近ChatGPT可谓是火出天际,人工智能领域的股票最近都被这家伙带的一路狂飙,如果到现在你都没听过或使用过的话那你可能是有点out了。今天的文章并不打算介绍ChatGPT,而是要带大家玩一件好玩的事。将…

泰克示波器采样率问题解答

1. 怎样选择示波器的采样率?采样率通常由带宽决定。高斯响应的泰克示波器通常而言采样率需要是带宽的 4 倍或更高。2. 选择具有最大额定采样率的示波器, 足以提供示波器的额定实时带宽吗?示波器的最大额定采样率与其实时带宽密切相关。 简单来讲,“实时”表示在单…

【C++】C++入门 类与对象(一)

类与对象(一)一、类的引入二、类的定义1、类的两种定义方式:2、成员变量命名规则的建议:三、类的访问限定符及封装1、访问限定符2、封装四、类的实例化1、类的实例化概念2、类对象的大小的计算五、this指针this指针的特性一、类的…