当前位置: 首页 > news >正文

单片机按键扫描程序,可以单击、双击、长按,使用状态机,无延时,不阻塞。

  • 根据按下时的时长、间隔来判断是否是连按或者长按。
  • 当连按间隔很短时,计录连按次数
  • 超过连接间隔时,回报按下次数
  • 根据按键次数自行判断是单击、双击、三击、四击。。。最多记录15击。

结构体版:

#define KEY_CHANNEL_COUNT (6 + 8 + 8)
struct keyInfo
{uint8_t act : 4;       // 按了多少次,最多连按15次uint8_t down : 1;      // 按下了uint8_t up : 1;        // 松开了uint8_t longPress : 1; // 长按了uint8_t io : 1;        // 按键IO状态uint8_t intervalTime;  // 连按间隔时间uint8_t holdTime;      // 长按时间uint8_t duration;      // 按键次数保持时间,超过后,act清零
};
struct keyInfo keyValues[KEY_CHANNEL_COUNT] = {0};void button_trace_handle(void *p)
{static uint32_t lastTime = 0;const uint8_t KEYSCAN_INTERVAL_TIME = 10; // 按键扫描间隔时间const uint8_t LONG_PRESS_TIME = 100;  // 长按多久生效, 实际时间为,下面同理 LONG_PRESS_TIME * KEYSCAN_INTERVAL_TIMEconst uint8_t INTERVAL_TIME_SET = 20; // 两次按键检测超时const uint8_t ANTI_SHAKE_TIME = 2;    // 按键防抖检测超时/*** @brief 需要实现millis()函数,系统毫秒计时器。* */if (millis()> lastTime + KEYSCAN_INTERVAL_TIME){lastTime = millis();        }else{return;}/**给按键IO赋值, 有多个按键就传多少个, 自己实现ic_read函数 */for (uint8_t i = 0; i < KEY_CHANNEL_COUNT; i++){keyValues[i].io = io_read(i);}for (uint8_t i = 0; i < KEY_CHANNEL_COUNT; i++){if (keyValues[i].io)//按下了{if (keyValues[i].holdTime < LONG_PRESS_TIME){keyValues[i].holdTime++;if (keyValues[i].holdTime >= ANTI_SHAKE_TIME)//防抖{keyValues[i].down = 1;keyValues[i].intervalTime = INTERVAL_TIME_SET;}}else //长按了,会一直标记,直到松开{keyValues[i].longPress = 1;}}else{//松开了keyValues[i].holdTime = 0;keyValues[i].longPress = 0;if (keyValues[i].down)//按下过了{if (!keyValues[i].longPress)//不是长按keyValues[i].act++;//按下次数+1keyValues[i].down = 0;}if (keyValues[i].intervalTime)//连按超时{keyValues[i].intervalTime--;if (keyValues[i].intervalTime == 1){LOG_D("key[%d] act:%d", i, keyValues[i].act);//打印哪个按键按了多少次keyValues[i].duration = 10;}}}if (keyValues[i].duration >= 1){keyValues[i].duration--;if (keyValues[i].duration == 1)//按键次数保持时间到{keyValues[i].act = 0;}}}
}

无结构体版,更方便移到51单片机上

#define KEY_DOWN_MASK  0X80/**按下标记*/
#define KEY_LONG_PRESS_MASK  0X40/**长按标记 */
#define KEY_TIMEOUT_MASK  0X10/**超时标志,此时返回按键值*/
#define KEY_TIEMES_MASK  0X0F/**按了多少次 */
#define KEY_VALUE(x) (0x0001<<(x))#define KEY_COUNTS 5void keyScanPro()
{const uint8_t SHORT_PRESS_TIME = 25;const uint16_t LONG_PRESS_TIME = 150;const uint8_t IS_KEY_DOWN = 0X80;/**按下了 */const uint8_t IS_LONG_PRESS = 0X40;/**长按了 */const uint8_t IS_TIME_OUT = 0X10;/**退好久没按 */static uint8_t keyActionHold = 0;static uint8_t pressTimesRecord[KEY_COUNTS] = { 0 };static uint8_t pressTime[KEY_COUNTS] = { 0 };static uint16_t longPressTime[KEY_COUNTS] = { 0 };const uint16_t channel_keyScan_map[KEY_COUNTS] = { DEF_SET_BIT0,DEF_SET_BIT1,DEF_SET_BIT2,DEF_SET_BIT3,DEF_SET_BIT4 };/**A,B,C,D,E,F,G,H,I,J,K,L对就的键值*/uint8_t i;keyValue = KP; keyValue <<= 1;keyValue |= !K1; keyValue <<= 1;keyValue |= !K2; keyValue <<= 1;keyValue |= !K3; keyValue <<= 1;keyValue |= !K4;if (keyValue != keyValuePre){ResetSystemShutdownCountdown();keyValuePre = keyValue;}// LOG("keyValue:%d\n",(int)keyValue);if (keyAction){if (keyActionHold++ > 100){keyActionHold = 0;keyAction = 0;}}for (i = 0; i < KEY_COUNTS; i++){if (keyValue & channel_keyScan_map[i]){//按下了if (longPressTime[i] < LONG_PRESS_TIME){longPressTime[i]++;pressTime[i] = SHORT_PRESS_TIME;pressTimesRecord[i] |= IS_KEY_DOWN;}else{pressTimesRecord[i] |= IS_LONG_PRESS;pressTimesRecord[i] |= IS_TIME_OUT;pressTimesRecord[i] &= ~IS_KEY_DOWN; //取消标记高位keyLongPress |= 1 << i;keyAction |= ((i + 1) << 8);if (keyValue & PWR_KEY_VALUE){LOG("System shutting down ...");SYS_PWR_SHUTDOWN();while (1);}LOG("long press:%d\n", (int)keyLongPress);// if (pwrKeyLongPressCb) pwrKeyLongPressCb();// else pwrKeyLongPressCbDefault();}}else{//松开了longPressTime[i] = 0;keyLongPress &= ~(1 << i);if (pressTimesRecord[i] & IS_KEY_DOWN){//高位标记过,即按下过keyActionHold = 0;pressTimesRecord[i] &= ~IS_KEY_DOWN; //取消标记高位if ((pressTimesRecord[i] & KEY_TIEMES_MASK) < 15){uint8_t ptc = 0;pressTimesRecord[i]++;ptc = pressTimesRecord[i] & KEY_TIEMES_MASK;ptc = ptc > 7 ? 7 : ptc;// speaker_out(music_note_freq[ptc], 100);}}if (pressTime[i] > 0){if (pressTime[i] == 1){pressTimesRecord[i] |= IS_TIME_OUT;//BIT4 为检测时间到}pressTime[i]--;}if (pressTimesRecord[i] & IS_TIME_OUT){if (pressTimesRecord[i] & IS_LONG_PRESS){// rt_kprintf("Long press:%d \n", i);pressTimesRecord[i] &= ~IS_LONG_PRESS;}else if (pressTimesRecord[i] & KEY_TIEMES_MASK){uint8_t ptc = pressTimesRecord[i] & KEY_TIEMES_MASK;keyAction |= (i + 1) << 4 | ptc;LOG("keyAction:%x\n", (int)keyAction);// struct pwrKeyActList* p;// p = &pwrKeyActListHead;// do {//     // LOG_D("P:0x%08X", p);//     if (p->cb)//     {//         p->cb(ptc);//     }//     p = p->next;// } while (p);}// LOG("Press:%d - %d\n", (int)i, (int)(pressTimesRecord[i] & KEY_TIEMES_MASK));;pressTimesRecord[i] = 0;}}}
}

相关文章:

单片机按键扫描程序,可以单击、双击、长按,使用状态机,无延时,不阻塞。

根据按下时的时长、间隔来判断是否是连按或者长按。当连按间隔很短时&#xff0c;计录连按次数超过连接间隔时&#xff0c;回报按下次数根据按键次数自行判断是单击、双击、三击、四击。。。最多记录15击。 结构体版&#xff1a; #define KEY_CHANNEL_COUNT (6 8 8) struct…...

Django中自定义模板字符串

首先在目录中创建名为 templatetags 的文件夹 然后在文件中创建 python 文件 然后再相应的 HTML 模板文件中导入 {% load python的文件名 %} 然后在 HTML 文件中通过进行使用 {% 函数名 %} python文件中的代码 首先导入 from django import templateregister template…...

暴雨总裁孙辉:混合式人工智能是大势所趋

当前&#xff0c;生成式人工智能技术的突破和发展&#xff0c;大大加速了各行各业的数字化、智能化进程。在充满不确定性的全球发展环境下&#xff0c;人工智能已成为驱动未来增长最确定、最核心的力量。 对此&#xff0c;暴雨总裁孙辉认为&#xff0c;2025年&#xff0c;人工…...

【小制作】米家模拟手指点击

代码功能解释 这段代码是一个基于Arduino平台的控制程序&#xff0c;主要功能包括&#xff1a; 初始化&#xff1a;设置引脚模式、初始化编码器、舵机和EEPROM。按键检测&#xff1a;处理按钮的单击、双击和长按事件&#xff0c;并根据事件执行相应操作。编码器更新&#xff…...

【深度学习入门_基础篇】线性代数本质

开坑本部分主要为基础知识复习&#xff0c;新开坑中&#xff0c;学习记录自用。 学习目标&#xff1a; 熟悉向量、线性组合、线性变换、基变换、矩阵运算、逆函数、秩、列空间、零空间、范式、特征指、特征向量等含义与应用。 强烈推荐此视频&#xff1a; 【官方双语/合集】…...

047_小驰私房菜_Qcom 8系列,Jpeg GPU 旋转

【问题背景】 横屏模式下&#xff0c;发现有些三方app拍照旋转了90度。 【修改策略】 adb shell setprop endor.debug.camera.overrideGPURotationUsecase 1 或者在/vendor/etc/camera/camxoverridesettings.txt 里面添加如下内容 overrideGPURotationUsecase1 【解释】 Ga…...

Elasticsearch 操作文档对数据的增删改查操作 索引库文档 操作数据 CRUD

介绍 在 Elasticsearch 中&#xff0c;文档的增、删、改、查操作是核心的基本功能。Elasticsearch 使用 RESTful API 提供这些操作&#xff0c;通常通过 HTTP 请求与 Elasticsearch 集群进行交互。 索引库 {"mappings": {"properties": {"title&qu…...

最新MySQL面试题(2025超详细版)

2025最新超详细MySQL面试题 文章目录 2025最新超详细MySQL面试题[toc]一、 SQL 和基本操作1. SQL的执行顺序2. 如何优化MySQL查询3. 常用的聚合函数4. 数据库事务5. 事务的四大特性(ACID)6. 视图7. MySQL中使用LIMIT子句进行分页8. MySQL中使用变量和用户定义的函数9. MySQL中的…...

使用MPTCP+BBR进行数据传输,让网络又快又稳

1.前言 在前文《链路聚合技术——多路径传输Multipath TCP(MPTCP)快速实践》中我们使用mptcpize run命令实现了两个节点间通信使用MPTCP协议进行传输&#xff0c;并实现了传输速率的聚合。 实际应用中更推荐原生支持mptcp的应用&#xff0c;在MPTCP官网中可以看到如TCPDump、…...

滴滴数据分析80道面试题及参考答案

如何衡量分类好坏? 衡量分类好坏有多种方法,常用的有准确率、精确率、召回率、F1 值、ROC 曲线与 AUC 值等。 准确率:是指分类正确的样本数占总样本数的比例,计算公式为:准确率 = (分类正确的样本数)/(总样本数)。准确率越高,说明分类器整体的分类效果越好,但在正负…...

基于物联网疫苗冷链物流监测系统设计

1. 项目开发背景 随着全球对疫苗运输要求的提高&#xff0c;特别是针对温度敏感型药品&#xff08;如疫苗&#xff09;的冷链管理&#xff0c;如何保证疫苗在运输过程中的温度、湿度、震动等环境因素的稳定性已成为亟需解决的问题。疫苗运输过程中&#xff0c;任何温度或湿度的…...

计算机网络基础(7)中科大郑铨老师笔记

应用层 目标&#xff1a;  网络应用的 原理&#xff1a;网络应用协议的概念和实现方面 传输层的服务模型 客户-服务器模式 对等模式(peerto-peer) 内容分发网络  网络应用的 实例&#xff1a;互联网流行的应用层协 议  HTTP  FTP  SMTP / POP3 / IMAP  DNS…...

GOGOGO 抽象

抽象其实也算面向对象特征之一 抽象 含义&#xff1a;当多个子类中的共性向上提取&#xff0c;父类中不知道如何写具体实现&#xff0c;因为提取的共性并不一定能解决子类中实现的功能【同结构不一定同实现代码体】&#xff0c;就需要抽象概念 作用 父类只抽取结构&#xff…...

STM32-笔记26-WWDG窗口看门狗

一、简介 窗口看门狗用于监测单片机程序运行时效是否精准&#xff0c;主要检测软件异常&#xff0c;一般用于需要精准检测程序运行时间的场合。 窗口看门狗的本质是一个能产生系统复位信号和提前唤醒中断的6位计数器&#xff08;有的地方说7位。其实都无所谓&#xff0…...

10.装饰器

装饰器的基本用法创建简单的装饰器带参数的装饰器装饰器链类装饰器内置装饰器 定义:装饰器是一个函数&#xff0c;它接受另一个函数作为参数&#xff0c;并返回一个新的函数。装饰器通常用于在函数执行前后添加额外的功能&#xff0c;如日志记录、权限检查、性能测试等。 1.基…...

uniapp H5页面实现懒加载

在 uniapp 中&#xff0c;要在小的 view 内实现列表懒加载&#xff0c;可以通过以下步骤来实现&#xff1a; 使用 scroll-view 组件来创建一个可滚动的区域。在 scroll-view内 部放置一个list组件&#xff0c;用于显示数据列表。监听 scroll-view 的滚动事件&#xff0c;当滚动…...

STM32使用UART发送字符串与printf输出重定向

首先我们先看STM32F103C8T6的电路图 由图可知&#xff0c;其PA9和PA10引脚分别为UART的TX和RX(注意&#xff1a;这个电路图是错误的&#xff0c;应该是PA9是X而PA9是RX&#xff0c;我们看下图的官方文件可以看出)&#xff0c;那么接下来我们应该找到该引脚的定义是什么&#xf…...

NLP初识

目录 0简介一、自然语言概述1. 什么是NLP?2. NLP常用工具0简介 NLP系列开始更新了!!!这个系列主要会介绍一些NLP的基础概念,比如RNN、LSTM、GRU等内容,重头戏放在大语言模型的基础讲解上,其中大语言模型的分享主要由两个方面:1.基础结构(Seq2Seq,Attention,Transfor…...

解決當前IP地址僅適用於本地網路

想要解決“當前IP地址僅適用於本地網路”其實並不困難。本篇文章將介紹其發生的原因以及如何解決。 “僅限本地網路”是什麼意思&#xff1f; 當IP地址為“僅限本地網路”時&#xff0c;意味著設備正在使用私人網路內部IP地址&#xff0c;但無法連接到互聯網。如果將本地IP視…...

Eplan 项目结构(高层代号、安装地点、位置代号)

Eplan中的项目结构分为3个层次&#xff1a; &#xff08;1&#xff09;功能面结构。指明这个系统的功能&#xff0c;有什么用途。在EPlan中&#xff0c;指的就是"高层代号&#xff08;&#xff09;"。 一般指的是线体。 &#xff08;2&#xff09;位置面结构。指明该…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度​

一、引言&#xff1a;多云环境的技术复杂性本质​​ 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时&#xff0c;​​基础设施的技术债呈现指数级积累​​。网络连接、身份认证、成本管理这三大核心挑战相互嵌套&#xff1a;跨云网络构建数据…...

Java 语言特性(面试系列2)

一、SQL 基础 1. 复杂查询 &#xff08;1&#xff09;连接查询&#xff08;JOIN&#xff09; 内连接&#xff08;INNER JOIN&#xff09;&#xff1a;返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...

微信小程序之bind和catch

这两个呢&#xff0c;都是绑定事件用的&#xff0c;具体使用有些小区别。 官方文档&#xff1a; 事件冒泡处理不同 bind&#xff1a;绑定的事件会向上冒泡&#xff0c;即触发当前组件的事件后&#xff0c;还会继续触发父组件的相同事件。例如&#xff0c;有一个子视图绑定了b…...

多场景 OkHttpClient 管理器 - Android 网络通信解决方案

下面是一个完整的 Android 实现&#xff0c;展示如何创建和管理多个 OkHttpClient 实例&#xff0c;分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂

蛋白质结合剂&#xff08;如抗体、抑制肽&#xff09;在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上&#xff0c;高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术&#xff0c;但这类方法普遍面临资源消耗巨大、研发周期冗长…...

STM32标准库-DMA直接存储器存取

文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA&#xff08;Direct Memory Access&#xff09;直接存储器存取 DMA可以提供外设…...

C++中string流知识详解和示例

一、概览与类体系 C 提供三种基于内存字符串的流&#xff0c;定义在 <sstream> 中&#xff1a; std::istringstream&#xff1a;输入流&#xff0c;从已有字符串中读取并解析。std::ostringstream&#xff1a;输出流&#xff0c;向内部缓冲区写入内容&#xff0c;最终取…...

.Net Framework 4/C# 关键字(非常用,持续更新...)

一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...

算法笔记2

1.字符串拼接最好用StringBuilder&#xff0c;不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...

LangFlow技术架构分析

&#x1f527; LangFlow 的可视化技术栈 前端节点编辑器 底层框架&#xff1a;基于 &#xff08;一个现代化的 React 节点绘图库&#xff09; 功能&#xff1a; 拖拽式构建 LangGraph 状态机 实时连线定义节点依赖关系 可视化调试循环和分支逻辑 与 LangGraph 的深…...