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

FreeRTOS 消息队列

1. 队列简介

1.1 队列的概念

队列是任务到任务、任务到中断、中断到任务数据交流的一种机制(消息传递)

类似全局变量?假设有一个全局变量a = 0,现有两个任务都在写这个变量 a:

在这里插入图片描述
大家想象一下如果任务 1 运行一次,任务 2 运行一次,理论上 a 等于什么?等于 2。但是大家想象一下,这个 a++ 在 C 语言这里其实它内部是分成很多个操作的,我们来看一下,内部首先就把 a 给读到 cpu 的寄存器 r0 里面,然后再把 r0 进行加一,然后加完之后,再把 r0 这个值给回这个 a 这个地址,这样的话 a 就变成 1 了,如果裸机的话,肯定是没有这种任务1、任务2 去干扰你。
但是 os 的话就存在这种可能了,比如任务 1 执行到第二步这里的时候被更高优先级的任务 2 给打断了,这时候有可能出现什么情况?那么假设一下,首先 a 本来是 0,读到 r0 里面,此时 r0 = r0 + 1 = 1,此时被任务 2 打断,那打断之后代表 r0 还没给到 a;那这时候任务 2 它同样的也是这么一个操作,因为任务 2 的优先级是最高的,所以它完整的执行了这 3 步,这时候 a 它还是 0,因为任务 1 还没有执行到第三步,还没给回 a,所以执行完这 3 步以后,a = 1,然后任务 2 执行完之后又回到任务 1 的第三步,那这时候 r0 它也是 1,1 它又赋值给 a,这时候它们运行的结果 a 就等于 1。
那这样的话执行了两个任务,都执行了一次,但是它实际的效果竟然 a = 1,这样就造成一个数据的受损。

全局变量的弊端:数据无保护,导致数据不安全,当多个任务同时对该变量操作时,数据易受损。

使用队列的情况如下:
在这里插入图片描述

本质:临界区->关中断->关闭优先级最低的 PendSV 中断->关闭任务调度。

队列的优点:读写队列做好了保护,防止多任务同时访问冲突;我们只需要直接调用API函数即可,简单易用!

FreeRTOS基于队列, 实现了多种功能,其中包括队列集、互斥信号量、计数型信号量、二值信号量、 递归互斥信号量,因此很有必要深入了解 FreeRTOS 的队列 。

1.2 队列的特征

在队列中可以存储数量有限、大小固定的数据。队列中的每一个数据叫做“队列项目”,队列能够存储“队列项目”的最大数量称为队列的长度。

类似于数组。

在这里插入图片描述

注意:在创建队列时,就要指定队列长度以及队列项目的大小!

FreeRTOS 队列特点

  1. 数据入队出队方式:队列通常采用 “先进先出”(FIFO) 的数据存储缓冲机制,即先入队的数据会先从队列中被读取,FreeRTOS中也可以配置为 “后进先出”(LIFO) 方式;
  2. 数据传递方式。FreeRTOS中队列采用实际值传递,即将数据拷贝到队列中进行传递。FreeRTOS采用拷贝数据传递,也可以传递指针,所以在传递较大的数据的时候采用指针传递。(像 ucos 是指针传递,把地址给写进去)

优点:互不干扰。
缺点:耗时比较长。

  1. 多任务访问。队列不属于某个任务,任何任务和中断都可以向队列发送/读取消息。
  2. 出队、入队阻塞。当任务向一个队列发送消息时,假设此时当队列已满无法入队,这时候就可以指定一个阻塞时间。
  1. 若阻塞时间为 0 :直接返回不会等待;
  2. 若阻塞时间为 0~port_MAX_DELAY :等待设定的阻塞时间,若在该时间内还无法入队,超时后直接返回不再等待;
  3. 若阻塞时间为 port_MAX_DELAY :死等,一直等到可以入队为止。出队阻塞与入队阻塞类似;
  • 入队阻塞:
    在这里插入图片描述

队列满了,此时写不进去数据;
① 将该任务的状态列表项挂载在 pxDelayedTaskList(阻塞列表);
② 将该任务的事件列表项挂载在 xTasksWaitingToSend(等待发送列表);

  • 出队阻塞:
    在这里插入图片描述
    队列为空,此时读取不了数据;
    ①将该任务的状态列表项挂载在 pxDelayedTaskList(阻塞列表);
    ②将该任务的事件列表项挂载在 xTasksWaitingToReceive(等待接收列表);

问题:当多个任务写入消息给一个“满队列”时,这些任务都会进入阻塞状态,也就是说有多个任务在等待同一个队列的空间。那当队列中有空间时,哪个任务会进入就绪态?

答:

  1. 优先级最高的任务
  2. 如果大家的优先级相同,那等待时间最久的任务会进入就绪态

1.3 队列基本操作过程

在这里插入图片描述
在这里插入图片描述
这时候这个 20 它会移到队列头部。

2. 队列结构体介绍

队列实际它的内存是分为两部分,第一个就是存放结构体的内存,接着是队列里面的队列项,它用来存放数据的,我们写入数据给队列就写入到队列项里面了。

typedef struct QueueDefinition 
{int8_t * pcHead							/* 存储区域的起始地址(队列项的起始地址) */int8_t * pcWriteTo;        				/* 下一个写入的位置 */union									/* 当把这个结构体用作不同的功能的时候,联合体的作用是不一样的 */{QueuePointers_t     xQueue; 		/* 当用作队列的时候,就使用的上面这个 */SemaphoreData_t  xSemaphore; 		/* 当用作互斥信号量的时候,就使用的下面这个 */} u ;List_t xTasksWaitingToSend; 			/* 等待发送列表 */List_t xTasksWaitingToReceive;			/* 等待接收列表 */volatile UBaseType_t uxMessagesWaiting; /* 非空闲队列项目的数量 */UBaseType_t uxLength;					/* 队列长度 */UBaseType_t uxItemSize;                 /* 队列项目的大小 */volatile int8_t cRxLock; 				/* 读取上锁计数器 */volatile int8_t cTxLock;				/* 写入上锁计数器 *//* 其他的一些条件编译 */
} xQUEUE;

上锁计数器:当锁住队列的时候,此时还是可以正常读写队列的,只不过操作不了它的等待发送和等待接收这两个列表;当解锁的时候,才会去操作这两个列表。那这个就叫队列锁。

当用于队列使用时:

typedef struct QueuePointers
{int8_t * pcTail; 					/* 存储区的结束地址 */int8_t * pcReadFrom;				/* 最后一个读取队列的地址 */
} QueuePointers_t;

当用于互斥信号量和递归互斥信号量时 :

typedef struct SemaphoreData
{TaskHandle_t xMutexHolder;			/* 互斥信号量持有者 */UBaseType_t uxRecursiveCallCount;	/* 递归互斥信号量的获取计数器 */
} SemaphoreData_t;

队列结构体整体示意图:

在这里插入图片描述

3. 队列相关 API 函数介绍

使用队列的主要流程:创建队列->写队列->读队列。

3.1 创建队列

创建队列相关API函数介绍:

函数描述
xQueueCreate()动态方式创建队列
xQueueCreateStatic()静态方式创建队列

动态和静态创建队列之间的区别:

  • 动态:队列所需的内存空间由 FreeRTOS 从 FreeRTOS 管理的堆中自动分配。
  • 静态:创建需要用户自行分配内存。

3.1.1 动态创建队列(常用)

#define	xQueueCreate(  uxQueueLength,   uxItemSize  )						xQueueGenericCreate( ( uxQueueLength ), ( uxItemSize ), (queueQUEUE_TYPE_BASE ))

此函数用于使用动态方式创建队列,队列所需的内存空间由 FreeRTOS 从 FreeRTOS 管理的堆中自动分配 。

形参描述
uxQueueLength队列长度
uxItemSize队列项目的大小
返回值描述
NULL队列创建失败
其他值队列创建成功,返回队列句柄

前面说 FreeRTOS 基于队列实现了多种功能,每一种功能对应一种队列类型,队列类型的 queue.h 文件中有定义:

#define queueQUEUE_TYPE_BASE                  	( ( uint8_t ) 0U )	/* 队列 */
#define queueQUEUE_TYPE_SET                  	( ( uint8_t ) 0U )	/* 队列集 */
#define queueQUEUE_TYPE_MUTEX                 	( ( uint8_t ) 1U )	/* 互斥信号量 */
#define queueQUEUE_TYPE_COUNTING_SEMAPHORE    	( ( uint8_t ) 2U )	/* 计数型信号量 */
#define queueQUEUE_TYPE_BINARY_SEMAPHORE     	( ( uint8_t ) 3U )	/* 二值信号量 */
#define queueQUEUE_TYPE_RECURSIVE_MUTEX       	( ( uint8_t ) 4U )	/* 递归互斥信号量 */ ```

3.2 写队列

往队列写入消息API函数:

函数(任务级+中断级)描述
xQueueSend()往队列的尾部写入消息
xQueueSendToBack()同 xQueueSend()
xQueueSendToFront()往队列的头部写入消息
xQueueOverwrite()覆写队列消息(只用于队列长度为 1 的情况)
xQueueSendFromISR()在中断中往队列的尾部写入消息
xQueueSendToBackFromISR()同 xQueueSendFromISR()
xQueueSendToFrontFromISR()在中断中往队列的头部写入消息
xQueueOverwriteFromISR()在中断中覆写队列消息(只用于队列长度为 1 的情况)

队列写入消息

#define	xQueueSend(  xQueue,   pvItemToQueue,   xTicksToWait  )xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK )
#define	xQueueSendToBack(  xQueue,   pvItemToQueue,   xTicksToWait  )xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK )
#define	xQueueSendToFront(  xQueue,   pvItemToQueue,   xTicksToWait  )xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_FRONT )
#define	xQueueOverwrite(  xQueue,   pvItemToQueue  )xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), 0, queueOVERWRITE )

可以看到这几个写入函数调用的是同一个函数 xQueueGenericSend(),只是指定了不同的写入位置!

覆写:队列长度为 1,只有一个队列项目,比如队列里有数据了,那覆写就是不管队列中有没有数据,都会再写进去覆盖,就是永远是写的进去的,所以是不会阻塞的,所以它的默认阻塞时间是 0,就直接跳过,直接继续写。
其他像尾部写入、头部写入,那这些它们都是会阻塞的,它们都是有一个阻塞时间的设置的,如果队列满了之后,它是写不进去的。那这个是覆写方式与其他方式它们之间的一个区别。

队列一共有 3 种写入位置 :

#define queueSEND_TO_BACK               ( ( BaseType_t ) 0 )		/* 写入队列尾部 */
#define queueSEND_TO_FRONT              ( ( BaseType_t ) 1 )		/* 写入队列头部 */
#define queueOVERWRITE                  ( ( BaseType_t ) 2 )		/* 覆写队列 */

注意:覆写方式写入队列,只有在队列的队列长度为 1 时,才能够使用

往队列写入消息函数入口参数解析:

BaseType_t	xQueueGenericSend(QueueHandle_t 	xQueue,const void * const 	pvItemToQueue,TickType_t 	xTicksToWait,const BaseType_t 	xCopyPosition); 
形参描述
xQueue待写入的队列
pvItemToQueue待写入消息
xTicksToWait阻塞超时时间
xCopyPosition写入的位置
返回值描述
pdTRUE队列写入成功
errQUEUE_FULL队列写入失败

3.3 读队列

从队列读取消息API函数:

函数(任务级+中断级)描述
xQueueReceive()从队列头部读取消息,并删除消息
xQueuePeek()从队列头部读取消息
xQueueReceiveFromISR()在中断中从队列头部读取消息,并删除消息
xQueuePeekFromISR()在中断中从队列头部读取消息
BaseType_t    xQueueReceive( QueueHandle_t   xQueue,  void *   const pvBuffer,  TickType_t   xTicksToWait )

此函数用于在任务中,从队列中读取消息,并且消息读取成功后,会将消息从队列中移除。

形参描述
xQueue待读取的队列
pvBuffer信息读取缓冲区
xTicksToWait阻塞超时时间
返回值描述
pdTRUE读取成功
pdFALSE读取失败
BaseType_t   xQueuePeek( QueueHandle_t   xQueue,   void * const   pvBuffer,   TickType_t   xTicksToWait )

此函数用于在任务中,从队列中读取消息, 但与函数 xQueueReceive()不同,此函数在成功读取消息后,并不会移除已读取的消息!

形参描述
xQueue待读取的队列
pvBuffer信息读取缓冲区
xTicksToWait阻塞超时时间
返回值描述
pdTRUE读取成功
pdFALSE读取失败

4. 队列操作实验

实验目的:学习 FreeRTOS 的队列相关API函数的使用 ,实现队列的入队和出队操作。
实验设计:将设计四个任务:start_task、task1、task2、task3

四个任务的功能如下:
start_task:用来创建task1和task2以及task3任务
task1:当按键 key0 或 key1 按下,将键值拷贝到队列 key_queue(入队);当按键 key_up 按下,将传输大数据,这里拷贝大数据的地址到队列 big_date_queue 中。
task2:读取队列 key_queue 中的消息(出队),打印出接收到的键值。
task3:从队列 big_date_queue 读取大数据地址,通过地址访问大数据。

4.1 创建队列

#include "queue.h"QueueHandle_t key_queue;        /* 小数据句柄 */
QueueHandle_t big_date_queue;   /* 大数据句柄 */
char buff[100] = {"我是一个大数组,大大的数组 124214 uhsidhaksjhdklsadhsaklj"};
/*** @brief       FreeRTOS例程入口函数* @param       无* @retval      无*/
void freertos_demo(void)
{    /* 队列的创建 */key_queue = xQueueCreate( 2, sizeof(uint8_t) );if(key_queue != NULL){printf("key_queue队列创建成功!!\r\n");}else printf("key_queue队列创建失败!!\r\n");big_date_queue = xQueueCreate( 1, sizeof(char *) );if(big_date_queue != NULL){printf("big_date_queue队列创建成功!!\r\n");}else printf("big_date_queue队列创建失败!!\r\n");xTaskCreate((TaskFunction_t         )   start_task,(char *                 )   "start_task",(configSTACK_DEPTH_TYPE )   START_TASK_STACK_SIZE,(void *                 )   NULL,(UBaseType_t            )   START_TASK_PRIO,(TaskHandle_t *         )   &start_task_handler );vTaskStartScheduler();
}

4.2 任务函数实现

/* 任务一,实现入队 */
void task1( void * pvParameters )
{uint8_t key = 0;char * buf;buf = buff; 														/* buf = &buff[0] */BaseType_t   err = 0;while(1) {key = key_scan(0);if(key == KEY0_PRES || key == KEY1_PRES){err = xQueueSend( key_queue, &key, portMAX_DELAY );			/* 写入队列、死等 */if(err != pdTRUE){printf("key_queue队列发送失败\r\n");}}else if(key == WKUP_PRES){err = xQueueSend( big_date_queue, &buf, portMAX_DELAY );	/* 写入队列、死等 */if(err != pdTRUE){printf("key_queue队列发送失败\r\n");}}vTaskDelay(10);}
}/* 任务二,小数据出队 */
void task2( void * pvParameters )
{uint8_t key = 0;BaseType_t err = 0;while(1){err = xQueueReceive(key_queue, &key, portMAX_DELAY);if(err != pdTRUE){printf("key_queue队列读取失败\r\n");}else {printf("key_queue读取队列成功,数据:%d\r\n",key);}}
}/* 任务三,大数据出队 */
void task3( void * pvParameters )
{char * buf;BaseType_t err = 0;while(1){err = xQueueReceive(big_date_queue, &buf, portMAX_DELAY);if(err != pdTRUE){printf("big_date_queue队列读取失败\r\n");}else {printf("数据:%s\r\n",buf);}}
}

5. 队列相关API函数解析

  • 队列的创建API函数:xQueueCreate( )
  • 往队列写入数据API函数(入队):xQueueSend( )
  • 从队列读取数据API函数(出队): xQueueReceive( )

更多的队列相关API函数讲解可以查看《FreeRTOS开发指南》第十三章—队列

相关文章:

FreeRTOS 消息队列

1. 队列简介 1.1 队列的概念 队列是任务到任务、任务到中断、中断到任务数据交流的一种机制(消息传递) 类似全局变量?假设有一个全局变量a 0,现有两个任务都在写这个变量 a: 大家想象一下如果任务 1 运行一次&#…...

如何在Python中实现列表推导式?并给出一个例子

如何在Python中实现列表推导式?并给出一个例子 Python的列表推导式(List Comprehension)是一种强大且简洁的创建列表的方法。它允许我们在一行代码中完成循环和条件判断,从而生成所需的列表。列表推导式不仅提高了代码的可读性&a…...

Flask中的Blueprints:模块化和组织大型Web应用【第142篇—Web应用】

👽发现宝藏 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。 Flask中的Blueprints:模块化和组织大型Web应用 在构建大型Web应用时&#xff0…...

如何通过idea搭建一个SpringBoot的Web项目(最基础版)

通过idea搭建一个SpringBoot的Web项目 文章目录 通过idea搭建一个SpringBoot的Web项目一、打开idea,找到 create new project二、创建方式三、配置项目依赖四、新建项目模块五、总结 一、打开idea,找到 create new project 方式1 方式2 二、创建方式 新…...

Python和FastAPI语义分析和文本图像

要点 使用FastAPI开发RESTful API,创建端点,自定义响应,结构化多路由。Pydantic数据验证库数据建模,创建依赖项注入。开发数据库和对象关系映射,SQLAlchemy,Tortoise ORM,MongoDB。建立权限和安…...

centos系统ssh7.4升级9.6

编译安装 OpenSSL 下载 OpenSSL 源代码: wget https://www.openssl.org/source/openssl-1.1.1w.tar.gz这个命令从 OpenSSL 的官方网站下载指定版本(1.1.1w)的源代码压缩包。 解压源代码: tar zxvf openssl-1.1.1w.tar.gz使用 tar…...

excel所有知识点

1要加双引号 工作表(.xlsx) 单击右键→插入,删除,移动、重命名、复制、设置标签颜色,选定全部工作表 工作表的移动:两个表打开→右键→移动(如果右键是灰色的,可能是保护工作表了&#xff09…...

显卡基础知识及元器件原理分析

显卡应该算是是目前最为火热的研发方向了,其中的明星公司当属英伟达。 当地时间8月23日,英伟达发布截至7月30日的2024财年第二财季财报,营收和利润成倍增长,均超市场预期。 财报显示,第二财季英伟达营收为135.07 亿美…...

Spark Rebalance hint的倾斜的处理(OptimizeSkewInRebalancePartitions)

背景 本文基于Spark 3.5.0 目前公司在做小文件合并的时候用到了 Spark Rebalance 这个算子,这个算子的主要作用是在AQE阶段的最后写文件的阶段进行小文件的合并,使得最后落盘的文件不会太大也不会太小,从而达到小文件合并的作用,…...

Vue 3中实现基于角色的权限认证实现思路

一、基于角色的权限认证主要步骤 在Vue 3中实现基于角色的权限认证通常涉及以下几个主要步骤: 定义角色和权限:首先需要在后端服务定义不同的角色和它们对应的权限。权限可以是对特定资源的访问权限,比如读取、写入、修改等。用户认证&#…...

Visual Studio 2022进行文件差异比较

前言 Visual Studio 2022在版本17.7.4中发布在解决方案资源管理器中比较文件的功能,通过使用此功能,可以轻松地查看两个文件之间的差异,包括添加、删除和修改的代码行。可以逐行查看差异,并根据需要手动调整和编辑文件内容以进行…...

1.2 编译型语言和解释型语言的区别

编译型语言和解释型语言的区别 通过高级语言编写的源码,我们能够轻松理解,但对于计算机来说,它只认识二进制指令,源码就是天书,根本无法识别。源码要想执行,必须先转换成二进制指令。 所谓二进制指令&…...

C语言-常量

什么是常量? 答:常量是在程序执行过程中,其值不发生改变的量,常量分为直接常量和符号常量两种。 其中直接常量又可以分为整型常量、实型常量、字符型常量、字符串常量。 直接常量 1.整型常量 整型常量即整数,包括正整数,负整数和0。c语言中常量可以用八进制,十进制和十六…...

开源的OCR工具基本使用:PaddleOCR/Tesseract/CnOCR

前言 因项目需要,调研了一下目前市面上一些开源的OCR工具,支持本地部署,非调用API,主要有PaddleOCR/CnOCR/chinese_lite OCR/EasyOCR/Tesseract/chineseocr/mmocr这几款产品。 本文主要尝试了EasyOCR/CnOCR/Tesseract/PaddleOCR这…...

vue3实现输入框短信验证码功能---全网始祖

组件功能分析 1.按键删除,清空当前input,并跳转prevInput & 获取焦点,按键delete,清空当前input,并跳转nextInput & 获取焦点。按键Home/End键,焦点跳转first/最后一个input输入框。ArrowLeft/ArrowRight键点击…...

[C#]winformYOLO区域检测任意形状区域绘制射线算法实现

【简单介绍】 Winform OpenCVSharp YOLO区域检测与任意形状区域射线绘制算法实现 在现代安全监控系统中,区域检测是一项至关重要的功能。通过使用Winform结合OpenCVSharp库,并结合YOLO(You Only Look Once)算法,我们…...

个人网站制作 Part 14 添加网站分析工具 | Web开发项目

文章目录 👩‍💻 基础Web开发练手项目系列:个人网站制作🚀 添加网站分析工具🔨使用Google Analytics🔧步骤 1: 注册Google Analytics账户🔧步骤 2: 获取跟踪代码 🔨使用Vue.js&#…...

数据按设定单位(分辨率)划分的方法

1. 问题描述 需要将使用公式计算后的float数值换算到固定间隔数轴的对应位置上的数据,比如2.186这个数据,将该数据换算到以0.25为间隔的数轴上,换算后是2.0,还是2.25呢?该方法就是解决这个问题。 2. 方法 输入&…...

Ubuntu 搭建gitlab服务器,及使用repo管理

一、GitLab安装与配置 GitLab 是一个用于仓库管理系统的开源项目,使用Git作为代码管理工具,并在此基础上搭建起来的Web服务。 1、安装Ubuntu系统(这个教程很多,就不展开了)。 2、安装gitlab社区版本,有需…...

QT(19)-QNetworkRequest

attribute(QNetworkRequest::Attribute code, const QVariant &defaultValue QVariant()) const 获取指定的请求属性。如果该属性未设置,则返回默认值。 hasRawHeader(const QByteArray &headerName) const 检查是否存在指定名称的原始请求头。 header(Q…...

基于大模型的 UI 自动化系统

基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...

ES6从入门到精通:前言

ES6简介 ES6(ECMAScript 2015)是JavaScript语言的重大更新,引入了许多新特性,包括语法糖、新数据类型、模块化支持等,显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var&#xf…...

java_网络服务相关_gateway_nacos_feign区别联系

1. spring-cloud-starter-gateway 作用:作为微服务架构的网关,统一入口,处理所有外部请求。 核心能力: 路由转发(基于路径、服务名等)过滤器(鉴权、限流、日志、Header 处理)支持负…...

进程地址空间(比特课总结)

一、进程地址空间 1. 环境变量 1 )⽤户级环境变量与系统级环境变量 全局属性:环境变量具有全局属性,会被⼦进程继承。例如当bash启动⼦进程时,环 境变量会⾃动传递给⼦进程。 本地变量限制:本地变量只在当前进程(ba…...

mongodb源码分析session执行handleRequest命令find过程

mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程,并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令,把数据流转换成Message,状态转变流程是:State::Created 》 St…...

【第二十一章 SDIO接口(SDIO)】

第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...

Java - Mysql数据类型对应

Mysql数据类型java数据类型备注整型INT/INTEGERint / java.lang.Integer–BIGINTlong/java.lang.Long–––浮点型FLOATfloat/java.lang.FloatDOUBLEdouble/java.lang.Double–DECIMAL/NUMERICjava.math.BigDecimal字符串型CHARjava.lang.String固定长度字符串VARCHARjava.lang…...

第25节 Node.js 断言测试

Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...

Module Federation 和 Native Federation 的比较

前言 Module Federation 是 Webpack 5 引入的微前端架构方案,允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...

DBAPI如何优雅的获取单条数据

API如何优雅的获取单条数据 案例一 对于查询类API,查询的是单条数据,比如根据主键ID查询用户信息,sql如下: select id, name, age from user where id #{id}API默认返回的数据格式是多条的,如下: {&qu…...