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

单片机软件定时器V4.0

单片机软件定时器V4.0

用于单片机定时执行任务等,比如LED GPIO等定时控制,内置前后台工作模式

头文件有使用例子

#ifndef __SORFTIME_APP_H
#define __SORFTIME_APP_H#ifdef __cplusplus
extern "C"
{
#endif#include <stdint.h>// #define ST_CLIENT_SERVER_MODE 1  /*取消注释切换到前后台模式*/#define MAX_TIMER_NUM 16 /* 定时器最大个数(可修改) *//**移植修改步骤**//*1:st_sorft_timer_init(); 初始化2: 把	st_sorft_timer_counter_prosess(); 放入1ms中断回调或1ms的OS任务中3: 修改 MAX_TIMER_NUM  的定义值,比如需要用到10个定时器就改为>=104: 查看底部例程使用方法5: 记得把printf注释掉,如果没有配置printf会停在printf的while循环里面*/#if 1typedef unsigned char u8;typedef unsigned short int u16;typedef unsigned int u32;
#endif
#if 0typedef unsigned char uint8_t;typedef unsigned short int uint16_t;typedef unsigned int uint32_t;
#endiftypedef enum timer_run_mode{TIM_INTERUPUT_MODE = 0, /* 中断模式*/
#ifdef ST_CLIENT_SERVER_MODETIM_CLIENT_SERVER_MODE = 1, /* 前后台模式*/
#endif} st_e_run_mode_t;/***********状态枚举***********/typedef enum timer_init_state{TIM_CRAT_SUCES = 0, /* create succes 创建成功状态 */TIM_CRAT_ERROR = 1, /* create faild  创建失败状态 */} st_e_state_crat_t;typedef enum timer_run_state{TIM_LOCK = 2,	/* 锁定计数,不能再次更新计数值,只能等到计数结束 */TIM_UNLOCK = 3, /* 不锁定计数,可以中途手动更新计数值 */TIM_END = 4,	/* 计数值到达目标值,停止计数 */} st_e_state_run_t;typedef enum timer_end_state{TIM_ONCE = 5,  /* 单次计数模式*/TIM_CYCLE = 6, /* 循环计数模式*/} st_e_state_end_t;typedef enum timer_close_state{TIM_DESTROYED = 7, /* 销毁状态 (擦除这个定时器所占坑位资源)*/TIM_SUSPEND = 8	   /* 挂起定时器 (会占用一个定时器坑位,不推荐)*/} st_e_state_close_t;typedef void (*st_rtn_func_t)(uint16_t);/*******单个定时器结构体 *************/typedef struct id_menber{uint16_t id;				/* 软件定时器id */uint32_t count;				/* 计数运行值 */uint32_t target;			/* 计数目标值 */st_e_state_run_t run_state; /* 运行时的状态 */st_e_state_end_t end_state; /* 结束后的状态 */st_rtn_func_t rtn_func;		/* 计时结束的回调函数 */} st_id_t;/*******所有定时器结构体 *************/typedef struct timer_id{st_id_t id_ary[MAX_TIMER_NUM]; /*数组*/uint16_t timer_last_index;	   /*当前定时器最大个数*/} s_timer_id;#ifdef ST_CLIENT_SERVER_MODE/*前后台模式,前台运行在main while模式,后台中断定时器设置标志*/typedef struct timer_event{uint16_t event_id[MAX_TIMER_NUM];st_rtn_func_t event_ary[MAX_TIMER_NUM]; /*数组*/} s_event_id;
#endifvoid st_sorft_timer_init(void);			   /*初始化软件定时器*/void st_sorft_timer_counter_prosess(void); /*此函数放入定时器中断回调函数*/
#ifdef ST_CLIENT_SERVER_MODE/*这个函数放入main 的while循环*/void st_sorft_timer_event_prosess(void);
#endifst_e_state_crat_t st_start_timer(uint16_t timer_id, uint32_t count, st_e_state_run_t run_state); /*开启一个定时器*/st_e_state_crat_t st_start_once_timer(uint16_t timer_id, uint32_t count, st_e_state_run_t run_state); /*开启一次定时器*/st_e_state_crat_t st_start_cb_timer(uint16_t timer_id, uint32_t count, st_e_state_run_t run_state, st_e_state_end_t end_state, st_rtn_func_t rtn_func); /*计时结束,执行回调函数,函数执行完毕自动销毁该定时器*/st_e_state_close_t st_close_timer(uint16_t timer_id, st_e_state_close_t close_state); /* 关掉或者暂停一个定时器 */st_e_state_run_t st_timer_state(uint16_t timer_id); /* 读取定时器状态 */uint32_t st_timer_count_value(uint16_t timer_id); /*查询定时器计数值 *///**使用例程 start**///*#define EVENT_ID_LED 0x10#define EVENT_ID_GPIO 0x11#define EVENT_ID_SPI 0x12#define EVENT_ID_TIME 0x13#define LOG(...) printf(__VA_ARGS__)void app_main_process(uint16_t id){if (id == EVENT_ID_LED){st_start_cb_timer(EVENT_ID_LED, 30, TIM_LOCK, TIM_ONCE, app_main_process);LOG("LED\n");return;}if (id == EVENT_ID_GPIO){st_start_cb_timer(EVENT_ID_GPIO, 40, TIM_LOCK, TIM_ONCE, app_main_process);LOG("GPIO\n");return;}if (id == EVENT_ID_SPI){LOG("SPI\n");return;}}main(){st_sorft_timer_init();st_start_cb_timer(EVENT_ID_LED, 5, TIM_LOCK, TIM_ONCE, app_main_process);st_start_cb_timer(EVENT_ID_GPIO, 10, TIM_LOCK, TIM_CYCLE, app_main_process);st_start_cb_timer(EVENT_ID_SPI, 20, TIM_UNLOK, TIM_CYCLE, app_main_process);while (1){// st_sorft_timer_event_prosess(); //前后台模式}return 0;}*///**end**//#ifdef __cplusplus
}
#endif
#endif
#include "sorftime_app.h"#include "stdio.h"/***********计数值**************/
#define ST_START_COUNT_VALUE 0
#define ST_END_COUNT_VALUE 0xFFFFFFFE
#define ST_ID_NULL 0
/************ID值****************/
#define ST_NULL_ID 0
#define ST_NEW_ID 1
#define ST_OLD_ID 2static s_timer_id timer_id_ary;static uint8_t OPEN_COUNTER = 0;
static uint8_t MAX_USE_NUMBER = 0;#ifdef ST_CLIENT_SERVER_MODE
static s_event_id event_id_ary;
static void add_event_to_list(st_rtn_func_t event_cb, uint16_t id);
#endif/*** @brief 定时器中断回调,对所有计数值进行减少*       中断触发为 1ms* 		根据用户层需要的计时时间,到达就改变状态**/
void st_sorft_timer_counter_prosess(void)
{ /* 此函数放入中断回调*/uint8_t i = 0;st_id_t end_id;if (OPEN_COUNTER){for (i = 0; i < MAX_USE_NUMBER; i++){if ((timer_id_ary.id_ary[i].id) != ST_ID_NULL){if ((timer_id_ary.id_ary[i].run_state != TIM_SUSPEND) && (timer_id_ary.id_ary[i].run_state != TIM_END)){if ((++(timer_id_ary.id_ary[i].count)) >= (timer_id_ary.id_ary[i].target)){timer_id_ary.id_ary[i].count = ST_END_COUNT_VALUE;end_id.id = timer_id_ary.id_ary[i].id;end_id.run_state = timer_id_ary.id_ary[i].run_state;end_id.end_state = timer_id_ary.id_ary[i].end_state;end_id.rtn_func = timer_id_ary.id_ary[i].rtn_func;timer_id_ary.id_ary[i].run_state = TIM_END;/*结束定时*/if (end_id.end_state == TIM_ONCE){timer_id_ary.id_ary[i].id = ST_ID_NULL;timer_id_ary.id_ary[i].count = ST_END_COUNT_VALUE;timer_id_ary.id_ary[i].run_state = (st_e_state_run_t)TIM_DESTROYED;timer_id_ary.id_ary[i].end_state = (st_e_state_end_t)TIM_DESTROYED;timer_id_ary.id_ary[i].target = ST_END_COUNT_VALUE;timer_id_ary.id_ary[i].rtn_func = NULL;}/*循环触发*/if (end_id.end_state == TIM_CYCLE){timer_id_ary.id_ary[i].count = ST_START_COUNT_VALUE;timer_id_ary.id_ary[i].run_state = end_id.run_state;}/*执行回调*/if (end_id.rtn_func != NULL){
#ifdef ST_CLIENT_SERVER_MODEadd_event_to_list(end_id.rtn_func, end_id.id);#elseend_id.rtn_func(end_id.id);
#endif}}}}}}
}#ifdef ST_CLIENT_SERVER_MODE
/*** @brief 前台调用,处理对应id的事件* 后台中断将触发的timer id 标记* 此函数负责处理对应的id事件调用**/
void st_sorft_timer_event_prosess(void)
{uint16_t i = 0;for (i = 0; i < MAX_TIMER_NUM; i++){if (event_id_ary.event_ary[i] != NULL){event_id_ary.event_ary[i](event_id_ary.event_id[i]);event_id_ary.event_id[i] = ST_ID_NULL;event_id_ary.event_ary[i] = NULL;return;}}
}
#endif
#ifdef ST_CLIENT_SERVER_MODE
/*** @brief 添加事件回调到列表**/
static void add_event_to_list(st_rtn_func_t event_cb, uint16_t id)
{uint16_t i = 0;for (i = 0; i < MAX_TIMER_NUM; i++){if (event_id_ary.event_ary[i] == NULL){event_id_ary.event_ary[i] = event_cb;event_id_ary.event_id[i] = id;return;}}
}
#endif
/**@brief 定时器id赋值,使用定时器前先调用一次此接口
**/
void st_sorft_timer_init(void)
{uint16_t i = 0;/*  清空定时器所有 timer_id = 0*/for (i = 0; i < MAX_TIMER_NUM; i++){timer_id_ary.id_ary[i].id = ST_ID_NULL;timer_id_ary.id_ary[i].count = ST_END_COUNT_VALUE;timer_id_ary.id_ary[i].target = ST_END_COUNT_VALUE;timer_id_ary.id_ary[i].run_state = (st_e_state_run_t)TIM_DESTROYED;timer_id_ary.id_ary[i].end_state = (st_e_state_end_t)TIM_DESTROYED;timer_id_ary.id_ary[i].rtn_func = NULL;#ifdef ST_CLIENT_SERVER_MODEevent_id_ary.event_id[i] = ST_ID_NULL;event_id_ary.event_ary[i] = NULL;
#endif}timer_id_ary.timer_last_index = 0; /* 对管理的timer进行计数*/OPEN_COUNTER = 1;
}/**@brief 启动一个定时器
*		timer_id 用户自定义ID
*		需要计数时间MS
*		计数状态,LOCK_TIMING(计数时无法刷新计数值,只能等到计数结束)
*		计数状态,TIMING 可以中途重新刷新计数值
**/st_e_state_crat_t st_start_timer(uint16_t timer_id, uint32_t count, st_e_state_run_t run_state)
{uint16_t i = 0;uint8_t first_i = 0;uint8_t flag = ST_NULL_ID;if (timer_id == 0 || count == 0){return TIM_CRAT_ERROR;}if (!OPEN_COUNTER){st_sorft_timer_init();}/*************查找相同ID或者直接创建****************/for (i = 0; i < MAX_TIMER_NUM; i++){if (timer_id_ary.id_ary[i].id == timer_id){first_i = i;flag = ST_OLD_ID; // 查找相同IDif ((timer_id_ary.id_ary[i].run_state == TIM_LOCK) || (timer_id_ary.id_ary[i].run_state == TIM_END)){return (st_e_state_crat_t)TIM_LOCK;}break;}if ((timer_id_ary.id_ary[i].id == ST_ID_NULL) && (!flag)){first_i = i;flag = ST_NEW_ID; /* 查找并记录空闲ID*/}}if (!flag){return TIM_CRAT_ERROR; /* 防止未查找到*/}if ((timer_id_ary.timer_last_index) < MAX_TIMER_NUM){timer_id_ary.id_ary[first_i].id = timer_id;timer_id_ary.id_ary[first_i].count = ST_START_COUNT_VALUE; /* 计数初始值*/timer_id_ary.id_ary[first_i].target = count;timer_id_ary.id_ary[first_i].run_state = run_state;timer_id_ary.id_ary[first_i].end_state = (st_e_state_end_t)TIM_DESTROYED;timer_id_ary.id_ary[first_i].rtn_func = NULL;if (flag == ST_NEW_ID){if (first_i >= MAX_USE_NUMBER){MAX_USE_NUMBER = first_i + 1;}if (++timer_id_ary.timer_last_index >= MAX_USE_NUMBER) /* 新增一个ID ,进行+1计数 */{timer_id_ary.timer_last_index = MAX_USE_NUMBER;}}return TIM_CRAT_SUCES; /* 返回创建成功的状态 */}else{return TIM_CRAT_ERROR;}
}
/***@brief 启动一次定时器* 计时结束自动销毁定时器* **/
st_e_state_crat_t st_start_once_timer(uint16_t timer_id, uint32_t count, st_e_state_run_t run_state)
{uint16_t i = 0;uint8_t first_i = 0;uint8_t flag = ST_NULL_ID;if (timer_id == 0 || count == 0){return (st_e_state_crat_t)TIM_DESTROYED;}if (!OPEN_COUNTER){st_sorft_timer_init();}/*************查找相同ID或者直接创建****************/for (i = 0; i < MAX_TIMER_NUM; i++){if (timer_id_ary.id_ary[i].id == timer_id){first_i = i;flag = ST_OLD_ID; /* 查找相同ID */if (timer_id_ary.id_ary[i].run_state == TIM_LOCK){return (st_e_state_crat_t)TIM_LOCK;}break;}if ((timer_id_ary.id_ary[i].id == ST_ID_NULL) && (!flag)){first_i = i;flag = ST_NEW_ID;}}if (!flag){return TIM_CRAT_ERROR;}if ((timer_id_ary.timer_last_index) < MAX_TIMER_NUM){timer_id_ary.id_ary[first_i].id = timer_id;timer_id_ary.id_ary[first_i].count = ST_START_COUNT_VALUE;timer_id_ary.id_ary[first_i].target = count;timer_id_ary.id_ary[first_i].run_state = run_state;timer_id_ary.id_ary[first_i].end_state = TIM_ONCE;timer_id_ary.id_ary[first_i].rtn_func = NULL;if (flag == ST_NEW_ID){if (first_i >= MAX_USE_NUMBER){MAX_USE_NUMBER = first_i + 1;}if (++timer_id_ary.timer_last_index >= MAX_USE_NUMBER){timer_id_ary.timer_last_index = MAX_USE_NUMBER;}}return TIM_CRAT_SUCES;}else{return TIM_CRAT_ERROR;}
}/*** @brief 启动一次定时器* 计时结束自动销毁定时器**/
st_e_state_crat_t st_start_cb_timer(uint16_t timer_id,uint32_t count,st_e_state_run_t run_state,st_e_state_end_t end_state,st_rtn_func_t rtn_func)
{uint16_t i = 0;uint8_t first_i = 0;uint8_t flag = ST_NULL_ID;if (timer_id == 0 || count == 0 || rtn_func == NULL){return (st_e_state_crat_t)TIM_DESTROYED;}if (!OPEN_COUNTER){st_sorft_timer_init();}/*************查找相同ID或者直接创建****************/for (i = 0; i < MAX_TIMER_NUM; i++){if (timer_id_ary.id_ary[i].id == timer_id){first_i = i;flag = ST_OLD_ID;if (timer_id_ary.id_ary[i].run_state == TIM_LOCK){return (st_e_state_crat_t)TIM_LOCK;}break;}if ((timer_id_ary.id_ary[i].id == ST_ID_NULL) && (!flag)){first_i = i;flag = ST_NEW_ID;}}if (!flag){return TIM_CRAT_ERROR;}if ((timer_id_ary.timer_last_index) < MAX_TIMER_NUM){timer_id_ary.id_ary[first_i].id = timer_id;timer_id_ary.id_ary[first_i].count = ST_START_COUNT_VALUE;timer_id_ary.id_ary[first_i].target = count;timer_id_ary.id_ary[first_i].run_state = run_state;timer_id_ary.id_ary[first_i].end_state = end_state;timer_id_ary.id_ary[first_i].rtn_func = rtn_func;if (flag == ST_NEW_ID){if (first_i >= MAX_USE_NUMBER){MAX_USE_NUMBER = first_i + 1;}if (++timer_id_ary.timer_last_index >= MAX_USE_NUMBER){timer_id_ary.timer_last_index = MAX_USE_NUMBER;}}return TIM_CRAT_SUCES; /*返回创建成功的状态*/}else{return TIM_CRAT_ERROR;}
}/*** @brief 关掉定时器,* TIM_SUSPEND 定时器不销毁,计数暂停* TIM_DESTROYED  销毁定时器,ID将被抹去*/
st_e_state_close_t st_close_timer(uint16_t timer_id, st_e_state_close_t close_state)
{uint16_t i = 0;if (timer_id == 0){return TIM_DESTROYED;}for (i = 0; i < MAX_USE_NUMBER; i++){if (timer_id_ary.id_ary[i].id == timer_id){break;}}if (i >= MAX_USE_NUMBER){return TIM_DESTROYED;}if (close_state == TIM_SUSPEND){ /* 暂停定时器,也就是关掉的意思 *//***暂停定时器****	查看是否有相同ID       	 ********/if ((timer_id_ary.id_ary[i].id) == timer_id){timer_id_ary.id_ary[i].id = timer_id; /*ID不能抹去 */timer_id_ary.id_ary[i].count = ST_END_COUNT_VALUE;timer_id_ary.id_ary[i].run_state = (st_e_state_run_t)TIM_SUSPEND; /*挂起定时器 */timer_id_ary.id_ary[i].end_state = (st_e_state_end_t)TIM_SUSPEND;timer_id_ary.id_ary[i].target = ST_END_COUNT_VALUE;return TIM_SUSPEND;}}else if (close_state == TIM_DESTROYED){ /* 销毁定时器 *//****销毁定时器***	查看是否有相同ID       	 ********/if ((timer_id_ary.id_ary[i].id) == timer_id){timer_id_ary.id_ary[i].id = ST_ID_NULL;timer_id_ary.id_ary[i].count = ST_END_COUNT_VALUE;timer_id_ary.id_ary[i].run_state = (st_e_state_run_t)TIM_DESTROYED;timer_id_ary.id_ary[i].end_state = (st_e_state_end_t)TIM_DESTROYED;timer_id_ary.id_ary[i].target = ST_END_COUNT_VALUE;timer_id_ary.id_ary[i].rtn_func = NULL;if (timer_id_ary.timer_last_index > 0){timer_id_ary.timer_last_index--;}if (timer_id_ary.id_ary[MAX_USE_NUMBER - 1].run_state == TIM_DESTROYED){MAX_USE_NUMBER--;}return TIM_DESTROYED; // 返回刚刚创建的状态}}return TIM_DESTROYED;
}/***@bref 返回定时器状态有此ID的定时器就返回当前状态没有就返回DESTROYED* **/
st_e_state_run_t st_timer_state(uint16_t timer_id)
{uint16_t i = 0;if (timer_id == 0){return (st_e_state_run_t)TIM_DESTROYED;}for (i = 0; i < MAX_TIMER_NUM; i++){if ((timer_id_ary.id_ary[i].id) == timer_id){return timer_id_ary.id_ary[i].run_state;}}return (st_e_state_run_t)TIM_DESTROYED;
}/*@bref 查询计数值
*/
uint32_t st_timer_count_value(uint16_t timer_id)
{uint16_t i = 0;if (timer_id == 0){return ST_END_COUNT_VALUE;}for (i = 0; i < MAX_TIMER_NUM; i++){if ((timer_id_ary.id_ary[i].id) == timer_id){return timer_id_ary.id_ary[i].count;}}return ST_END_COUNT_VALUE;
}

相关文章:

单片机软件定时器V4.0

单片机软件定时器V4.0 用于单片机定时执行任务等&#xff0c;比如LED GPIO等定时控制&#xff0c;内置前后台工作模式 头文件有使用例子 #ifndef __SORFTIME_APP_H #define __SORFTIME_APP_H#ifdef __cplusplus extern "C" { #endif#include <stdint.h>// #…...

超完整Docker学习记录,Docker常用命令详解

前言 关于国内拉取不到docker镜像的问题&#xff0c;可以利用Github Action将需要的镜像转存到阿里云私有仓库&#xff0c;然后再通过阿里云私有仓库去拉取就可以了。 参考项目地址&#xff1a;使用Github Action将国外的Docker镜像转存到阿里云私有仓库 一、Docker简介 Do…...

C++ 入门第26天:文件与流操作基础

往期回顾&#xff1a; C 入门第23天&#xff1a;Lambda 表达式与标准库算法入门-CSDN博客 C 入门第24天&#xff1a;C11 多线程基础-CSDN博客 C 入门第25天&#xff1a;线程池&#xff08;Thread Pool&#xff09;基础-CSDN博客 C 入门第26天&#xff1a;文件与流操作基础 前言…...

使用python将多个Excel表合并成一个表

import pandas as pd# 定义要合并的Excel文件路径和名称 file_paths [file1.xlsx, file2.xlsx, file3.xlsx, file4.xlsx, file5.xlsx]# 创建一个空的DataFrame来存储合并后的数据 merged_data pd.DataFrame()# 循环遍历每个Excel文件&#xff0c;并读取其中的数据 for file_p…...

halcon三维点云数据处理(七)find_shape_model_3d_recompute_score

目录 一、find_shape_model_3d_recompute_score例程代码二、set_object_model_3d_attrib_mod函数三、prepare_object_model_3d 函数四、create_cube_shape_model_3d函数五、获得CamPose六、project_cube_image函数七、find_shape_model_3d函数八、project_shape_model_3d函数 一…...

vue js实现时钟以及刻度效果

2025.01.08今天我学习如何用js实现时钟样式&#xff0c;效果如下&#xff1a; 一、html代码如下&#xff1a; <template><!--圆圈--><div class"notice_border"><div class"notice_position notice_name_class" v-for"item in …...

unity学习15:预制体prefab

目录 1 创建多个gameobject 2 创建prefab 2.1 创建prefab &#xff08;类&#xff09; 2.2 prefab 是一个文件 2.3 prefab可以导出 3 创建prefab variant &#xff08;子类&#xff09; 3.1 除了创建多个独立的prefab&#xff0c; 还可以创建 prefab variant 3.2 他…...

基于Thinkphp6+uniapp的陪玩陪聊软件开发方案分析

使用uni-app框架进行前端开发。uni-app是一个使用Vue.js开发所有前端应用的框架&#xff0c;支持一次编写&#xff0c;多端发布&#xff0c;包括APP、小程序、H5等。 使用Thinkphp6框架进行后端开发。Thinkphp6是一个轻量级、高性能、面向对象的PHP开发框架&#xff0c;具有易…...

MySQL - 子查询和相关子查询详解

在SQL中&#xff0c;子查询&#xff08;Subquery&#xff09;和相关子查询&#xff08;Correlated Subquery&#xff09;是非常强大且灵活的工具&#xff0c;可以用于执行复杂的数据检索和操作。它们允许我们在一个查询中嵌套另一个查询&#xff0c;从而实现更复杂的逻辑和条件…...

Android 系统签名 keytool-importkeypair

要在 Android 项目中使用系统签名并将 APK 打包时与项目一起打包&#xff0c;可以按照以下步骤操作&#xff1a; 步骤 1&#xff1a;准备系统签名文件 从 Android 系统源码中获取系统签名文件&#xff0c;通常位于 build/target/product/security 目录下&#xff0c;包括 pla…...

安卓漏洞学习(十八):Android加固基本原理

APP加固技术发展历程 APK加固整体思路 加固整体思路&#xff1a;先解压apk文件&#xff0c;取出dex文件&#xff0c;对dex文件进行加密&#xff0c;然后组合壳中的dex文件&#xff08;Android类加载机制&#xff09;&#xff0c;结合之前的apk资源&#xff08;解压apk除dex以外…...

Docker 使用Dockerfile创建镜像

创建并且生成镜像 在当前目录下创建一个名为Dockerfile文件 vi Dockerfile填入下面配置 # 使用 CentOS 作为基础镜像 FROM centos:7# 设置工作目录 WORKDIR /app# 复制项目文件到容器中 COPY bin/ /app/bin/ COPY config/ /app/config/ COPY lib/ /app/lib/ COPY plugin/ /a…...

【Python运维】利用Python实现高效的持续集成与部署(CI/CD)流程

《Python OpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门! 解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 持续集成与部署(CI/CD)是现代软件开发中不可或缺的实践,通过自动化测试、构建和部署流程,显著提高了开发效率与运维质量。本文详细介绍…...

成功!QT 5.15.2编译mysql驱动

首选要说明&#xff0c;5.15与6.7编译驱动是完全不同的。搞错了永远编译不出来。 参考 主要是参考安装QT&#xff0c;安装mysql等。 编译成功&#xff01;QT/6.7.2/Creator编译Windows64 MySQL驱动(MSVC版)_mingw编译qt6.7-CSDN博客 复制mysql的include和lib到一个方便的目…...

安卓NDK视觉开发——手机拍照文档边缘检测实现方法与库封装

一、项目创建 创建NDK项目有两种方式&#xff0c;一种从新创建整个项目&#xff0c;一个在创建好的项目添加NDK接口。 1.创建NDK项目 创建 一个Native C项目&#xff1a; 选择包名、API版本与算法交互的语言&#xff1a; 选择C版本&#xff1a; 创建完之后&#xff0c;可…...

第二届 Sui 游戏峰会将于 3 月 18 日在旧金山举行

3 月中旬&#xff0c;Sui 基金会和 Mysten Labs 将共同举办第二届 Sui 游戏峰会&#xff08;Sui Gaming Summit&#xff09;&#xff0c;这是一个专注于 Sui 游戏平台的 GDC 周边活动。此次峰会将与旧金山的年度游戏开发者大会&#xff08;GDC&#xff0c;Game Developers Conf…...

自动驾驶相关知识学习笔记

一、概要 因为想知道SIL、HIL是什么仿真工具&#xff0c;故而浏览了自动驾驶相关的知识。 资料来源《自动驾驶——人工智能理论与实践》胡波 林青 陈强 著&#xff1b;出版时间&#xff1a;2023年3月 二、图像的分类、分割与检测任务区别 如图所示&#xff0c;这些更高阶的…...

uniapp - 基于uniapp+vue3实现自定义增强版table表格组件体验「兼容H5+小程序+App端」

本文提供增强版table表格组件体验,打造跨端表格的新标杆. uv3-table&#xff1a;一款基于uniappvue3跨端自定义手机端增强版表格组件。支持固定表头/列、边框、斑马纹、单选/多选&#xff0c;自定义表头/表体插槽、左右固定列阴影高亮显示。支持编译兼容H5小程序端App端。 提供…...

新时期下k8s 网络插件calico 安装

1、k8s master节点初始化完毕以后一直处于notreadey状态&#xff0c;一直怀疑是安装有问题或者是初始化有问题&#xff08;当然&#xff0c;如果真有问题要先解决这些问题&#xff09;&#xff0c;经过不断探索才发现是网络插件没有安装导致的&#xff0c;根据建议安装calico插…...

【SQL】COUNT()函数 用法详解

COUNT()函数 COUNT函数用法&#xff1a;COUNT ( [ALL | DISTINCT] column | expression | *) ALL关键字指示统计所有值&#xff0c;而DISTINCT关键字强制函数仅对不同的值进行操作。 默认情况下&#xff0c;使用ALL选项。条件表达式 COUNT()函数中条件表达式加 OR null。例如…...

十一、【ESP32开发全栈指南: TCP通信服务端】

一、TCP与UDP协议对比 1.1 基本特性比较 TCP(传输控制协议)和UDP(用户数据报协议)是两种最常用的传输层协议&#xff0c;它们在ESP32网络编程中都有广泛应用&#xff1a; 连接方式 TCP是面向连接的协议&#xff0c;通信前需要先建立连接(三次握手)UDP是无连接的协议&#xff…...

【envoy】-1.安装与下载源码

1.安装 建议使用ubuntu2004&#xff0c;对glibc有要求。上个ti子更快。 wget -O- https://apt.envoyproxy.io/signing.key | sudo gpg --dearmor -o /etc/apt/keyrings/envoy-keyring.gpg $ echo "deb [arch$(dpkg --print-architecture) signed-by/etc/apt/keyrings/envo…...

Ps:Adobe PDF 预设

Ps菜单&#xff1a;编辑/Adobe PDF 预设 Edit/Adobe PDF Presets 通过“Adobe PDF 预设” Adobe PDF Presets对话框&#xff0c;可以查看 Adobe PDF 预设&#xff0c;了解复杂的 PDF 设置。还可以编辑、新建、删除、载入预设&#xff0c;根据最终用途&#xff08;如高质量打印、…...

.net webapi http参数自定义绑定模型

.NET Web API 中 HTTP 参数自定义绑定模型的深度解析 在 .NET Web API 开发里&#xff0c;常规的参数绑定往往能满足大部分需求。不过&#xff0c;当遇到一些特殊情况时&#xff0c;就需要自定义将 HTTP 参数绑定到 action 特定模型参数了。接下来&#xff0c;我们就深入探讨如…...

【LLM】多智能体系统 Why Do Multi-Agent LLM Systems Fail?

note 构建一个成功的 MAS&#xff0c;不仅仅是提升底层 LLM 的智能那么简单&#xff0c;它更像是在构建一个组织。如果组织结构、沟通协议、权责分配、质量控制流程设计不当&#xff0c;即使每个成员&#xff08;智能体&#xff09;都很“聪明”&#xff0c;整个系统也可能像一…...

使用 Python + SQLAlchemy 创建知识库数据库(SQLite)—— 构建本地知识库系统的基础《一》

&#x1f4da; 使用 Python SQLAlchemy 创建知识库数据库&#xff08;SQLite&#xff09;—— 构建本地知识库系统的基础 &#x1f9e0; 一、前言 随着大模型技术的发展&#xff0c;越来越多的项目需要构建本地知识库系统来支持 RAG&#xff08;Retrieval-Augmented Generat…...

Flask 基础与实战概述

一、Flask 基础知识 什么是 Flask? Flask 是一个基于 Python 的轻量级 Web 框架(微框架)。 特点:核心代码简洁,给予开发者更多选择空间。 与 Django 对比: Django 创建空项目生成多个文件,Flask 仅需一个文件即可实现简单应用(如 "Hello, World!")。 Flask …...

LinkedList、Vector、Set

LinkedList 基本概念 LinkedList 是一个双向链表的实现类&#xff0c;它实现了 List、Deque、Queue 和 Cloneable 接口&#xff0c;底层使用双向链表结构&#xff0c;适合频繁插入和删除操作。 主要特点 有序&#xff0c;可重复。 查询速度较慢&#xff0c;插入/删除速度较…...

六、【ESP32开发全栈指南:深入解析ESP32 IDF中的WiFi AP模式开发】

1. 引言&#xff1a;AP模式的核心价值 ESP32的AP&#xff08;Access Point&#xff09;模式使设备成为独立无线热点&#xff0c;适用于&#xff1a; 设备配网&#xff08;SmartConfig&#xff09;无路由器场景的本地组网数据直采终端&#xff08;传感器集中器&#xff09;临时…...

html表格转换为markdown

文章目录 工具功能亮点1.核心实现解析1. 剪贴板交互2. HTML检测与提取3. 转换规则设计 2. 完整代码 在日常工作中&#xff0c;我们经常遇到需要将网页表格快速转换为Markdown格式的场景。无论是文档编写、知识整理还是数据迁移&#xff0c;手动转换既耗时又容易出错。本文将介绍…...