单片机状态机实现多个按键同时检测单击、多击、长按等操作
1.背景
在之前有个项目需要一个或多个按键检测:单击、双击、长按等操作
于是写了一份基于状态机的按键检测,分享一下思路
2.实现效果
单击翻转绿灯电平
双击翻转红灯电平
长按反转红绿灯电平
实现状态机检测按键单击,双击,长按等状态
3.代码实现
本代码是基于正点原子STM32F407ZGT6探索者开发板 HAL库写的
关于按键的代码可以直接移植,与芯片和HAL库没有多大联系,主要就是引脚定义是使用CubeMX生成的在main.h中,如下
#define BUTTON3_Pin GPIO_PIN_2
#define BUTTON3_GPIO_Port GPIOE
#define BUTTON2_Pin GPIO_PIN_3
#define BUTTON2_GPIO_Port GPIOE
#define BUTTON1_Pin GPIO_PIN_4
#define BUTTON1_GPIO_Port GPIOE
#define LED0_Pin GPIO_PIN_9
#define LED0_GPIO_Port GPIOF
#define LED1_Pin GPIO_PIN_10
#define LED1_GPIO_Port GPIOF
3.1 driver_button.c文件
#include "main.h"
#include "driver_boutton.h"#define NUM_BUTTONS 3
#define DOUBLE_CLICK_TIME 200 // 双击最大间隔时间(ms)
#define LONG_PRESS_TIME 300 // 长按最小持续时间(ms)void button_scan(void);
void button_init(void);
ButtonNum button_get_number(void);// GPIO端口和PIN引脚数组
const GPIO_TypeDef* button_GPIO_Ports[NUM_BUTTONS] =
{ BUTTON1_GPIO_Port,BUTTON2_GPIO_Port, BUTTON3_GPIO_Port,
}; const uint16_t button_GPIO_Pins[NUM_BUTTONS] =
{ BUTTON1_Pin,BUTTON2_Pin, BUTTON3_Pin,
};// 按键状态定义
typedef enum
{ BUTTON_RELEASED, //松开BUTTON_PRESSED, //按下BUTTON_SINGLE_CLICK, //单击BUTTON_DOUBLE_CLICK, //双击BUTTON_LONG_PRESS //长按
} Button_State; // 按键结构体定义
typedef struct
{ GPIO_TypeDef *GPIOx;uint16_t GPIO_PIN; // 按键连接的GPIO引脚 Button_State state; // 按键状态 uint32_t press_time; // 按下时间 uint32_t release_time; // 释放时间 uint8_t click_count; // 连续点击次数 uint32_t num; // 按键键值
} Button_TypeDef; //按键函数指针
const Button_Handler *button = &(const Button_Handler)
{.get_tick = HAL_GetTick, //获取系统时间滴答.init = button_init, //按键初始化.callback = button_scan, //按键扫描回调函数.get_number = button_get_number, //获取键值
};static Button_TypeDef buttons[NUM_BUTTONS]; static ButtonNum button_num = {0,0,0};/*** @简要 初始化按键配置* @说明 该函数对每个按键的GPIO端口和引脚进行初始化,并将按键状态设置为未按下* @参数 无* @返回值 无*/
void button_init(void)
{ for (int i = 0; i < NUM_BUTTONS; i++) { buttons[i].GPIOx = (GPIO_TypeDef*)button_GPIO_Ports[i]; buttons[i].GPIO_PIN = button_GPIO_Pins[i]; buttons[i].state = BUTTON_RELEASED; buttons[i].click_count = 0; buttons[i].num = 0x01 << i;}
} /*** @简要 定时器扫描按键* @说明 定时器消抖扫描并检测按键状态* @参数 无* @返回值 无*/
void button_scan(void) { uint32_t current_time = button->get_tick(); // 获取当前时间 for (int i = 0; i < NUM_BUTTONS; i++) //遍历所有按键{ Button_TypeDef *button = &buttons[i]; uint8_t current_state = HAL_GPIO_ReadPin(button->GPIOx, button->GPIO_PIN); // 读取按键状态 if (current_state == 0) // 按键按下{ if (button->state == BUTTON_RELEASED) // 如果之前是松开状态{ button->press_time = current_time; // 记录按下时间button->state = BUTTON_PRESSED; //更新按键状态为按下} } else // 按键释放 { if (button->state == BUTTON_PRESSED) // 如果之前是按下状态{ button->release_time = current_time; // 记录释放时间uint32_t press_duration = button->release_time - button->press_time; // 计算按下持续时间if (press_duration >= LONG_PRESS_TIME) // 如果按下时间超过长按阈值{ button->state = BUTTON_LONG_PRESS; // 更新状态为长按button_num.more |= buttons[i].num; // 标记长按事件} else //如果按下时间在长按阈值范围内{ button->click_count++; // 增加点击计数} // 复位按键状态 button->state = BUTTON_RELEASED; } }if (button->click_count) // 如果有点击计数{// 距离下一次按下时间大于 DOUBLE_CLICK_TIME 可认为是单击if (button->click_count == 1 && current_time - button->release_time > DOUBLE_CLICK_TIME) {button->click_count = 0; // 重置点击计数button_num.once |= buttons[i].num; // 标记单击事件}// 否则 在 DOUBLE_CLICK_TIME 时间段内按几下算几连击else if (button->click_count >= 2 && current_time - button->release_time > DOUBLE_CLICK_TIME){button->click_count = 0; // 重置点击计数button_num.twice |= buttons[i].num; // 标记双击事件} }}
} /*** @简要 获取按键状态* @说明 返回当前各类按键的键值* @参数 无* @返回值 按键的键值*/
ButtonNum button_get_number(void)
{ButtonNum temp = button_num;button_num.once = 0;button_num.twice = 0;button_num.more = 0;return temp;
}
3.2 driver_button.h文件
#ifndef __driver_button__
#define __driver_button__#include <stdint.h>#define BUTTON1_ONCE (0x01 << 0)
#define BUTTON2_ONCE (0x01 << 1)
#define BUTTON3_ONCE (0x01 << 2)#define BUTTON1_TWICE (0x01 << 0)
#define BUTTON2_TWICE (0x01 << 1)
#define BUTTON3_TWICE (0x01 << 2)#define BUTTON1_MORE (0x01 << 0)
#define BUTTON2_MORE (0x01 << 1)
#define BUTTON3_MORE (0x01 << 2)typedef struct{uint32_t once; //单击uint32_t twice; //双击uint32_t more; //长按
}ButtonNum;extern ButtonNum button_num;
// 按键处理函数结构体定义
typedef struct {uint32_t (*get_tick)(void); // 获取系统时间的函数指针void (*init)(void); // 初始化函数指针void (*callback)(void); // 回调函数指针ButtonNum (*get_number)(void);
} Button_Handler;extern const Button_Handler *button;#endif
3.3 在定时器中断中 检测按键
这里我使用的是TIM6,每10ms扫描一次
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{static uint32_t timerCount_key = 0;if(htim->Instance == TIM6){timerCount_key++;if(timerCount_key == 10){timerCount_key = 0;button->callback();}}
}
3.4 主函数中使用方法
这里使用按键控制led灯演示
/* USER CODE BEGIN 2 */HAL_TIM_Base_Start_IT(&htim6);button->init();/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */ButtonNum num = button->get_number(); if(num.twice == BUTTON1_TWICE) HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);if(num.twice == BUTTON2_TWICE) HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);if(num.twice == BUTTON3_TWICE) HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);if(num.more == BUTTON1_MORE) HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin),HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);if(num.more == BUTTON2_MORE) HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin),HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);if(num.more == BUTTON3_MORE) HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin),HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);if(num.once == BUTTON1_ONCE) HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);if(num.once == BUTTON2_ONCE) HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);if(num.once == BUTTON3_ONCE) HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);}/* USER CODE END 3 */
4.按键状态机思路
void button_scan(void)
主要思路是这样:
我每次定时器执行这个按键扫描的回调函数,都会轮询判断一下所有的按键状态。
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{static uint32_t timerCount_key = 0;if(htim->Instance == TIM6){timerCount_key++;if(timerCount_key == 10){timerCount_key = 0;button->callback();}}
}
例如在此之前我从来没按下过按键,当我的按键1按下的时刻,
uint8_t current_state = HAL_GPIO_ReadPin(button->GPIOx, button->GPIO_PIN); // 读取按键状态
current_state被返回了低电平(取决于你的电路设计,我这里按键按下接地)
然后就会进入到
if (current_state == 0) // 按键按下{ if (button->state == BUTTON_RELEASED) // 如果之前是松开状态{ button->press_time = current_time; // 记录按下时间button->state = BUTTON_PRESSED; // 更新按键状态为按下} }
在这里由于我们是第一次按下会被标记为状态为按下,然后将你的结构体中的按下时间记录为这一次扫描按键时的HAL_GetTick();
然后你按下按键是需要松手的吧
现在你松手了,接上面的if语句:
else // 按键释放 { if (button->state == BUTTON_PRESSED) // 如果之前是按下状态{ button->release_time = current_time; // 记录释放时间uint32_t press_duration = button->release_time - button->press_time; // 计算按下持续时间if (press_duration >= LONG_PRESS_TIME) // 如果按下时间超过长按阈值{ button->state = BUTTON_LONG_PRESS; // 更新状态为长按button_num.more |= buttons[i].num; // 标记长按事件} else // 如果按下时间在长按阈值范围内{ button->click_count++; // 增加点击计数} // 复位按键状态 button->state = BUTTON_RELEASED; } }
松手之后(按键释放,那么按键又被上拉到高电平了),这里先判断一下你之前的状态,必须要判断一下这个按键之前是不是被按下了,要不然就会一直进入这个if语句。
由于每次进入这个按键扫描函数都会记录一下HAL_GetTick();,
uint32_t press_duration = button->release_time - button->press_time; // 计算按下持续时间
所以记下了你上次按下按键与这次松开按键的时间间隔,那么这就可以得出你的按下时间,如果超过了长按阈值那么肯定就是长按状态了,就执行对应的长按操作。
如果你的时间间隔少于长按的时间阈值,那么就会给你增加一次点击计数。
之后你松开了按键那么可能要把按键的状态恢复到初始化的情况。
这时这个函数还没有结束,接下来会进入到这个if语句:
if (button->click_count) // 如果有点击计数{// 距离下一次按下时间大于 DOUBLE_CLICK_TIME 可认为是单击if (button->click_count == 1 && current_time - button->release_time > DOUBLE_CLICK_TIME) {button->click_count = 0; // 重置点击计数button_num.once |= buttons[i].num; // 标记单击事件}// 否则 在 DOUBLE_CLICK_TIME 时间段内按几下算几连击else if (button->click_count >= 2 && current_time - button->release_time > DOUBLE_CLICK_TIME){button->click_count = 0; // 重置点击计数button_num.twice |= buttons[i].num; // 标记双击事件} }
如果你按下按键的时间低于长按的时间阈值的话,那么就会进入这个函数,否则直接跳过这个if语句。
例如,这个时候从头到尾,你只按了一次低于长按时间阈值的操作,暂停时间分析:
再进入这个if语句:
if (button->click_count == 1 && current_time - button->release_time > DOUBLE_CLICK_TIME) {button->click_count = 0; // 重置点击计数button_num.once |= buttons[i].num; // 标记单击事件}
这里判断你的点击次数为1,但是当前你按下到松手后时间还没有超过双击的时间阈值,那么
current_time - button->release_time > DOUBLE_CLICK_TIME
就是false,if语句就进不去,但是如果时间再过去一点,
current_time - button->release_time > DOUBLE_CLICK_TIME
就是true,时间超过了双击的阈值,所以直接判断为单击。
再回到:例如,这个时候从头到尾,你只按了一次低于长按时间阈值的操作,时间暂停分析
接着上面的if判断:
if (button->click_count == 1 && current_time - button->release_time > DOUBLE_CLICK_TIME) {button->click_count = 0; // 重置点击计数button_num.once |= buttons[i].num; // 标记单击事件}
目前你还没有超过双击的时间阈值
紧接着你又按下了一次按键,并且这一次按下时间同样低于双击的阈值,那么就会继续增加的点击计数
直到本次按键的时间间隔大于双击的阈值,则判断结束,可以返回按键的点击次数了
5.结束
目前代码能够正常检测单击,双击,长按等操作,如果读者使用此代码发现有什么bug,或者值得优化的地方,欢迎评论区留言!
相关文章:
单片机状态机实现多个按键同时检测单击、多击、长按等操作
1.背景 在之前有个项目需要一个或多个按键检测:单击、双击、长按等操作 于是写了一份基于状态机的按键检测,分享一下思路 2.实现效果 单击翻转绿灯电平 双击翻转红灯电平 长按反转红绿灯电平 实现状态机检测按键单击,双击,长…...
graph rag都能做哪些事情
从提供的项目目录结构看,系统具备高复杂度和模块化的设计,可能用于大规模数据处理、知识图谱构建、自然语言处理等方面。以下是一些推理出的核心能力和应用场景: 1. 核心模块能力: API 层 (api) 主要用于对外接口的定义和服务调…...
Linux 用户和用户组管理
Linux 用户和用户组管理 Linux系统是一个多用户多任务的分时操作系统,任何一个要使用系统资源的用户,都必须首先向系统管理员申请一个账号,然后以这个账号的身份进入系统。 用户的账号一方面可以帮助系统管理员对使用系统的用户进行跟踪&…...
Python酷库之旅-第三方库Pandas(251)
目录 一、用法精讲 1186、pandas.tseries.offsets.BusinessMonthEnd.is_year_start方法 1186-1、语法 1186-2、参数 1186-3、功能 1186-4、返回值 1186-5、说明 1186-6、用法 1186-6-1、数据准备 1186-6-2、代码示例 1186-6-3、结果输出 1187、pandas.tseries.offs…...
利用Ubuntu批量下载modis图像(New)
由于最近modis原来批量下载的代码不再直接给出,因此,再次梳理如何利用Ubuntu下载modis数据。 之前的下载代码为十分长,现在只给出一部分,需要自己再补充另一部分。之前的为: 感谢郭师兄的指导(https://blo…...
Redis分布式锁
一、全局ID生成器 1.1 概念 全局ID生成器,是一种在分布式系统下用来生成全局唯一ID的工具。具有以下特点: (1)唯一性;(2)高可用;(3&…...
【Maven】依赖管理
4. Maven的依赖管理 在 Java 开发中,项目的依赖管理是一项重要任务。通过合理管理项目的依赖关系,我们可以有效的管理第三方库,模块的引用及版本控制。而 Maven 作为一个强大的构建工具和依赖管理工具,为我们提供了便捷的方式来管…...
leetcode——移除数组
26.删除有序数组中的重复项 给你一个 非严格递增排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。 考虑 nums 的唯一元素…...
vue项目部署到github pages后页面显示不出来??
问题: 当我们在命令行执行 npm run build 后,项目的目录下会生成一个 dist 文件夹,它里面又包含一个 static 文件夹和一个 index.html 文件,这是 webpack 最终打包好的文件 项目上传到仓库后发现页面为空,找不到文件路…...
为什么爱用低秩矩阵
目录 为什么爱用低秩矩阵 一、定义与性质 二、区别与例子 为什么爱用低秩矩阵 我们更多地提及低秩分解而非满秩分解,主要是因为低秩分解在数据压缩、噪声去除、模型简化和特征提取等方面具有显著的优势。而满秩分解虽然能够保持数据的完整性,但在实际应用中的场景较为有限…...
如何在MySQL中计算两个日期的间隔天数
目录 1. DATEDIFF函数2. TIMESTAMPDIFF函数3. PERIOD_DIFF函数4. 函数对比 在MySQL 5.7中,计算两个日期之间的间隔天数是一项常见的任务。 1. DATEDIFF函数 DATEDIFF函数可以直接计算两个日期之间的天数差异。 -- 计算2024年1月1日和2024年1月10日之间的天数差异 …...
SQL面试题——抖音SQL面试题 共同问题—共同使用ip用户检测问题
共同使用ip用户检测问题 现有用户登录日志表,记录了每个用户登录的IP地址,请查询共同使用过3个及以上IP的用户对; +---+--------------+-------------------+ | id| ip| etime| +---+--------------+-------------------+ | 2|223.104.41.101|20…...
python学习笔记2
下载安装PyCharm 打开pycharm官网: https://www.jetbrains.com.cn/en-us/pycharm/download/?sectionwindows 找到社区版(免费) 下载之后打开,不停下一步就行 打开pycharm软件后,新建py文件 基本输出:…...
IS-IS的原理
IS-IS的基本概念: 概述: IS-IS,中间系统到中间系统,是ISO国际标准化组织为它的无连接网络协议设计的一种动态路由协议 IS-IS支持CLNP网络和IP网络,采用数据链路层封装,区别于ospf只支持IP网络࿰…...
现代应用程序中基于 Cell 架构的安全防护之道
在飞速发展的软件开发领域,基于 Cell 的架构日益流行起来。其概念源自船舶舱壁的设计准则,即单独的水密舱室能允许故障孤立存在。通过将这个概念应用于软件,我们创建了一个架构,将应用程序划分为离散的、可管理的组件,…...
Rust : 生成日历管理markdown文件的小工具
需求: 拟生成以下markdown管理小工具,这也是我日常工作日程表。 可以输入任意时间段,运行后就可以生成以上的markdown文件。 一、toml [package] name "rust-workfile" version "0.1.0" edition "2021"[d…...
Burp Suite 全面解析:开启你的 Web 安全测试之旅
声明! 学习视频来自B站up主 **泷羽sec** 有兴趣的师傅可以关注一下,如涉及侵权马上删除文章,笔记只是方便各位师傅的学习和探讨,文章所提到的网站以及内容,只做学习交流,其他均与本人以及泷羽sec团队无关&a…...
RocketMQ: 消息积压问题的解决
概述 1 ) 什么是消息积压 在分布式消息系统中,消息积压是指消息生产速度超过消息消费速度,导致未处理的消息在消息队列中累积的现象这种现象可能会导致系统性能下降、资源占用增加,甚至影响系统的正常运行 2 )消息积…...
Qt的定时器应用案例 || Qt的图片添加显示
目录 1.ui界面 2.头文件 3.cpp源文件 4.main文件 5.关于ui_mytimerevent.h的代码编译错误 6.图片的添加展示方式 7.结果展示 8.参考文章 1.ui界面 2.头文件 #ifndef MYTIMEREVENT_H #define MYTIMEREVENT_H#include <QMainWindow> #include <QTime> //#in…...
24.12.02 Element
import { createApp } from vue // 引入elementPlus js库 css库 import ElementPlus from element-plus import element-plus/dist/index.css //中文语言包 import zhCn from element-plus/es/locale/lang/zh-cn //图标库 import * as ElementPlusIconsVue from element-plus/i…...
web安全攻防入门教程
Web安全攻防入门教程 Web安全攻防是指在Web应用程序的开发、部署和运行过程中,保护Web应用免受攻击和恶意行为的技术与策略。这个领域不仅涉及防御措施的实现,还包括通过渗透测试、漏洞挖掘和模拟攻击来识别潜在的安全问题。 本教程将带你入门Web安全攻…...
Android——android相对布局(RelativeLayout)及各属性
参考:Android——android相对布局(RelativeLayout)及属性 - 艺言弈行 - 博客园 (cnblogs.com)...
初窥 HTTP 缓存
引言 对于前端来说, 你肯定听说过 HTTP 缓存。 当然不管你知不知道它, 对于提高网站性能和用户体验, 它都扮演着重要的角色! 它通过在客户端和服务器之间存储和重用先前获取的资源副本, 来减少网络流量和降低资源加载时间, 从而提升用户体验! 以下是 HTTP 缓存的重要性: 减少…...
【LeetCode】3. 哈希表: 字母异位词分组;有效的数独
题目 字母异位词分组 给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。 字母异位词 是由重新排列源单词的所有字母得到的一个新单词。 示例 1: 输入: strs [“eat”, “tea”, “tan”, “ate”, “nat”, “bat”] 输出: [[“…...
设计模式之抽象工厂 C# 范例
在设计模式中,抽象工厂模式(Abstract Factory Pattern) 是一种创建型模式,它提供一个接口,用于创建一组相关或相互依赖的对象,而无需指定具体类。这种模式的关键在于通过抽象工厂来封装产品的创建ÿ…...
基于Python的猎聘网招聘数据采集与可视化分析
1.1项目简介 在现代社会,招聘市场的竞争日趋激烈,企业和求职者都希望能够更有效地找到合适的机会与人才。猎聘网作为国内领先的人力资源服务平台,汇聚了大量的招聘信息和求职者数据,为研究招聘市场趋势提供了丰富的素材。基于Pyt…...
oracle数据库的启动与关闭
一.oracle数据库的启动过程 启动实例(Start the Instance) 启动实例:一个Oracle数据库实例由内存结构和后台进程组成,启动实例时会加载这些内存结构和启动进程。实例是数据库的一个运行时环境,它包含了数据库的控制文…...
openGauss开源数据库实战十六
文章目录 任务十六 openGauss逻辑结构:触发器管理任务目标实施步骤一、测试openGauss的触发器1.创建测试表2.创建触发器对应的函数3.创建触发器4.测试触发器 二、触发器的类型1.行级触发器2.语句级触发器3.AFTER触发器和 BEFORE触发器 任务十六 openGauss逻辑结构:触发器管理 …...
智能教育的关键之一是构建智能学习系统
教育部办公厅12月27日发布《关于加强中小学人工智能教育的通知》,提出人工智能教育六大主要任务和举措,包括构建系统化课程体系、实施常态化教学与评价、开发普适化教学资源、建设泛在化教学环境、推动规模化教师供给和组织多样化交流活动。《通知》提出…...
【Linux 篇】Docker 容器星河与镜像灯塔:Linux 系统下解锁应用部署奇幻征程
文章目录 【Linux 篇】Docker 容器星河与镜像灯塔:Linux 系统下解锁应用部署奇幻征程前言一 、docker上部署mysql1. 拉取mysql镜像2. 创建容器3. 远程登录mysql 二 、docker上部署nginx1. 拉取nginx镜像2. 在dockerTar目录下 上传nginx.tar rz命令3. 创建nginx容器4…...
十四(AJAX)、AJAX、axios、常用请求方法(GET POST...)、HTTP协议、接口文档、form-serialize
1. AJAX介绍及axios基本使用 <!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8" /><meta http-equiv"X-UA-Compatible" content"IEedge" /><meta name"viewport" content&q…...
雪花算法生成ID
下面将简单介绍雪花算法的简单应用和在web应用中的使用。 雪花算法的组成:雪花算法是由64位组成:符号位(1)、时间戳(41)、机器码(5[数据中心]5[机器ID])、计数器(12) 对于雪花算法的源码可以在这里看:bwmarrin/snowflake: A simple to use …...
Java - JSR223规范解读_在JVM上实现多语言支持
文章目录 1. 概述2. 核心目标3. 支持的脚本语言4. 主要接口5. 脚本引擎的使用执行JavaScript脚本执行groovy脚本1. Groovy简介2. Groovy脚本示例3. 如何在Java中集成 Groovy4. 集成注意事项 6. 与Java集成7. 常见应用场景8. 优缺点9. 总结 1. 概述 JSR223(Java Spe…...
vue3 基本使用
Vue 3 提供了多种方式来构建用户界面,包括选项式 API 和 Composition API。下面我将详细介绍 Vue 3 的基本使用和语法,主要集中在选项式 API 上,因为这对于初学者来说更容易上手。 1. 创建 Vue 项目 如果你还没有一个 Vue 项目,…...
Redis自学之路—高级特性(实现消息队列)(七)
目录 简介 Redis的Key和Value的数据结构组织 全局哈希表 渐进式rehash 发布和订阅 操作命令 publish 发布消息 subscribe 订阅消息 psubscribe订阅频道 unsubscribe 取消订阅一个或多个频道 punsubscribe 取消订阅一个或多个模式 查询订阅情况-查看活跃的频道 查询…...
ROS基本框架2——在ROS开发中创建并使用自定义消息(C++版本)
ROS基本框架2——在ROS开发中创建并使用自定义消息(C++版本) code review! 参考笔记 1.ROS基本框架1——编写简单的发布者和订阅者(C++和Python版本) 2.ROS基本框架2——在ROS开发中创建并使用自定义消息(C++版本) 文章目录 ROS基本框架2——在ROS开发中创建并使用自定义…...
计算机的错误计算(一百七十二)
摘要 探讨 MATLAB 对于算式 的计算误差。 例1. 在 MATLAB 中计算 的值。 直接贴图吧: 这样,MATLAB 的输出中只有3位正确数字,有效数字的错误率为 (16-3)/16 81.25% . 因为16位的正确输出为 0.2971242332737277e-18(ISReals…...
贵州大学oj平台高级语言第九次作业(四)
题目:链表的基础操作 题目描述 链表是软件中一种最基本的数据结构,它是用链式存储结构实现数据存储的线性表。它较顺序表(如数组)而言在插入和删除数据时不必移动其后的大批量元素。现在给你一些整数,然后会频繁地插入和删除其中的某些元素&a…...
手机卡限速丨中国移动5G变3G,网速500kb
以下猜测错误,又有新的猜测:河南移动的卡出省限速。可能是因为流量结算。 “2024年7月1日起,中国移动集团内部将开启跨省流量结算” 在深圳四五年了,之前没有过,就从上个月开始。11月底解除限速,12月刚开…...
种花问题算法
假设有一个很长的花坛,一部分地块种植了花,另一部分却没有。可是,花不能种植在相邻的地块上,它们会争夺水源,两者都会死去。 给你一个整数数组 flowerbed 表示花坛,由若干 0 和 1 组成,其中 0 …...
Node.js-Mongodb数据库
MongoDB MongoDB是什么? MongoDB是一个基于分布式文件存储的数据库 数据库是什么? 数据库(DataBase)是按照数据结构来组织、存储和管理数据的应用程序(软件) 数据库作用? 对数据进行增、删…...
Nginx
目录 基本介绍 Nginx核心功能 Nginx下载&安装&启动 配置防火墙 Nginx常用命令 Nginx配置文件 全局块 events块 http块 http全局块 server 块 检查配置信息 快速入门 安装JDK 安装Tomcat 反向代理分析 Location语法规则 反向代理配置-Location实例 …...
CTF-PWN: 全保护下格式化字符串利用 [第一届“吾杯”网络安全技能大赛 如果能重来] 赛后学习(没思路了)
通过网盘分享的文件:如果能重来.zip 链接: https://pan.baidu.com/s/1XKIJx32nWVcSpKiWFQGpYA?pwd1111 提取码: 1111 --来自百度网盘超级会员v2的分享漏洞分析 格式化字符串漏洞,在printf(format); __int64 sub_13D7() {char format[56]; // [rsp10h] [rbp-40h]…...
HTML5系列(7)-- Web Storage 实战指南
前端技术探索系列:HTML5 Web Storage 实战指南 🗄️ 致读者:本地存储的新纪元 👋 前端开发者们, 今天我们将深入探讨 HTML5 中的 Web Storage 技术,这是一个强大的本地存储解决方案,让我们能…...
RocketMQ: 保证消息的可靠性投递
概述 在分布式系统中,消息队列作为异步通信的重要组件,其可靠性和稳定性至关重要RocketMQ 是阿里巴巴开源的一款高性能、高可靠性的分布式消息中间件,广泛应用于各种场景,如交易订单处理、日志收集、流计算等 RocketMQ 的可靠性…...
消息传递神经网络(Message Passing Neural Networks, MPNN)
消息传递神经网络(Message Passing Neural Networks, MPNN) 一、引言二、消息传递框架概述1.消息传递阶段(1)消息生成与传播-message(2)消息聚合-aggregate(3)消息更新-update&#…...
Python干货总结篇:列表、字典、集合、元组的区别与用途
前言: 更详细知识点,搞懂列表、字典、集合、元组到底是什么,可关注主页文章:Python知识点精汇! 目录 一、特点与用途 1.列表:a[ ] 2.集合:a{ } 3.字典:a{key:value} 4.元组&am…...
vue.js学习(day 18)
实例:面经基础版...
【Gitlab】CICD使用minio作为分布式缓存
1、安装minio 下载适合自己系统版本的安装文件https://dl.min.io/server/minio/release/windows-amd64/ yum install xxx.rpm 2、配置/etc/profile export MINIO_ACCESS_KEYroot [ui登录账号] export MINIO_SECRET_KEYminioDev001 [ui登录密码] export MINIO_OPTS"…...
医院管理系统
私信我获取源码和万字论文,制作不易,感谢点赞支持。 医院管理系统 摘要 随着信息互联网信息的飞速发展,医院也在创建着属于自己的管理系统。本文介绍了医院管理系统的开发全过程。通过分析企业对于医院管理系统的需求,创建了一个计…...