STM32F103 HAL多實例通用USART驅動 - 高效DMA+RingBuffer方案,量產級工程模板

導言


《STM32F103_LL庫+寄存器學習筆記12.2 - 串口DMA高效收發實戰2:進一步提高串口接收的效率》前陣子完成的LL庫與寄存器版本的代碼,有一個明顯的缺點是不支持多實例化。最近,計劃基于HAL庫系統地梳理一遍bootloader程序開發。在bootloader程序開發項目里,需要用到HAL庫的串口驅動代碼。所以,繼續把代碼優化優化,將多實例化模塊做出來。

bsp_usart_hal 驅動代碼特點總結:

  1. 支持多實例通用管理

    • 設計為USART_Driver_t結構體+接口函數,支持多個USART端口同時獨立驅動,便于單板多串口應用、項目橫向復用、一套代碼多項目。
    • 各實例參數(緩沖區、DMA句柄、UART句柄)解耦,代碼維護簡便。
  2. DMA收發全流程、雙緩沖高效傳輸

    • 接收采用DMA環形模式,支持半傳輸(HT)、全傳輸(TC)、IDLE三類中斷協同搬運,保證任意長度數據不丟包、無粘包。
    • 發送采用DMA塊傳輸,自動調度RingBuffer隊列,避免CPU阻塞。
    • 收發均使用DMA,極大減輕CPU負擔,適用于高帶寬、高實時性場景。
  3. RingBuffer無縫緩存機制

    • 內置收發雙向RingBuffer,自動管理協議包拼接、數據緩沖,簡化上層協議處理。
    • 支持超大緩沖、溢出自動覆蓋或丟棄舊數據,易于移植第三方協議棧。
  4. 健壯的錯誤統計與自恢復機制

    • 內置DMA傳輸錯誤、串口硬件錯誤等統計計數(errorDMATX/errorDMARX/errorRX),便于產線異常監控、后期故障溯源。
    • 檢測到DMA錯誤時,自動執行自恢復:自動重啟DMA、自動清理異常、可定制連續多次異常的告警或自動復位,保障系統長期穩定運行。
  5. 工程化量產導向

    • 代碼結構清晰、注釋標準,適用于量產項目長期維護。
    • CubeMX工程直接集成,無需魔改HAL庫代碼。
    • 支持多串口、多DMA。

測試效果如下,接收與發送都沒有丟包。
在這里插入圖片描述
項目地址:
github: https://github.com/q164129345/MCU_Develop/tree/main/stm32f103_hal_usart_dma_ringbuffer
gitee(國內): https://gitee.com/wallace89/MCU_Develop/tree/main/stm32f103_hal_usart_dma_ringbuffer

一、CubeMX


1.1、Clock Configuration

在這里插入圖片描述

1.2、USART1

在這里插入圖片描述
波特率115200,數據長度8bits,停止位長度1bit。
在這里插入圖片描述
使能USART1全局中斷。
在這里插入圖片描述
USART1_RX的DMA接收模式一定要選擇“Circular”模式,長度選擇Byte(字節) = 8bits。
在這里插入圖片描述
USART1_RX的DMA發送模式一定要選擇“Normal”模式,長度選擇Byte(字節) = 8bits。
在這里插入圖片描述
GPIO Setting的設置如上所示。

二、代碼


2.1、bsp_usart_hal.h

/*** @file    bsp_usart_hal.h* @brief   STM32F1系列 USART + DMA + RingBuffer HAL庫底層驅動接口(多實例、可變緩沖區)* @author  Wallace.zhang* @version 2.0.0* @date    2025-05-23*/
#ifndef __BSP_USART_HAL_H
#define __BSP_USART_HAL_H#ifdef __cplusplus
extern "C" {
#endif#include "main.h"
#include "usart.h"
#include "dma.h"
#include "lwrb/lwrb.h"/*** @brief USART驅動結構體(DMA + RingBuffer + 統計)*/
typedef struct
{volatile uint8_t   txDMABusy;        /**< DMA發送忙標志(1:發送中,0:空閑) */volatile uint64_t  rxMsgCount;       /**< 統計接收字節總數 */volatile uint64_t  txMsgCount;       /**< 統計發送字節總數 */volatile uint16_t  dmaRxLastPos;     /**< DMA接收緩沖區上次處理到的位置 */volatile uint32_t  errorDMATX;       /**< DMA發送錯誤統計 */volatile uint32_t  errorDMARX;       /**< DMA接收錯誤統計 */volatile uint32_t  errorRX;          /**< 串口接收錯誤統計 */DMA_HandleTypeDef   *hdma_rx;        /**< HAL庫的DMA RX句柄 */DMA_HandleTypeDef   *hdma_tx;        /**< HAL庫的DMA TX句柄 */UART_HandleTypeDef  *huart;          /**< HAL庫的UART句柄 *//* RX方向 */uint8_t             *rxDMABuffer;    /**< DMA接收緩沖區 */uint8_t             *rxRBBuffer;     /**< 接收RingBuffer緩存區 */uint16_t            rxBufSize;       /**< DMA接收/RX Ringbuffer緩沖區大小 */lwrb_t              rxRB;            /**< 接收RingBuffer句柄 *//* TX方向 */uint8_t             *txDMABuffer;    /**< DMA發送緩沖區 */uint8_t             *txRBBuffer;     /**< 發送RingBuffer緩存區 */uint16_t            txBufSize;       /**< DMA發送/TX Ringbuffer緩沖區大小 */lwrb_t              txRB;            /**< 發送RingBuffer句柄 */} USART_Driver_t;/*** @brief  阻塞方式發送以 NUL 結尾的字符串*/
void USART_SendString_Blocking(USART_Driver_t* const usart, const char* str);
/*** @brief  USART發送DMA中斷處理函數*/
void USART_DMA_TX_Interrupt_Handler(USART_Driver_t *usart);
/*** @brief  USART接收DMA中斷處理函數*/
void USART_DMA_RX_Interrupt_Handler(USART_Driver_t *usart);
/*** @brief  USART空閑接收中斷處理函數(支持DMA+RingBuffer,適用于多實例)*/
void USART_RX_IDLE_Interrupt_Handler(USART_Driver_t *usart);
/*** @brief  將數據寫入指定USART驅動的發送 RingBuffer中*/
uint8_t USART_Put_TxData_To_Ringbuffer(USART_Driver_t *usart, const void* data, uint16_t len);
/*** @brief  USART模塊定時任務處理函數,建議主循環1ms周期回調*/
void USART_Module_Run(USART_Driver_t *usart);
/*** @brief  獲取USART接收RingBuffer中的可讀字節數*/
uint32_t USART_Get_The_Existing_Amount_Of_Data(USART_Driver_t *usart);
/*** @brief  從USART接收RingBuffer中讀取一個字節數據*/
uint8_t USART_Take_A_Piece_Of_Data(USART_Driver_t *usart, uint8_t* data);
/*** @brief  DMA傳輸錯誤后的自動恢復操作(含錯誤統計)*/
void USART_DMA_Error_Recover(USART_Driver_t *usart, uint8_t dir);
/*** @brief   初始化USART驅動,配置DMA、RingBuffer與中斷*/
void USART_Config(USART_Driver_t *usart,uint8_t *rxDMABuffer, uint8_t *rxRBBuffer, uint16_t rxBufSize,uint8_t *txDMABuffer, uint8_t *txRBBuffer, uint16_t txBufSize);#ifdef __cplusplus
}
#endif#endif /* __BSP_USART_HAL_H */

2.2、bsp_usart_hal.c

/*** @file    bsp_usart_hal.c* @brief   STM32F1系列 USART + DMA + RingBuffer HAL庫底層驅動實現(多實例、可變緩沖區)* @author  Wallace.zhang* @version 2.0.0* @date    2025-05-23*/#include "bsp_usart_hal.h"/*** @brief   阻塞方式發送以NUL結尾字符串(調試用,非DMA)* @param   usart  指向USART驅動結構體的指針* @param   str    指向以'\0'結尾的字符串* @note    通過HAL庫API逐字節發送,底層會輪詢TXE位(USART_SR.TXE)。* @retval  無*/
void USART_SendString_Blocking(USART_Driver_t* usart, const char* str)
{if (!usart || !str) return;HAL_UART_Transmit(usart->huart, (uint8_t*)str, strlen(str), 1000);
}/*** @brief  配置并啟動USART的DMA接收(環形模式)* @param  usart 指向USART驅動結構體的指針* @note   必須保證huart、hdma_rx已通過CubeMX正確初始化*         - 調用本函數會停止原有DMA,然后重新配置DMA并啟動環形接收*         - 使能USART的IDLE中斷,實現突發/不定長幀高效處理* @retval 無*/
static void USART_Received_DMA_Configure(USART_Driver_t *usart)
{if (!usart) return;HAL_DMA_Abort(usart->hdma_rx); //! 先關閉HAL_UART_Receive_DMA(usart->huart, usart->rxDMABuffer, usart->rxBufSize); //! 啟動環形DMA__HAL_UART_ENABLE_IT(usart->huart, UART_IT_IDLE); //! 使能IDLE中斷usart->dmaRxLastPos = 0;
}/*** @brief  啟動DMA方式串口發送* @param  usart 指向USART驅動結構體的指針* @param  data  指向待發送的數據緩沖區* @param  len   待發送的數據字節數* @note   發送前需確保txDMABusy為0,否則應等待前一幀發送完成*         啟動后DMA自動填充USART_DR寄存器,實現高效異步發送* @retval 無*/
static void USART_SendString_DMA(USART_Driver_t *usart, uint8_t *data, uint16_t len)
{if (!usart || !data || len == 0 || len > usart->txBufSize) return;while (usart->txDMABusy); // 等待DMA空閑usart->txDMABusy = 1;HAL_UART_Transmit_DMA(usart->huart, data, len);
}/*** @brief  寫入數據到接收RingBuffer* @param  usart 指向USART驅動結構體的指針* @param  data  指向要寫入的數據緩沖區* @param  len   要寫入的數據長度(單位:字節)* @retval 0  數據成功寫入,無數據丟棄* @retval 1  ringbuffer剩余空間不足,丟棄部分舊數據以容納新數據* @retval 2  數據長度超過ringbuffer總容量,僅保留新數據尾部(全部舊數據被清空)* @retval 3  輸入數據指針為空* @note* - 本函數通過lwrb庫操作ringbuffer。* - 當len > ringbuffer容量時,強行截斷,僅保留最新usart->rxRBBuffer字節。* - 若空間不足,自動調用lwrb_skip()丟棄部分舊數據。*/
static uint8_t Put_Data_Into_Ringbuffer(USART_Driver_t *usart, const void *data, uint16_t len)
{//! 檢查輸入指針是否合法if (!usart || !data) return 3;lwrb_t *rb = &usart->rxRB;uint16_t rb_size = usart->rxBufSize;//! 獲取當前RingBuffer剩余空間lwrb_sz_t free_space = lwrb_get_free(rb);//! 分三種情況處理:長度小于、等于、大于RingBuffer容量uint8_t ret = 0;if (len < rb_size) {//! 數據小于RingBuffer容量if (len <= free_space) {//! 空間充足,直接寫入lwrb_write(rb, data, len);} else {//! 空間不足,需丟棄部分舊數據lwrb_sz_t used = lwrb_get_full(rb);lwrb_sz_t skip_len = len - free_space;if (skip_len > used) {skip_len = used;}lwrb_skip(rb, skip_len); //! 跳過(丟棄)舊數據lwrb_write(rb, data, len);ret = 1;}} else if (len == rb_size) { //! 數據剛好等于RingBuffer容量if (free_space < rb_size) {lwrb_reset(rb); //! 空間不足,重置RingBufferret = 1;}lwrb_write(rb, data, len);} else { //! 數據超過RingBuffer容量,僅保留最后rb_size字節const uint8_t *byte_ptr = (const uint8_t *)data;data = (const void *)(byte_ptr + (len - rb_size));lwrb_reset(rb);lwrb_write(rb, data, rb_size);ret = 2;}return ret;
}/*** @brief  從DMA環形緩沖區搬運新收到的數據到RingBuffer(支持環繞)* @param  usart 指向USART驅動結構體的指針* @note   支持IDLE、DMA HT/TC等多中斷共同調用*         - 本函數計算DMA環形緩沖區的新數據,并搬運到RingBuffer*         - 支持一次性或分段搬運(緩沖區環繞時自動分兩段處理)* @retval 無*/
static void USART_DMA_RX_Copy(USART_Driver_t *usart)
{uint16_t bufsize  = usart->rxBufSize;uint16_t curr_pos = bufsize - __HAL_DMA_GET_COUNTER(usart->hdma_rx);uint16_t last_pos = usart->dmaRxLastPos;if (curr_pos != last_pos) {if (curr_pos > last_pos) {//! 普通情況,未環繞Put_Data_Into_Ringbuffer(usart, usart->rxDMABuffer + last_pos, curr_pos - last_pos);usart->rxMsgCount += (curr_pos - last_pos);} else {//! 環繞,分兩段處理Put_Data_Into_Ringbuffer(usart, usart->rxDMABuffer + last_pos, bufsize - last_pos);Put_Data_Into_Ringbuffer(usart, usart->rxDMABuffer, curr_pos);usart->rxMsgCount += (bufsize - last_pos) + curr_pos;}usart->dmaRxLastPos = curr_pos;}
}/*** @brief  DMA接收搬運環形Buffer(推薦在IDLE、DMA中斷等調用)* @param  usart 指向USART驅動結構體的指針* @retval 無*/
void USART_DMA_RX_Interrupt_Handler(USART_Driver_t *usart)
{if (!usart) return;USART_DMA_RX_Copy(usart);
}/*** @brief  串口IDLE中斷處理(需在USARTx_IRQHandler中調用)* @param  usart 指向USART驅動結構體的指針* @note   檢查并清除IDLE標志,及時觸發DMA搬運* @retval 無*/
void USART_RX_IDLE_Interrupt_Handler(USART_Driver_t *usart)
{if (!usart) return;if (__HAL_UART_GET_FLAG(usart->huart, UART_FLAG_IDLE)) {__HAL_UART_CLEAR_IDLEFLAG(usart->huart);USART_DMA_RX_Copy(usart);}
}/*** @brief  DMA發送完成回調(由用戶在HAL庫TxCpltCallback中調用)* @param  usart 指向USART驅動結構體的指針* @note   一定要調用,否則無法再次DMA發送* @retval 無*/
void USART_DMA_TX_Interrupt_Handler(USART_Driver_t *usart)
{if (!usart) return;usart->txDMABusy = 0;
}/*** @brief  將數據寫入指定USART驅動的發送 RingBuffer 中* @param  usart  指向USART驅動結構體的指針* @param  data   指向要寫入的數據緩沖區* @param  len    要寫入的數據長度(字節)* @retval  0  數據成功寫入,無數據丟棄* @retval  1  ringbuffer 空間不足,丟棄部分舊數據以容納新數據* @retval  2  數據長度超過 ringbuffer 總容量,僅保留最新 TX_BUFFER_SIZE 字節* @retval  3  輸入數據指針為空* @note* - 使用 lwrb 庫操作發送 RingBuffer(usart->txRB)。* - 若 len > ringbuffer 容量,會自動截斷,僅保留最新的數據。* - 若空間不足,將調用 lwrb_skip() 丟棄部分舊數據。*/
uint8_t USART_Put_TxData_To_Ringbuffer(USART_Driver_t *usart, const void* data, uint16_t len)
{if (!usart || !data) return 3; //! 檢查輸入數據指針有效性lwrb_t *rb = &usart->txRB;uint16_t capacity = usart->txBufSize;lwrb_sz_t freeSpace = lwrb_get_free(rb);uint8_t ret = 0;//! 情況1:數據長度小于ringbuffer容量if (len < capacity) {if (len <= freeSpace) {lwrb_write(rb, data, len); //! 剩余空間充足,直接寫入} else {//! 空間不足,需丟棄部分舊數據lwrb_sz_t used = lwrb_get_full(rb);lwrb_sz_t skip_len = len - freeSpace;if (skip_len > used) skip_len = used;lwrb_skip(rb, skip_len);lwrb_write(rb, data, len);ret = 1;}} else if (len == capacity) { //! 情況2:數據長度等于ringbuffer容量if (freeSpace < capacity) { //! 如果ringbuffer已有數據lwrb_reset(rb);ret = 1;}lwrb_write(rb, data, len);} else { //! 情況3:數據長度大于ringbuffer容量,僅保留最后 capacity 字節const uint8_t *ptr = (const uint8_t*)data + (len - capacity);lwrb_reset(rb);lwrb_write(rb, ptr, capacity);ret = 2;}return ret;
}/*** @brief   初始化USART驅動,配置DMA、RingBuffer與中斷* @param   usart         指向USART驅動結構體的指針* @param   rxDMABuffer   DMA接收緩沖區指針* @param   rxRBBuffer    接收RingBuffer緩沖區指針* @param   rxBufSize     接收緩沖區大小* @param   txDMABuffer   DMA發送緩沖區指針* @param   txRBBuffer    發送RingBuffer緩沖區指針* @param   txBufSize     發送緩沖區大小* @retval  無* @note    需先通過CubeMX完成串口、DMA相關硬件配置和句柄賦值*/
void USART_Config(USART_Driver_t *usart,uint8_t *rxDMABuffer, uint8_t *rxRBBuffer, uint16_t rxBufSize,uint8_t *txDMABuffer, uint8_t *txRBBuffer, uint16_t txBufSize)
{if (!usart) return;usart->rxDMABuffer = rxDMABuffer;usart->rxRBBuffer  = rxRBBuffer;usart->rxBufSize   = rxBufSize;lwrb_init(&usart->rxRB, usart->rxRBBuffer, usart->rxBufSize);usart->txDMABuffer = txDMABuffer;usart->txRBBuffer  = txRBBuffer;usart->txBufSize   = txBufSize;lwrb_init(&usart->txRB, usart->txRBBuffer, usart->txBufSize);USART_Received_DMA_Configure(usart); // 初始化DMA RXusart->txDMABusy = 0;usart->dmaRxLastPos = 0;usart->rxMsgCount = 0;usart->txMsgCount = 0;usart->errorDMATX = 0;usart->errorDMARX = 0;usart->errorRX = 0;
}/*** @brief  USART模塊主循環調度函數(DMA + RingBuffer高效收發)* @param  usart 指向USART驅動結構體的指針* @note   建議主循環定時(如1ms)調用*         - 檢查發送RingBuffer是否有待發送數據,且DMA當前空閑*         - 若條件滿足,從發送RingBuffer讀取一段數據到DMA發送緩沖區,并通過DMA啟動異步發送*         - 自動維護已發送數據統計* @retval 無*/
void USART_Module_Run(USART_Driver_t *usart)
{if (!usart) return;uint16_t available = lwrb_get_full(&usart->txRB);if (available && usart->txDMABusy == 0) {uint16_t len = (available > usart->txBufSize) ? usart->txBufSize : available;lwrb_read(&usart->txRB, usart->txDMABuffer, len);usart->txMsgCount += len;USART_SendString_DMA(usart, usart->txDMABuffer, len);}
}/*** @brief  獲取USART接收RingBuffer中的可讀字節數* @param  usart 指向USART驅動結構體的指針* @retval uint32_t 可讀取的數據字節數* @note   通常在主循環或數據解析前調用,用于判斷是否需要讀取數據。*/
uint32_t USART_Get_The_Existing_Amount_Of_Data(USART_Driver_t *usart)
{if (!usart) return 0;return lwrb_get_full(&usart->rxRB);
}/*** @brief  從USART接收RingBuffer中讀取一個字節數據* @param  usart 指向USART驅動結構體的指針* @param  data  指向存放讀取結果的緩沖區指針* @retval 1  讀取成功,有新數據存入 *data* @retval 0  讀取失敗(無數據或data為NULL)* @note   本函數不會阻塞,無數據時直接返回0。*/
uint8_t USART_Take_A_Piece_Of_Data(USART_Driver_t *usart, uint8_t* data)
{if (!usart || !data) return 0;return lwrb_read(&usart->rxRB, data, 1);
}/*** @brief  DMA傳輸錯誤后的自動恢復操作(含錯誤統計)* @param  usart 指向USART驅動結構體* @param  dir   方向:0=RX, 1=TX* @note   檢測到DMA傳輸錯誤(TE)時調用,自動進行統計并恢復*         RX方向會自動重啟DMA,TX方向建議等待主循環調度新發送* @retval 無*/
void USART_DMA_Error_Recover(USART_Driver_t *usart, uint8_t dir)
{if (!usart) return;if (dir == 0) { //! RX方向usart->errorDMARX++; //! DMA接收錯誤計數 */HAL_DMA_Abort(usart->hdma_rx);HAL_UART_Receive_DMA(usart->huart, usart->rxDMABuffer, usart->rxBufSize);//! 可以加入極端情況下的USART復位等} else { //! TX方向usart->errorDMATX++; //! DMA發送錯誤計數 */HAL_DMA_Abort(usart->hdma_tx);//! 一般等待主循環觸發新的DMA發送}//! 可插入報警、日志
}

2.3、stm32f1xx_it.c

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

2.4、main.c

在這里插入圖片描述
緩存分別是DMA緩存與ringbuffer緩存。
在這里插入圖片描述

2.5、編譯代碼、下載代碼

在這里插入圖片描述

三、測試代碼


在這里插入圖片描述
在這里插入圖片描述
如上所示,從成員rxMsgCount與txMsgCount看到,數據在正常收發。errorDMATX、errorDMARX、errorRX一直保持0,證明沒有發生錯誤。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/82101.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/82101.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/82101.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【數據結構】棧和隊列(上)

目錄 一、棧&#xff08;先進后出、后進先出的線性表&#xff09; 1、棧的概念及結構 2、棧的底層結構分析 二、代碼實現 1、定義一個棧 2、棧的初始化 3、入棧 3、增容 4、出棧 5、取棧頂 6、銷毀棧 一、棧&#xff08;先進后出、后進先出的線性表&#xff09; 1、…

Vue 3 官方 Hooks 的用法與實現原理

Vue 3 引入了 Composition API&#xff0c;使得生命周期鉤子&#xff08;hooks&#xff09;在函數式風格中更清晰地表達。本篇文章將從官方 hooks 的使用、實現原理以及自定義 hooks 的結構化思路出發&#xff0c;全面理解 Vue 3 的 hooks 系統。 &#x1f4d8; 1. Vue 3 官方生…

大語言模型 17 - MCP Model Context Protocol 介紹對比分析 基本環境配置

MCP 基本介紹 官方地址&#xff1a; https://modelcontextprotocol.io/introduction “MCP 是一種開放協議&#xff0c;旨在標準化應用程序向大型語言模型&#xff08;LLM&#xff09;提供上下文的方式。可以把 MCP 想象成 AI 應用程序的 USB-C 接口。就像 USB-C 提供了一種…

云原生安全之PaaS:從基礎到實踐的技術指南

??「炎碼工坊」技術彈藥已裝填! 點擊關注 → 解鎖工業級干貨【工具實測|項目避坑|源碼燃燒指南】 云原生安全之PaaS:從基礎到實踐的技術指南 一、基礎概念 PaaS(Platform as a Service)平臺 PaaS是一種云計算服務模型,為開發者提供應用程序的開發、部署和運行環境,涵…

Chrome中http被強轉成https問題

原因&#xff1a;2023年11月1日&#xff0c;chrome發布HTTPS-Upgrades功能&#xff0c;在用戶訪問 http:// 的舊鏈接之后&#xff0c;會自動嘗試跳轉到通過加密的 https:// 協議&#xff0c;訪問該網站。且探測到 https 服務存在也會自動改成 https。 親測兩種方案可行&#x…

Linux 操作文本文件列數據的常用命令

文章目錄 Linux 操作文本文件列數據的常用命令基本列處理命令高級列處理列數據轉換和排序列數據統計和分析 Linux 操作文本文件列數據的常用命令 Linux 提供了多種強大的命令來處理文本文件中的列數據&#xff0c;以下是一些最常用的命令和工具&#xff1a; 基本列處理命令 c…

如何理解線性判別分析(LDA)算法?

在高維數據空間中,特征變量呈指數級增長,信息分布密集且復雜。研究者在面對海量特征時,仿佛置身于一幅結構高度抽象且維度交織的多變量圖景之中,其解析與建模猶如在一幅復雜的數據宇宙圖譜中導航,既需理論框架的指引,也依賴于算法工具的精確刻畫。如何從眾多維度中篩選出…

鴻蒙UI開發——Builder函數的封裝

1、問題引入 我們在開發中可能會遇到這樣一個問題&#xff1a;將一個Builder修飾后的函數用變量或者數組記錄下來&#xff0c;在業務其他地方使用這些Builder函數。 舉個例子&#xff0c;有下面一段代碼&#xff1a; Builderfunction builderElement() {}let builderArr: Fu…

ARM筆記-ARM指令集

第三章 ARM指令集 3.1 ARM指令集簡介 ARM微處理器的ARM指令集 &#xff0c;所有的指令長度都是32位 &#xff0c;并且大多數指令都在一個單獨指令周期內執行。 主要特點&#xff1a; 指令是條件執行的ARM微處理器的指令集是加載/存儲型的在多寄存器操作指令中一次最多可以完成…

Spring Boot接口通用返回值設計與實現最佳實踐

一、核心返回值模型設計&#xff08;增強版&#xff09; package com.chat.common;import com.chat.util.I18nUtil; import com.chat.util.TraceUtil; import lombok.AllArgsConstructor; import lombok.Data; import lombok.Getter;import java.io.Serializable;/*** 功能: 通…

2025年上半年軟件架構師考試回憶版【持續更新】

文章目錄 案例分析1、端AI相對于云AI的優勢2、redis持久化&#xff0c;主從庫3、解釋器架構風格4、知識圖譜5、區塊鏈 論文1、基于事件驅動的模型2、多模型數據庫及其應用3、負載均衡設計方法4、論軟件測試理論及其應用 考試感受 2025年軟件考試架構考試于5月24日如期舉行&…

Windows下編譯Zipios

本文記錄在Windows下編譯Zipios的流程。 注1&#xff1a;文章內容會不定期更新。 零、環境 操作系統Windows 11VS Code1.92.1Git2.34.1Visual StudioVisual Studio Community 2022CMake3.22.1 一、安裝依賴 二、編譯 2.1 下載代碼 git clone https://github.com/Zipios/Zi…

SOC-ESP32S3部分:11-任務創建

飛書文檔https://x509p6c8to.feishu.cn/wiki/EH3owsPahisvl6kL6k3cqaQ3n0g 在我們學習單片機的時候&#xff0c;main函數入口中一般有一個while大循環在不停輪詢&#xff0c;如果我們需要實現多種不同的業務&#xff0c;就需要用到狀態機&#xff0c;根據不同時刻的要求執行不…

[Git] 如何進行版本回退

版本控制系統最重要的能力之一&#xff0c;就是能夠輕松地在項目的不同歷史版本之間切換。有時&#xff0c;你可能發現最近的修改引入了嚴重問題&#xff0c;或者需要回到之前的某個節點重新開始。這時&#xff0c;“版本回退”功能就派上用場了。 版本回退&#xff1a;反方向…

易貝平臺關鍵字搜索技術深度解析

一、核心搜索機制 關鍵詞匹配原理 采用TF-IDF算法計算關鍵詞權重 支持同義詞擴展&#xff08;如"phone"匹配"cellphone"&#xff09; 標題權重 > 副標題 > 商品描述 搜索排序因素 # 搜索權重模擬計算 def calculate_rank(keyword, item): title…

深度剖析 MCP SDK 最新版:Streamable HTTP 模式

好記憶不如爛筆頭&#xff0c;能記下點東西&#xff0c;就記下點&#xff0c;有時間拿出來看看&#xff0c;也會發覺不一樣的感受. 目錄 一、概述 二、快速上手&#xff1a;開啟 Streamable HTTP 服務端開啟 客戶端連接 三、深入兩個核心參數 stateless_http json_resp…

樹莓派開箱上手教程(無需顯示器版)

樹莓派開箱上手教程&#xff08;無需顯示器版&#xff09; 硬件準備 名稱參數電源適配器5V電源適配器&#xff0c;至少需要3A的額定電流&#xff0c;配備USB Type-C輸出接頭microSD卡用來將樹莓派的操作系統安裝到上邊&#xff0c;至少需要8GB容量&#xff0c;一般建議16GB及以…

MySQL強化關鍵_015_存儲過程

目 錄 一、概述 1.說明 2.優點 3.缺點 二、存儲過程的操作 1.創建 2.調用 3.查看 4.刪除 三、變量 1.系統變量 &#xff08;1&#xff09;說明 &#xff08;2&#xff09;查看系統變量 &#xff08;3&#xff09;設置系統變量 2.用戶變量 &#xff08;1&…

動態規劃dp

這里寫目錄標題 動態規劃01背包完全背包多重背包混合背包二維費用的背包分組背包有依賴的背包背包問題求方案數背包問題求具體方案數位 DP狀壓 DP常用例題 動態規劃 01背包 有 n n n 件物品和一個容量為 W W W 的背包&#xff0c;第 i i i 件物品的體積為 w [ i ] w[i] w…

arcgis js統計FeatureLayer的橢球面積、平面面積

1、導入依賴 import FeatureLayer from arcgis/core/layers/FeatureLayer import { geodesicArea, planarArea, simplify } from arcgis/core/geometry/geometryEngine; import { project, load as projectionLoad } from arcgis/core/geometry/projection2、初始化project o…