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

【开源移植】MultiButton_小型按键驱动模块移植

MultiButton

简介

MultiButton 是一个小巧简单易用的事件驱动型按键驱动模块,可无限量扩展按键,按键事件的回调异步处理方式可以简化你的程序结构,去除冗余的按键处理硬编码,让你的按键业务逻辑更清晰。

使用方法

1.先申请一个按键结构

struct Button button1;

2.初始化按键对象,绑定按键的GPIO电平读取接口read_button_pin() ,后一个参数设置有效触发电平

button_init(&button1, read_button_pin, 0, 0);

3.注册按键事件

button_attach(&button1, SINGLE_CLICK, Callback_SINGLE_CLICK_Handler);
button_attach(&button1, DOUBLE_CLICK, Callback_DOUBLE_Click_Handler);
...

4.启动按键

button_start(&button1);

5.设置一个5ms间隔的定时器循环调用后台处理函数

while(1) {...if(timer_ticks == 5) {timer_ticks = 0;button_ticks();}
}

特性

MultiButton 使用C语言实现,基于面向对象方式设计思路,每个按键对象单独用一份数据结构管理:

struct Button {uint16_t ticks;uint8_t  repeat: 4;uint8_t  event : 4;uint8_t  state : 3;uint8_t  debounce_cnt : 3;uint8_t  active_level : 1;uint8_t  button_level : 1;uint8_t  button_id;uint8_t  (*hal_button_Level)(uint8_t  button_id_);BtnCallback  cb[number_of_event];struct Button* next;
};

这样每个按键使用单向链表相连,依次进入 button_handler(struct Button* handle) 状态机处理,所以每个按键的状态彼此独立。

按键事件

事件说明
PRESS_DOWN按键按下,每次按下都触发
PRESS_UP按键弹起,每次松开都触发
PRESS_REPEAT重复按下触发,变量repeat计数连击次数
SINGLE_CLICK单击按键事件
DOUBLE_CLICK双击按键事件
LONG_PRESS_START达到长按时间阈值时触发一次
LONG_PRESS_HOLD长按期间一直触发

Examples

#include "button.h"unit8_t btn1_id = 0;struct Button btn1;uint8_t read_button_GPIO(uint8_t button_id)
{// you can share the GPIO read function with multiple Buttonsswitch(button_id){case btn1_id:return HAL_GPIO_ReadPin(B1_GPIO_Port, B1_Pin);break;default:return 0;break;}
}
void BTN1_PRESS_DOWN_Handler(void* btn)
{//do something...
}void BTN1_PRESS_UP_Handler(void* btn)
{//do something...
}...int main()
{button_init(&btn1, read_button_GPIO, 0, btn1_id);button_attach(&btn1, PRESS_DOWN,       BTN1_PRESS_DOWN_Handler);button_attach(&btn1, PRESS_UP,         BTN1_PRESS_UP_Handler);button_attach(&btn1, PRESS_REPEAT,     BTN1_PRESS_REPEAT_Handler);button_attach(&btn1, SINGLE_CLICK,     BTN1_SINGLE_Click_Handler);button_attach(&btn1, DOUBLE_CLICK,     BTN1_DOUBLE_Click_Handler);button_attach(&btn1, LONG_PRESS_START, BTN1_LONG_PRESS_START_Handler);button_attach(&btn1, LONG_PRESS_HOLD,  BTN1_LONG_PRESS_HOLD_Handler);button_start(&btn1);//make the timer invoking the button_ticks() interval 5ms.//This function is implemented by yourself.__timer_start(button_ticks, 0, 5);while(1){}
}

开源移植 STM32

源文件 main.c

#include "stm32f10x.h"
#include "Delay.h"
#include "LED.h"
#include "KEY.h"
#include "multi_button.h"int main()
{LED_Init(); // LED初始化KEY_Init(); // 按键初始化while (1){Delay_ms(5);button_ticks();// 按键运行}
}

源文件multi_button.c

/** Copyright (c) 2016 Zibin Zheng <znbin@qq.com>* All rights reserved*/#include "multi_button.h"#define EVENT_CB(ev)   if(handle->cb[ev])handle->cb[ev]((void*)handle)
#define PRESS_REPEAT_MAX_NUM  15 /*!< The maximum value of the repeat counter *///button handle list head.
static struct Button* head_handle = NULL;static void button_handler(struct Button* handle);/*** @brief  Initializes the button struct handle.* @param  handle: the button handle struct.* @param  pin_level: read the HAL GPIO of the connected button level.* @param  active_level: pressed GPIO level.* @param  button_id: the button id.* @retval None*/
void button_init(struct Button* handle, u8(*pin_level)(u8), u8 active_level, u8 button_id)
{memset(handle, 0, sizeof(struct Button));handle->event = (u8)NONE_PRESS;handle->hal_button_Level = pin_level;handle->button_level = handle->hal_button_Level(button_id);handle->active_level = active_level;handle->button_id = button_id;
}//  /*button1 init*/
//  button_init(&btn1, read_button_GPIO, 0, KEY1_id);                      // 初始化按键结构体
//  button_attach(&btn1, SINGLE_CLICK, BTN1_SINGLE_CLICK_Handler);         // 添加单击事件
//  button_attach(&btn1, DOUBLE_CLICK, BTN1_DOUBLE_CLICK_Handler);         // 添加双击事件
//  button_attach(&btn1, LONG_PRESS_START, BTN1_LONG_PRESS_START_Handler); // 添加长按事件
//  button_start(&btn1);                                                   // 启动按键  /*** @brief  Attach the button event callback function.* @param  handle: the button handle struct.* @param  event: trigger event type.* @param  cb: callback function.* @retval None*/
void button_attach(struct Button* handle, PressEvent event, BtnCallback7 cb)
{handle->cb[event] = cb;
}/*** @brief  Inquire the button event happen.* @param  handle: the button handle struct.* @retval button event.*/
PressEvent get_button_event(struct Button* handle)
{return (PressEvent)(handle->event);
}/*** @brief  Button driver core function, driver state machine.* @param  handle: the button handle struct.* @retval None*/
static void button_handler(struct Button* handle)
{u8 read_gpio_level = handle->hal_button_Level(handle->button_id);//ticks counter working..4if((handle->state) > 0) handle->ticks++;/*------------button debounce handle---------------*/if(read_gpio_level != handle->button_level) { //not equal to prev one//continue read 3 times same new level changeif(++(handle->debounce_cnt) >= DEBOUNCE_TICKS) {handle->button_level = read_gpio_level;handle->debounce_cnt = 0;}} else { //level not change ,counter reset.handle->debounce_cnt = 0;}/*-----------------State machine-------------------*/switch (handle->state) {case 0:if(handle->button_level == handle->active_level) {	//start press downhandle->event = (u8)PRESS_DOWN;EVENT_CB(PRESS_DOWN);handle->ticks = 0;handle->repeat = 1;handle->state = 1;} else {handle->event = (u8)NONE_PRESS;}break;case 1:if(handle->button_level != handle->active_level) { //released press uphandle->event = (u8)PRESS_UP;EVENT_CB(PRESS_UP);handle->ticks = 0;handle->state = 2;} else if(handle->ticks > LONG_TICKS) {handle->event = (u8)LONG_PRESS_START;EVENT_CB(LONG_PRESS_START);handle->state = 5;}break;case 2:if(handle->button_level == handle->active_level) { //press down againhandle->event = (u8)PRESS_DOWN;EVENT_CB(PRESS_DOWN);if(handle->repeat != PRESS_REPEAT_MAX_NUM) {handle->repeat++;}EVENT_CB(PRESS_REPEAT); // repeat hithandle->ticks = 0;handle->state = 3;} else if(handle->ticks > SHORT_TICKS) { //released timeoutif(handle->repeat == 1) {handle->event = (u8)SINGLE_CLICK;EVENT_CB(SINGLE_CLICK);} else if(handle->repeat == 2) {handle->event = (u8)DOUBLE_CLICK;EVENT_CB(DOUBLE_CLICK); // repeat hit}handle->state = 0;}break;case 3:if(handle->button_level != handle->active_level) { //released press uphandle->event = (u8)PRESS_UP;EVENT_CB(PRESS_UP);if(handle->ticks < SHORT_TICKS) {handle->ticks = 0;handle->state = 2; //repeat press} else {handle->state = 0;}} else if(handle->ticks > SHORT_TICKS) { // SHORT_TICKS < press down hold time < LONG_TICKShandle->state = 1;}break;case 5:if(handle->button_level == handle->active_level) {//continue hold triggerhandle->event = (u8)LONG_PRESS_HOLD;EVENT_CB(LONG_PRESS_HOLD);} else { //releasedhandle->event = (u8)PRESS_UP;EVENT_CB(PRESS_UP);handle->state = 0; //reset}break;default:handle->state = 0; //resetbreak;}
}/*** @brief  Start the button work, add the handle into work list.* @param  handle: target handle struct.* @retval 0: succeed. -1: already exist.*/
int button_start(struct Button* handle)
{struct Button* target = head_handle;while(target) {if(target == handle) return -1;	//already exist.target = target->next;}handle->next = head_handle;head_handle = handle;return 0;
}/*** @brief  Stop the button work, remove the handle off work list.* @param  handle: target handle struct.* @retval None*/
void button_stop(struct Button* handle)
{struct Button** curr;for(curr = &head_handle; *curr; ) {struct Button* entry = *curr;if(entry == handle) {*curr = entry->next;
//			free(entry);return;//glacier add 2021-8-18} else {curr = &entry->next;}}
}/*** @brief  background ticks, timer repeat invoking interval 5ms.* @param  None.* @retval None*/
void button_ticks(void)
{struct Button* target;for(target=head_handle; target; target=target->next) {button_handler(target);}
}

头文件multi_button.h

/** Copyright (c) 2016 Zibin Zheng <znbin@qq.com>* All rights reserved*/#ifndef _MULTI_BUTTON_H_
#define _MULTI_BUTTON_H_#include <string.h>
#include "stm32f10x.h"//According to your need to modify the constants.
#define TICKS_INTERVAL    5	//ms 
#define DEBOUNCE_TICKS    3	//MAX 7 (0 ~ 7)
#define SHORT_TICKS       (300 /TICKS_INTERVAL)
#define LONG_TICKS        (1000 /TICKS_INTERVAL)typedef void (*BtnCallback)(void*);typedef enum {PRESS_DOWN = 0,PRESS_UP,PRESS_REPEAT,SINGLE_CLICK,DOUBLE_CLICK,LONG_PRESS_START,LONG_PRESS_HOLD,number_of_event,NONE_PRESS
}PressEvent;typedef struct Button {u16 ticks;u8  repeat;u8  event;u8  state;u8  debounce_cnt;u8  active_level;u8  button_level;u8  button_id;u8  (*hal_button_Level)(u8 button_id_);BtnCallback  cb[number_of_event];struct Button* next;
}Button;void button_init(struct Button* handle, u8(*pin_level)(u8), u8 active_level, u8 button_id);
void button_attach(struct Button* handle, PressEvent event, BtnCallback cb);
PressEvent get_button_event(struct Button* handle);
int  button_start(struct Button* handle);
void button_stop(struct Button* handle);
void button_ticks(void);#endif

源文件KEY2.C

/********************************************************************************* @file    KEY2.c* @author  LQ* @version* @date    2024-4-29* @brief   multi_button******************************************************************************* @attention********************************************************************************/#include "stm32f10x.h"
#include "KEY.h"
#include "LED.h"#ifdef USE_KEY2struct Button btn1;
struct Button btn2;// GPIO读取回调函数
u8 read_button_GPIO(u8 button_id)
{u8 read_v;switch (button_id){case KEY1_id:read_v = GPIO_ReadInputDataBit(KEY1_GPIO_PORT, KEY1_GPIO_PIN);break;case KEY2_id:read_v = GPIO_ReadInputDataBit(KEY2_GPIO_PORT, KEY2_GPIO_PIN);break;default:break;}return read_v;
}// 单击事件
void BTN1_SINGLE_CLICK_Handler(void *btn)
{switch (((Button *)btn)->button_id){case KEY1_id:LED_ON(LED1);break;case KEY2_id:LED_OFF(LED1);break;default:break;}
}
// 双击事件
void BTN1_DOUBLE_CLICK_Handler(void *btn)
{LED_Toggle(LED1);
}// 长按事件
void BTN1_LONG_PRESS_START_Handler(void *btn)
{LED_OFF(LED1);
}/*** @brief  KEY初始化* @param  None* @retval None*/
void KEY_Init(void)
{/* GPIO_KEY Clock */RCC_APB2PeriphClockCmd(KEY1_GPIO_CLK, ENABLE);RCC_APB2PeriphClockCmd(KEY2_GPIO_CLK, ENABLE);/* GPIO_KEY Pin */GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Pin = KEY1_GPIO_PIN;GPIO_Init(KEY1_GPIO_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = KEY2_GPIO_PIN;GPIO_Init(KEY2_GPIO_PORT, &GPIO_InitStructure);/*button1 init*/button_init(&btn1, read_button_GPIO, 0, KEY1_id);                      // 初始化按键结构体button_attach(&btn1, SINGLE_CLICK, BTN1_SINGLE_CLICK_Handler);         // 添加单击事件button_attach(&btn1, DOUBLE_CLICK, BTN1_DOUBLE_CLICK_Handler);         // 添加双击事件button_attach(&btn1, LONG_PRESS_START, BTN1_LONG_PRESS_START_Handler); // 添加长按事件button_start(&btn1);                                                   // 启动按键                                                ///*button2 init*/button_init(&btn2, read_button_GPIO, 0, KEY2_id);button_attach(&btn2, SINGLE_CLICK, BTN1_SINGLE_CLICK_Handler);button_attach(&btn2, DOUBLE_CLICK, BTN1_DOUBLE_CLICK_Handler);button_start(&btn2);
}#endif

头文件KEY.h

/********************************************************************************* @file    KEY.h* @author  LQ* @version V1.0* @date    2023-4-29* @brief   multi_button******************************************************************************* @attention********************************************************************************/#ifndef _KEY_H
#define _KEY_H#define USE_KEY2 // 定义使用KEY2.c,注释则使用KEY1.c#ifndef USE_KEY2  // 如果USE_KEY2没有被定义就定义名为USE_KEY1的宏
#define USE_KEY1
#endif#include "multi_button.h"/*GPIO宏定义*/
#define KEY1_GPIO_PORT GPIOA
#define KEY1_GPIO_PIN GPIO_Pin_8
#define KEY1_GPIO_CLK RCC_APB2Periph_GPIOA#ifdef USE_KEY2  // 如果USE_KEY2被定定义
#define KEY2_GPIO_PORT GPIOA
#define KEY2_GPIO_PIN GPIO_Pin_9
#define KEY2_GPIO_CLK RCC_APB2Periph_GPIOAenum Button_IDs
{KEY1_id,KEY2_id,
};
#endifvoid KEY_Init(void);#endif

源文件KEY1.C

/********************************************************************************* @file    KEY1.c* @author  LQ* @version* @date    2024-4-29* @brief   multi_button******************************************************************************* @attention********************************************************************************/#include "stm32f10x.h"
#include "KEY.h"
#include "LED.h"#ifdef USE_KEY1struct Button btn1;// GPIO读取回调函数
u8 read_button_GPIO(u8 button_id)
{u8 led_sta;led_sta = GPIO_ReadInputDataBit(KEY1_GPIO_PORT, KEY1_GPIO_PIN);return led_sta;
}// 单击事件
void BTN1_SINGLE_CLICK_Handler(void *btn)
{LED_ON(LED1);
}// 双击事件
void BTN1_DOUBLE_CLICK_Handler(void *btn)
{LED_Toggle(LED1);
}// 长按事件
void BTN1_LONG_PRESS_START_Handler(void *btn)
{LED_OFF(LED1);
}/*** @brief  KEY初始化* @param  None* @retval None*/
void KEY_Init(void)
{/* GPIO_KEY Clock */RCC_APB2PeriphClockCmd(KEY1_GPIO_CLK, ENABLE);/* GPIO_KEY pin */GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin = KEY1_GPIO_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(KEY1_GPIO_PORT, &GPIO_InitStructure);/*button init*/button_init(&btn1, read_button_GPIO, 0, 0);                            // 初始化按键结构体button_attach(&btn1, SINGLE_CLICK, BTN1_SINGLE_CLICK_Handler);         // 添加单击事件button_attach(&btn1, DOUBLE_CLICK, BTN1_DOUBLE_CLICK_Handler);         // 添加双击事件button_attach(&btn1, LONG_PRESS_START, BTN1_LONG_PRESS_START_Handler); // 添加长按事件button_start(&btn1);                                                   // 启动按键
}#endif

参考资料

  • [1] 【B@落子叶初LQ】MultiButton_小型按键驱动模块
  • [2] 【GitHub】https://github.com/0x1abin/MultiButton/tree/master

相关文章:

【开源移植】MultiButton_小型按键驱动模块移植

MultiButton 简介 MultiButton 是一个小巧简单易用的事件驱动型按键驱动模块&#xff0c;可无限量扩展按键&#xff0c;按键事件的回调异步处理方式可以简化你的程序结构&#xff0c;去除冗余的按键处理硬编码&#xff0c;让你的按键业务逻辑更清晰。 使用方法 1.先申请一个…...

【Python系列】Python 字典合并

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...

C# 设计模式之装饰器模式

总目录 前言 装饰器模式的主要作用就是扩展一个类的功能&#xff0c;或给一个类添加多个变化的情况。学习面向对象的都知道&#xff0c;如果想单纯的给某个类增加一些功能&#xff0c;可以直接继承该类生成一个子类就可以。应对一些简单的业务场景继承也就够了&#xff0c;但是…...

【uniapp离线打包】(基于Android studio)

文章目录 uniapp打包官方教程入口一、准备工作(工具三大件)Android Studio版本推荐 二、准备工作&#xff08;Android壳和uniapp包&#xff09;导入Android壳生成uniapp包将uniapp包导入android壳降低jdk版本 三、准备工作&#xff08;证书&#xff09;准备Android平台离线签名…...

稳稳的年化10%,多任务时序动量策略——基于pytorch的深度学习策略(附python代码)

原创文章第608篇&#xff0c;专注“AI量化投资、世界运行的规律、个人成长与财富自由"。 做因子挖掘这段时间&#xff0c;有一个观感。 传统的因子挖掘&#xff0c;尤其是手工构造因子&#xff0c;到遗传算法因子挖掘。——本身也是一种”拟合“&#xff0c;或者说试图”…...

C++分析AVL树

目录 AVL树介绍 AVL树平衡因子更新分析 AVL树插入时旋转与平衡因子更新 左单旋 右单旋 左右单旋 右左单旋 AVL旋转可行性 AVL树节点删除&#xff08;待补充&#xff09; AVL树分析 AVL树介绍 二叉搜索树在某些极端情况下可能会退化&#xff0c;为了解决这个问题&…...

aurora8b10b ip的使用(framing接口下的数据回环测试)

文章目录 一、Aurora8B/10B协议二、时钟、复位与状态指示1、时钟2、复位3、状态指示 三、数据发送、接受接口&#xff08;1&#xff09;AXI4-Stream位排序&#xff08;2&#xff09;Streaming接口&#xff08;3&#xff09;Framing接口&#xff08;帧传输接口&#xff09; 四、…...

如何通过OpenCV判断图片是否包含在视频内?

要判断图片是否包含在视频内&#xff0c;可以使用计算机视觉技术和图像处理方法。这通常涉及特征匹配或模板匹配。以下是一个基于OpenCV的解决方案&#xff0c;通过特征匹配的方法来实现这一目标。 步骤概述 读取视频和图片&#xff1a; 使用OpenCV读取视频文件和图片文件。 …...

大数据基础:Spark重要知识汇总

文章目录 Spark重要知识汇总 一、Spark 是什么 二、Spark 四大特点 三、Spark框架模块介绍 3.1、Spark Core的RDD详解 3.1.1、什么是RDD 3.1.2、RDD是怎么理解的 四、Spark 运行模式 4.1、Spark本地模式介绍 4.2、Spark集群模式 Standalone 4.3、Spark集群模式 Stan…...

Executable Code Actions Elicit Better LLM Agents

Executable Code Actions Elicit Better LLM Agents Github: https://github.com/xingyaoww/code-act 一、动机 大语言模型展现出很强的推理能力。但是现如今大模型作为Agent的时候&#xff0c;在执行Action时依然还是通过text-based&#xff08;文本模态&#xff09;后者JSO…...

循环结构(三)——do-while语句

目录 &#x1f341;引言 &#x1f341;一、语句格式 &#x1f680;格式1 &#x1f680;格式2 &#x1f341;二、语句执行过程 &#x1f341;三、实例 &#x1f680;【例1】 &#x1f680;【例2】 &#x1f680;【例3】 &#x1f341;总结 &#x1f341;备注 &am…...

pandas 或筛选

pandas 或筛选 在Pandas中&#xff0c;可以使用DataFrame.loc方法结合逻辑运算符来实现或筛选。这里提供一个简单的例子&#xff1a; import pandas as pd 创建示例DataFrame df pd.DataFrame({ ‘A’: [1, 2, 3, 4], ‘B’: [5, 6, 7, 8], ‘C’: [9, 10, 11, 12] }) 设定…...

工具(1)—截屏和贴图工具snipaste

演示和写代码文档的时候&#xff0c;总是需要用到截图。在之前的流程里面&#xff0c;一般是打开WX或者QQ&#xff0c;找到截图工具。但是尴尬的是&#xff0c;有时候&#xff0c;微信没登录&#xff0c;而你这个时候就在写文档。为了截个图&#xff0c;还需要启动微信&#xf…...

【从零开始一步步学习VSOA开发】快速体验SylixOS

快速体验SylixOS 安装完毕RealEvo-IDE 后&#xff0c;同时也安装了RealEvo-Simulator。RealEvo-Simulator 是一个虚拟运行环境&#xff0c;可以模拟各种体系结构并在其上运行 SylixOS。相比于物理板卡&#xff0c;在 RealEvo-Simulator 进行运行调测更加的方便快捷且成本低廉。…...

Ansible自动化:简化IT基础设施管理的艺术

目录 一.前言 二.Ansible简介 2.1什么是Ansible&#xff1f; 2.2Ansible的主要特点 2.3Ansible的应用场景 三.探索Ansible的高级功能 3.1 高级Playbook特性 3.2 Ansible Vault 3.3 动态Inventory 3.4Ansible Tower&#xff08;AWX&#xff09; 3.5模块开发 3.6 Ans…...

【Rust光年纪】探索Rust语言中的WebSocket库和框架:优劣一览

Rust语言中的实时通信利器&#xff1a;WebSocket库与框架全面解析 前言 随着Rust语言的不断发展&#xff0c;其在Web开发领域也变得越来越受欢迎。WebSocket作为实现实时通信的重要技术&#xff0c;在Rust的生态系统中也有多个库和框架提供了支持。本文将介绍几个主流的Rust …...

HTML 基础结构

目录 1. 文档声明 2. 根标签 3. 头部元素 4. 主题元素 5. 注释 6. 演示 1. 文档声明 <!DOCTYPE html>&#xff1a;声明文档类型&#xff0c;表示该文档是 html 文档&#xff0c; 2. 根标签 &#xff08;1&#xff09;所有的其他标签都要放在一对根标签中&#…...

多页合同怎么盖骑缝章_电子合同怎么盖骑缝章?

多页合同怎么盖骑缝章&#xff1f;电子合同怎么盖骑缝章&#xff1f; 对于纸质多页合同&#xff0c;盖骑缝章是一种常见的做法&#xff0c;用于确保合同的完整性&#xff0c;防止任何页面被替换或篡改。以下是盖骑缝章的基本步骤&#xff1a; 将所有合同页面平铺在桌面上。用…...

GD 32 IIC通信协议

前言&#xff1a; ... 通信方式 通信方式分为串行通信和并行通信。常见的串口就是串行通信的方式 常用的串行通信接口 常用的串行通信方式有USART,IIC,USB,CAN总线 同步与异步 同步通信&#xff1a;IIC是同步通信&#xff0c;有两个线一个是时钟信号线&#xff0c;一个数数据…...

Spring Task初学

介绍 Spring Task 是Spring框架提供的任务调度工具&#xff0c;可以按照约定的时间自动执行某个代码逻辑 为什么要在Java程序中使用Spring Task? 运行效果 cron表达式&#xff1a;一般日和周不会同时出现 入门案例 启动类添加注解EnableScheduling开始任务调度 创建MyTask类…...

决策树可解释性分析

决策树可解释性分析 决策树是一种广泛使用的机器学习算法&#xff0c;以其直观的结构和可解释性而闻名。在许多应用场景中&#xff0c;尤其是金融、医疗等领域&#xff0c;模型的可解释性至关重要。本文将从决策路径、节点信息、特征重要性等多个方面分析决策树的可解释性&…...

BUGKU-WEB never_give_up

解题思路 F12查看请求和响应&#xff0c;查找线索 相关工具 base64解码URL解码Burp Suit抓包 页面源码提示 <!--1p.html--> 2. 去访问这个文件&#xff0c;发现直接跳转到BUGKU首页&#xff0c;有猫腻那就下载看看这个文件内容吧 爬虫下载这个文件 import requests …...

hive自动安装脚本

使用该脚本注意事项 安装hive之前确定机子有网络。或者yum 更改为本地源&#xff0c;因为会使用epel仓库下载一个pv的软件使用该脚本前提是自行安装好mysql数据库准备好tomcat软件包&#xff0c;该脚本使用tomcat9.x版本测试过能正常执行安装成功&#xff0c;其他版本没有测试…...

unix 用户态 内核态

在UNIX操作系统中&#xff0c;"用户态"和"内核态"是两种不同的运行模式&#xff0c;它们定义了程序在执行时的权限级别&#xff1a; 用户态&#xff08;User Mode&#xff09;&#xff1a; 用户态是程序运行的常规状态&#xff0c;大多数应用程序在执行时…...

GD32 IAP升级——boot和app相互切换

GD32 IAP升级——boot和app相互切换 目录 GD32 IAP升级——boot和app相互切换1 Keil工程设置1.1 修改ROM1.2 Keil烧录配置 2 代码编写2.1 app跳转2.2 软件重启2.3 app中断向量表偏移 结束语 1 Keil工程设置 1.1 修改ROM GD32内部Flash是一整块连续的内存&#xff0c;但是因为…...

C++11革新之旅:探索C++编程的无限可能

C11革新之旅&#xff1a;探索C编程的无限可能 C11&#xff0c;作为C语言的一个重要标准&#xff0c;为C编程带来了革命性的变革。它不仅引入了众多新特性和改进&#xff0c;还极大地增强了C的表达能力、提高了程序的性能和资源利用率。本文将从多个方面深入探讨C11的新特性&am…...

免费自动化AI视频剪辑工具

下载地址&#xff1a;https://pan.quark.cn/s/3c5995da512e FunClip是一款完全开源、本地部署的自动化视频剪辑工具&#xff0c;通过调用阿里巴巴通义实验室开源的FunASR Paraformer系列模型进行视频的语音识别&#xff0c;随后用户可以自由选择识别结果中的文本片段或说话人&a…...

Linux中安装C#的.net,创建运行后端或控制台项目

安装脚本命令&#xff1a; 创建一个sh文件并将该文件更改权限运行 sudo apt update wget https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb sudo dpkg -i packages-microsoft-prod.deb sudo apt-get upd…...

最长上升子序列LIS(一般+优化)

1. 题目 题目链接&#xff1a; B3637 最长上升子序列 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 输入样例&#xff1a; 6 1 2 4 1 3 4 输出样例&#xff1a; 4 说明/提示&#xff1a; 分别取出 1、2、3、4 即可。 2. 具体实现 2.1 一般做法 dp[i]表示第i个位置的…...

【Python系列】Python 协程:并发编程的新篇章

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...

快速优化网站建设/海南百度推广公司电话

夫妻之间订立借款协议&#xff0c;能否成立借款关系&#xff1f; 一般而言&#xff0c;除法律另有规定或当事人另有约定外&#xff0c;婚后夫妻一方所得财产无论存于哪一方的名下账户&#xff0c;均属夫妻共同共有。夫妻之间钱款往来转账&#xff0c;仅改变其控制权&#xff0…...

做网站要找什么/网站搜索优化技巧

在对数据字段进行分类管理时&#xff0c;利用动态树折叠数据是一个很好的方法&#xff0c;也就是点击数据前面的加号才展开对应下面的数据&#xff0c;如下图。那这样的效果在制作报表时该如何实现呢&#xff1f; 下面以报表工具FineReport为例介绍。 思路&#xff1a; 通过将模…...

网站点击推广/百度一下官方入口

mysql主从结构下默认会在主上产生大量如mysql-bin*的log日志文件&#xff0c;这会消耗大量的硬盘空间。本篇文章主要介绍在保持MySQL主从复制的功能情况下清除bin log文件的方法。 1. 手动清除bin log文件 1.1 删除一段时间前的log mysql -u root -pmysql> purge master l…...

网站怎么做可以被收录/电脑办公软件培训班

Orientations: SupportedOrientations支持的手机朝向,Orientation当前朝向 手机朝向控制拥有Portrait(正直),Landscape(平放),PortraitOrLandscape(正直or平放)三种 XNA的设置方法: graphics.SupportedOrientations DisplayOrientation.Portrait | DisplayOrientation.Landsca…...

网站建设自建服务器/关键词歌曲

简介&#xff1a; seata-golang 是一个分布式事务框架&#xff0c;实现了 AT 模式和 TCC 模式&#xff0c;AT 模式相较 TCC 模式对代码的入侵性更小、需要开发的接口更少&#xff1b;但 AT 模式对事务操作的数据持有全局锁&#xff0c;从这点来说&#xff0c;TCC 模式性能更好。…...

东莞南城网站建设公司/疫情最严重的三个省

说起软件系统的层次结构&#xff0c;众说纷纭。不过&#xff0c;许多人都认为传统的C/S结构是两层结构——数据库服务器是一层&#xff0c;客户端应用程序是一层。从这一点来说&#xff0c;B/S结构可认为是三层结构——数据库服务器层、WEB应用服务器层和客户端浏览器一层。 但…...