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

超完整Docker学习记录,Docker常用命令详解
前言 关于国内拉取不到docker镜像的问题,可以利用Github Action将需要的镜像转存到阿里云私有仓库,然后再通过阿里云私有仓库去拉取就可以了。 参考项目地址:使用Github Action将国外的Docker镜像转存到阿里云私有仓库 一、Docker简介 Do…...
C++ 入门第26天:文件与流操作基础
往期回顾: C 入门第23天:Lambda 表达式与标准库算法入门-CSDN博客 C 入门第24天:C11 多线程基础-CSDN博客 C 入门第25天:线程池(Thread Pool)基础-CSDN博客 C 入门第26天:文件与流操作基础 前言…...
使用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文件,并读取其中的数据 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实现时钟样式,效果如下: 一、html代码如下: <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 (类) 2.2 prefab 是一个文件 2.3 prefab可以导出 3 创建prefab variant (子类) 3.1 除了创建多个独立的prefab, 还可以创建 prefab variant 3.2 他…...

基于Thinkphp6+uniapp的陪玩陪聊软件开发方案分析
使用uni-app框架进行前端开发。uni-app是一个使用Vue.js开发所有前端应用的框架,支持一次编写,多端发布,包括APP、小程序、H5等。 使用Thinkphp6框架进行后端开发。Thinkphp6是一个轻量级、高性能、面向对象的PHP开发框架,具有易…...
MySQL - 子查询和相关子查询详解
在SQL中,子查询(Subquery)和相关子查询(Correlated Subquery)是非常强大且灵活的工具,可以用于执行复杂的数据检索和操作。它们允许我们在一个查询中嵌套另一个查询,从而实现更复杂的逻辑和条件…...
Android 系统签名 keytool-importkeypair
要在 Android 项目中使用系统签名并将 APK 打包时与项目一起打包,可以按照以下步骤操作: 步骤 1:准备系统签名文件 从 Android 系统源码中获取系统签名文件,通常位于 build/target/product/security 目录下,包括 pla…...

安卓漏洞学习(十八):Android加固基本原理
APP加固技术发展历程 APK加固整体思路 加固整体思路:先解压apk文件,取出dex文件,对dex文件进行加密,然后组合壳中的dex文件(Android类加载机制),结合之前的apk资源(解压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驱动
首选要说明,5.15与6.7编译驱动是完全不同的。搞错了永远编译不出来。 参考 主要是参考安装QT,安装mysql等。 编译成功!QT/6.7.2/Creator编译Windows64 MySQL驱动(MSVC版)_mingw编译qt6.7-CSDN博客 复制mysql的include和lib到一个方便的目…...

安卓NDK视觉开发——手机拍照文档边缘检测实现方法与库封装
一、项目创建 创建NDK项目有两种方式,一种从新创建整个项目,一个在创建好的项目添加NDK接口。 1.创建NDK项目 创建 一个Native C项目: 选择包名、API版本与算法交互的语言: 选择C版本: 创建完之后,可…...

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

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

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

新时期下k8s 网络插件calico 安装
1、k8s master节点初始化完毕以后一直处于notreadey状态,一直怀疑是安装有问题或者是初始化有问题(当然,如果真有问题要先解决这些问题),经过不断探索才发现是网络插件没有安装导致的,根据建议安装calico插…...
【SQL】COUNT()函数 用法详解
COUNT()函数 COUNT函数用法:COUNT ( [ALL | DISTINCT] column | expression | *) ALL关键字指示统计所有值,而DISTINCT关键字强制函数仅对不同的值进行操作。 默认情况下,使用ALL选项。条件表达式 COUNT()函数中条件表达式加 OR null。例如…...
十一、【ESP32开发全栈指南: TCP通信服务端】
一、TCP与UDP协议对比 1.1 基本特性比较 TCP(传输控制协议)和UDP(用户数据报协议)是两种最常用的传输层协议,它们在ESP32网络编程中都有广泛应用: 连接方式 TCP是面向连接的协议,通信前需要先建立连接(三次握手)UDP是无连接的协议ÿ…...
【envoy】-1.安装与下载源码
1.安装 建议使用ubuntu2004,对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菜单:编辑/Adobe PDF 预设 Edit/Adobe PDF Presets 通过“Adobe PDF 预设” Adobe PDF Presets对话框,可以查看 Adobe PDF 预设,了解复杂的 PDF 设置。还可以编辑、新建、删除、载入预设,根据最终用途(如高质量打印、…...
.net webapi http参数自定义绑定模型
.NET Web API 中 HTTP 参数自定义绑定模型的深度解析 在 .NET Web API 开发里,常规的参数绑定往往能满足大部分需求。不过,当遇到一些特殊情况时,就需要自定义将 HTTP 参数绑定到 action 特定模型参数了。接下来,我们就深入探讨如…...

【LLM】多智能体系统 Why Do Multi-Agent LLM Systems Fail?
note 构建一个成功的 MAS,不仅仅是提升底层 LLM 的智能那么简单,它更像是在构建一个组织。如果组织结构、沟通协议、权责分配、质量控制流程设计不当,即使每个成员(智能体)都很“聪明”,整个系统也可能像一…...
使用 Python + SQLAlchemy 创建知识库数据库(SQLite)—— 构建本地知识库系统的基础《一》
📚 使用 Python SQLAlchemy 创建知识库数据库(SQLite)—— 构建本地知识库系统的基础 🧠 一、前言 随着大模型技术的发展,越来越多的项目需要构建本地知识库系统来支持 RAG(Retrieval-Augmented Generat…...
Flask 基础与实战概述
一、Flask 基础知识 什么是 Flask? Flask 是一个基于 Python 的轻量级 Web 框架(微框架)。 特点:核心代码简洁,给予开发者更多选择空间。 与 Django 对比: Django 创建空项目生成多个文件,Flask 仅需一个文件即可实现简单应用(如 "Hello, World!")。 Flask …...
LinkedList、Vector、Set
LinkedList 基本概念 LinkedList 是一个双向链表的实现类,它实现了 List、Deque、Queue 和 Cloneable 接口,底层使用双向链表结构,适合频繁插入和删除操作。 主要特点 有序,可重复。 查询速度较慢,插入/删除速度较…...
六、【ESP32开发全栈指南:深入解析ESP32 IDF中的WiFi AP模式开发】
1. 引言:AP模式的核心价值 ESP32的AP(Access Point)模式使设备成为独立无线热点,适用于: 设备配网(SmartConfig)无路由器场景的本地组网数据直采终端(传感器集中器)临时…...
html表格转换为markdown
文章目录 工具功能亮点1.核心实现解析1. 剪贴板交互2. HTML检测与提取3. 转换规则设计 2. 完整代码 在日常工作中,我们经常遇到需要将网页表格快速转换为Markdown格式的场景。无论是文档编写、知识整理还是数据迁移,手动转换既耗时又容易出错。本文将介绍…...