細說STM32單片機FreeRTOS消息緩沖區及其應用實例

目錄

一、消息緩沖區功能概述

二、消息緩沖區操作相關函數

1、相關函數概述

2、部分函數詳解

(1)創建消息緩沖區

(2)寫入消息

(3)讀取消息

(4)消息緩沖區狀態查詢

三、消息緩沖區使用示例

1、示例功能與CubeMX項目設置

(1)RCC、SYS、Code Generator、USART3、TIM6

(2)RTC的設置

(3)FreeRTOS的設置

(4)NVIC

2、程序功能實現

(1)主程序

(2)FreeRTOS對象初始化

(3)RTC的喚醒中斷

(4)任務Task_Show的功能

3、運行調試


一、消息緩沖區功能概述

????????消息緩沖區(message buffer)是基于流緩沖區實現的,也就是它的實現使用了流緩沖區的技術,如同信號量是基于隊列實現的。與流緩沖區的差異在于:消息緩沖區傳輸的是可變長度的消息,如10字節、20字節或35字節的消息。寫入者向消息緩沖區寫入一個10字節的消息,讀取者也必須以10字節的消息讀出,而不是像流緩沖區那樣,按字節流讀出。

????????每個消息都有一個消息頭,就是消息數據的字節數。在STM32 MCU上,消息頭就是一個uint32_t類型的整數。消息頭的寫入和讀取是由FreeRTOS的API函數自動處理的,例如,向消息緩沖區寫入一個長度為20字節的消息,實際占用空間是24字節。

????????消息緩沖區沒有觸發水平,寫入和讀取都是以一條消息為單位的,操作要么成功,要么失敗。

????????消息緩沖區的其他特性與流緩沖區一樣。例如:在只有一個寫入者和一個讀取者的情況下,可以安全操作消息緩沖區;如果有多個寫入者或多個讀取者,讀寫消息緩沖區的代碼必須在臨界代碼段內,且等待時間必須設置為0。

二、消息緩沖區操作相關函數

1、相關函數概述

????????消息緩沖區相關函數的頭文件message_buffer.h,源程序都在文件stream_buffer.c里,因為消息緩沖區是基于流緩沖區實現的,要在程序中使用消息緩沖區,需包含頭文件message_buffer.h。

分組

函數

功能

創建


刪除

xMessageBufferCreate()

創建一個消息緩沖區,只需設置緩沖區大小

xMessageBufferCreateStatic()

創建一個消息緩沖區,靜態分配內存

vMessageBufferDelete()

刪除一個消息緩沖區

xMessageBufferReset()

復位一個消息緩沖區,清空數據。只有沒有任務在阻塞狀態下讀或寫消息緩沖區時,才可以復位消息緩沖區

寫入

xMessageBufferSend()

向消息緩沖區發送一個消息

xMessageBufferSendFromISR()

xMessageBufferSend()的ISR版本

讀取

xMessageBufferReceive()

從消息緩沖區接收一條消息

xMessageBufferReceiveFromISR()

xMessageBufferReceive()的ISR版本

狀態

查詢

xMessageBufferIsEmpty()

查詢消息緩沖區是否為空,返回值pdTRUE表示無任何消息

xMessageBufferIsFull()

查詢消息緩沖區是否滿了,返回值pdTRUE表示不能
再寫入任何消息

xMessageBufferSpacesAvailable()

查詢消息緩沖區的剩余存儲空間

????????與流緩沖區不同的是:消息緩沖區無須設置觸發水平,在寫入或讀取消息超時的時候,實際寫入或讀取的數據字節數為0,不會只寫入或讀取部分數據。

2、部分函數詳解

(1)創建消息緩沖區

????????用于創建消息緩沖區的函數是xMessageBufferCreate(),這是個宏函數,其原型定義如下:

/**
* \defgroup xMessageBufferCreate xMessageBufferCreate
* \ingroup MessageBufferManagement
*/
#define xMessageBufferCreate( xBufferSizeBytes ) ( MessageBufferHandle_t ) xStreamBufferGenericCreate( xBufferSizeBytes, ( size_t ) 0, pdTRUE )

????????調用函數xMessageBufferCreate()時,只需傳遞緩沖區大小xBufferSizeBytes。這個函數實際上調用了函數xStreamBufferGenericCreate(),傳遞的觸發水平參數為0,因為消息緩沖區沒有觸發水平,最后的參數pdTRUE表示要創建的是消息緩沖區。

????????函數xMessageBufferCreate()的返回值是MessageBufferHandle_t類型的,就是所創建的消息緩沖區對象指針。

(2)寫入消息

????????用于向消息緩沖區寫入消息的函數是xMessageBufferSend(),這是個宏函數,其原型定義如下:

/**
* \defgroup xMessageBufferSend xMessageBufferSend
* \ingroup MessageBufferManagement
*/
#define xMessageBufferSend( xMessageBuffer, pvTxData, xDataLengthBytes, xTicksToWait ) xStreamBufferSend( ( StreamBufferHandle_t ) xMessageBuffer, pvTxData, xDataLengthBytes, xTicksToWait )

????????實際上,它是執行了流緩沖區寫入數據的函數xStreamBufferSend()。函數中各參數的意義如下。

  • xMessageBuffer,所操作的消息緩沖區的句柄。
  • pvTxData,準備寫入的數據緩沖區指針。
  • xDataLengthBytes,消息數據的字節數,不包括消息頭的4字節。
  • xTicksToWait,等待的節拍數,如果消息緩沖區沒有足夠的空間用于寫入這條消息,任務可以進入阻塞狀態等待。若設置為0,則表示不等待;若設置為portMAX_DELAY,則表示一直等待。

????????函數xStreamBufferSend()內部會判斷傳遞來的緩沖區對象的類型。如果是消息緩沖區,就在實際寫入數據前面加上一個uint32_t類型的整數,表示消息的字節數;如果是流緩沖區,就直接寫入數據。

????????函數xMessageBufferSend()的返回值是實際寫入消息的字節數,不包括消息頭的4字節。如果函數是因為等待超時而退出的,則返回值為0;如果寫入成功,返回值就是寫入的消息數據的字節數。這是與流緩沖區不同的一個地方,使用函數xStreamBufferSend()向流緩沖區寫入數據時,如果因等待超時而退出,仍然可能向流緩沖區寫入了一些數據。

????????在ISR中,向消息緩沖區寫入消息的函數是xMessageBufferSendFromISR(),它是個宏函數,實際就是執行了函數xStreamBufferSendFromISR(),其原型定義如下:

/**
* \defgroup xMessageBufferSendFromISR xMessageBufferSendFromISR
* \ingroup MessageBufferManagement
*/
#define xMessageBufferSendFromISR( xMessageBuffer, pvTxData, xDataLengthBytes, pxHigherPriorityTaskWoken ) xStreamBufferSendFromISR( ( StreamBufferHandle_t ) xMessageBuffer, pvTxData, xDataLengthBytes, pxHigherPriorityTaskWoken )

(3)讀取消息

????????用于從消息緩沖區讀取消息的函數是xMessageBufferReceive(),其原型定義如下:

/**
* \defgroup xMessageBufferReceive xMessageBufferReceive
* \ingroup MessageBufferManagement
*/
#define xMessageBufferReceive( xMessageBuffer, pvRxData, xBufferLengthBytes, xTicksToWait ) xStreamBufferReceive( ( StreamBufferHandle_t ) xMessageBuffer, pvRxData, xBufferLengthBytes, xTicksToWait )

????????它就是執行了函數xStreamBufferReceive()。函數中各參數的意義如下。

  • xMessageBuffer,所操作的消息緩沖區的句柄。
  • pvRxData,保存讀出數據的緩沖區指針。
  • xBufferLengthBytes,緩沖區pvRxData的長度,也就是最大能讀取的字節數。
  • xTicksToWait,等待的節拍數。如果消息緩沖區里沒有消息,任務可以進入阻塞狀態等待。若設置為0,則表示不等待;若設置為portMAX_DELAY,則表示一直等待。

????????函數xStreamBufferReceive()會自動區分參數xMessageBuffer是流緩沖區,還是消息緩沖區。如果是消息緩沖區,它會先讀取表示消息長度的4字節消息頭,然后按照長度讀取后面的消息數據。

????????函數xMessageBufferReceive()返回的是實際讀取的消息的字節數,不包括消息頭的4字節。如果函數是因為等待超時而退出的,則返回值為0。

????????在ISR中從消息緩沖區讀取消息的函數是xMessageBufferReceiveFromISR(),它是個宏函數,實際就是執行了函數xStreamBufferReceiveFromISR(),其原型定義如下:

/**
* \defgroup xMessageBufferReceiveFromISR xMessageBufferReceiveFromISR
* \ingroup MessageBufferManagement
*/
#define xMessageBufferReceiveFromISR( xMessageBuffer, pvRxData, xBufferLengthBytes, pxHigherPriorityTaskWoken ) xStreamBufferReceiveFromISR( ( StreamBufferHandle_t ) xMessageBuffer, pvRxData, xBufferLengthBytes, pxHigherPriorityTaskWoken )

(4)消息緩沖區狀態查詢

????????以下幾個查詢消息緩沖區狀態的函數,只需使用消息緩沖區的句柄作為函數的輸入參數。

  • xMessageBufferIsEmpty()查詢一個消息緩沖區是否為空,若返回pdTRUE,則表示緩沖區不包含任何消息。
  • xMessageBufferIsFull()查詢一個消息緩沖區是否已滿,若返回pdTRUE,則表示不能再寫入任何消息。
  • xMessageBufferSpacesAvailable()查詢一個消息緩沖區剩余的存儲空間字節數,返回值類型為uint32_t。

三、消息緩沖區使用示例

1、示例功能與CubeMX項目設置

????????本示例演示消息緩沖區的使用,實例的功能和使用流程如下。

  • 創建一個消息緩沖區和一個任務Task_Show。
  • 使用RTC的喚醒中斷,喚醒周期為1s。在RTC的喚醒中斷里讀取當前時間,轉化為字符串后,作為消息寫入消息緩沖區,每次寫入的消息長度不一樣。
  • 在任務Task_Show里讀取消息緩沖區的消息,并在串口助手上顯示。
  • 繼續使用旺寶紅龍開發板STM32F407ZGT6 KIT V1.0。

  • 一些設置可以參考本文作者寫的其他文章:

????????細說STM32單片機FreeRTOS流緩沖區及其應用實例-CSDN博客 ?https://wenchm.blog.csdn.net/article/details/148168854?spm=1011.2415.3001.5331

(1)RCC、SYS、Code Generator、USART3、TIM6

????????配置時鐘樹,將APB1定時器時鐘頻率設置為84MHz,APB2定時器時鐘頻率設置為168MHz ;設置TIM6作為基礎時鐘源;其它設置可見參考文章。

(2)RTC的設置

????????啟用LSE,啟用RTC,在時鐘樹上將LSE作為RTC的時鐘源。啟用周期喚醒功能,設置喚醒周期為1s,其他參數用默認值即可。

?

(3)FreeRTOS的設置

????????設置FreeRTOS接口為CMSIS_V2,所有“Config”和“Include”參數保持默認值。在FreeRTOS里創建一個任務Task_Show,其主要參數如圖所示。

(4)NVIC

????????在NVIC里開啟RTC喚醒中斷,設置其中斷優先級為5,因為要在其ISR里使用FreeRTOS API函數。

2、程序功能實現

(1)主程序

????????完成設置后,CubeMX自動生成代碼。在CubeIDE中打開項目,添加用戶功能代碼后,主程序代碼如下:

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "cmsis_os.h"
#include "rtc.h"
#include "usart.h"
#include "gpio.h"/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
void MX_FREERTOS_Init(void);/*** @brief  The application entry point.* @retval int*/
int main(void)
{/* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* Configure the system clock */SystemClock_Config();/* Initialize all configured peripherals */MX_GPIO_Init();MX_RTC_Init();MX_USART3_UART_Init();/* USER CODE BEGIN 2 *///Start Menuuint8_t startstr[] = "Demo9_2:Using Message Buffer.\r\n\r\n";HAL_UART_Transmit(&huart3,startstr,sizeof(startstr),0xFFFF);/* USER CODE END 2 *//* Init scheduler */osKernelInitialize();/* Call init function for freertos objects (in cmsis_os2.c) */MX_FREERTOS_Init();/* Start scheduler */osKernelStart();/* We should never get here as control is now taken by the scheduler *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}

(2)FreeRTOS對象初始化

????????自動生成的函數MX_FREERTOS_Init()只創建了任務,在CubeMX里不能可視化地創建消息緩沖區,需要在CubeMX生成的CubeIDE初始代碼的基礎上,編程創建消息緩沖區。在文件freertos.c中定義兩個常量和消息緩沖區對象,在函數MX_FREERTOS_Init()中增加創建消息緩沖區對象的代碼。完成后的代碼如下:

? ? ? ? 自動生成includes,并手動添加私有includes:?

/* Includes ------------------------------------------------------------------*/
#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os.h"/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "message_buffer.h"
#include "usart.h"
#include <stdio.h>		//用到函數sprintf()
#include <string.h>		//用到函數strlen()
/* USER CODE END Includes */

????????手動添加私有宏定義:

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define	MSG_BUFFER_LEN	50		//消息緩存區長度,單位:字節
#define	MSG_MAX_LEN		20		//消息最大長度,單位:字節
/* USER CODE END PD */

????????手動添加創建消息緩沖區句柄變量代碼;

? ? ? ? 自動生成任務函數句柄變量代碼:

/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN Variables */
MessageBufferHandle_t  msgBuffer;		//消息緩存區句柄變量
/* USER CODE END Variables */
/* Definitions for Task_Show */
osThreadId_t Task_ShowHandle;
const osThreadAttr_t Task_Show_attributes = {.name = "Task_Show",.stack_size = 256 * 4,.priority = (osPriority_t) osPriorityNormal,
};/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes *//* USER CODE END FunctionPrototypes */void AppTask_Show(void *argument);void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) *//*** @brief  FreeRTOS initialization* @param  None* @retval None*/
void MX_FREERTOS_Init(void) 
{/* Create the thread(s) *//* creation of Task_Show */Task_ShowHandle = osThreadNew(AppTask_Show, NULL, &Task_Show_attributes);/* USER CODE BEGIN RTOS_THREADS *//* add threads, ... */msgBuffer=xMessageBufferCreate(MSG_BUFFER_LEN);		//創建消息緩存區/* USER CODE END RTOS_THREADS */
}

(3)RTC的喚醒中斷

????????在RTC的喚醒中斷里讀取當前時間,將其轉換為字符串后寫入消息緩沖區。RTC喚醒中斷的回調函數是HAL_RTCEx_WakeUpTimerEventCallback()。為便于使用消息緩沖區句柄變量msgBuffer,在文件freertos.c中重新實現這個回調函數:

/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */
void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *hrtc)
{RTC_TimeTypeDef sTime;RTC_DateTypeDef sDate;if (HAL_RTC_GetTime(hrtc, &sTime,  RTC_FORMAT_BIN) != HAL_OK)return;if (HAL_RTC_GetDate(hrtc, &sDate,  RTC_FORMAT_BIN) !=HAL_OK)return;char dtArray[MSG_MAX_LEN];   						//存儲消息的數組, MSG_MAX_LEN=20if ((sTime.Seconds % 2)==0)  						//分奇偶秒,發送不同長度的消息字符串siprintf(dtArray,"Seconds = %u",sTime.Seconds);	//轉換為字符串,自動加'\0'elsesiprintf(dtArray,"Minute= %u",sTime.Minutes);	//轉換為字符串,自動加'\0'uint8_t bytesCount=strlen(dtArray);					//字符串長度,不帶最后的結束符BaseType_t  highTaskWoken=pdFALSE;if (msgBuffer != NULL){uint16_t  realCnt=xMessageBufferSendFromISR(msgBuffer,dtArray, bytesCount+1, &highTaskWoken);  // bytesCount+1,帶結束符'\0'printf("Write bytes=   %d\r\n", realCnt);		 //實際寫入消息長度portYIELD_FROM_ISR(highTaskWoken);				 //申請進行一次任務調度}
}int __io_putchar(int ch)
{HAL_UART_Transmit(&huart3,(uint8_t*)&ch,1,0xFFFF);return ch;
}
/* USER CODE END Application */

????????上述程序首先讀取RTC的時間和日期,根據當前時間的秒數是奇數還是偶數,生成不同長度的字符串數據并保存到數組dtArray里。這里用到了C語言標準庫中的兩個函數siprintf()和strlen()。siprintf()與printf()類似,只是把字符串寫入一個數組,并且在字符串最后自動添加結束符\0。strlen()用于得到字符串的長度,但是不包括最后的結束符。

????????在使用函數xMessageBufferSendFromISR()向消息緩沖區寫入消息時,執行的代碼如下:

uint16_t realCnt = xMessageBufferSendFromISR(msgBuffer,dtArray,bytesCount+1,&highTaskwoken);

????????這里傳遞的第3個參數值是bytesCount+1,也就是加上了字符串的結束符,否則,讀取者讀出的消息字符串將不帶結束符,串口助手將無法正常顯示字符串。bytesCount+1的值必須小于或等于MSG_MAX_LEN。

????????函數的返回值realCnt是實際寫入的消息長度,不帶消息頭的4個字節。如果消息寫入成功,那么realCnt等于bytesCount+1。

????????這里寫入消息的數據是字符串,這只是為了演示方便,實際寫入消息的數據可以是任意類型的數據,而不一定是字符串。

(4)任務Task_Show的功能

????????在任務Task_Show里讀取消息緩沖區里的消息,并在串口助手上顯示,其任務函數代碼如下:

/* USER CODE BEGIN Header_AppTask_Show */
/*** @brief  Function implementing the Task_Show thread.* @param  argument: Not used* @retval None*/
/* USER CODE END Header_AppTask_Show */
void AppTask_Show(void *argument)
{/* USER CODE BEGIN AppTask_Show *//* Infinite loop */uint8_t dtArray[MSG_MAX_LEN];								//讀出的數據臨時保存數組for(;;){uint16_t realCnt=xMessageBufferReceive(msgBuffer, dtArray,MSG_MAX_LEN, portMAX_DELAY);					//讀取消息printf("Read message bytes  =  %d\r\n", realCnt);		//實際讀出字節數printf("message string Read =  %s\r\n", dtArray);		//顯示讀出的消息字符串}/* USER CODE END AppTask_Show */
}

????????上述程序用函數xMessageBufferReceive()讀取消息緩沖區里的消息,然后在串口助手上顯示實際讀取的消息長度和消息字符串。調用函數xMessageBufferReceive()的代碼如下:

uint16_t realCnt = xMessageBufferReceive(msgBuffer,dtArray,MSG_MAX_LEN,portMAX_DELAY);

????????其中,dtArray是用于存儲讀出數據的uint8_t類型數組,傳遞的第3個參數是MSG_MAX_LEN,也就是最大可以讀取的消息的長度。函數返回值realCnt是實際讀取的消息的長度,不包括消息頭的4個字節。MSG_MAX_LEN應該大于或等于realCnt,否則,會導致無法讀出一條完整的消息。

3、運行調試

????????構建項目后,下載到開發板上并運行測試,會發現顯示的寫入消息長度和讀出消息長度是一致?的,串口助手上顯示的消息字符串也是正確的,說明可以寫入和讀出不同長度的消息。在實際使用消息緩沖區時,寫入者和讀取者之間應該定義好消息的格式,如同串口通信一樣定義通信協議。

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

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

相關文章

【緩存】JAVA本地緩存推薦Caffeine和Guava

&#x1f31f; 引言 在軟件開發過程中&#xff0c;緩存是提升系統性能的常用手段。對于基礎場景&#xff0c;直接使用 Java集合框架&#xff08;如Map/Set/List&#xff09;即可滿足需求。然而&#xff0c;當面對更復雜的緩存場景時&#xff1a; 需要支持多種過期策略&#x…

IDA插件 MIPSROP的安裝和使用方法

前言 筆者的IDA版本為9.0&#xff0c;剛開始根據一些博客描述以為將mipsrop.py拷貝到IDA的plugins目錄即可&#xff0c;可操作后發現事情好像沒這么簡單&#xff0c;復制進去后就發現沒有博客中所說的 MIPS ROP Finder &#xff0c;筆者在網上搜索了很多博客后在 https://bbs.…

(1)轉置后,行列式的值不變 (2)將行列式的任意兩行互換位置后,行列式改變符號

以下是對原始內容在不改變內容本身的前提下進行的格式優化&#xff0c;以提升可讀性和邏輯清晰度&#xff1a; ? 行列式的幾何意義 行列式&#xff08;determinant&#xff09;是線性代數中一個非常重要的概念&#xff0c;它的幾何含義可以從以下幾個方面理解&#xff1a; &a…

最大似然估計(Maximum Likelihood Estimation, MLE)詳解

一、定義 最大似然估計 是一種參數估計方法&#xff0c;其核心思想是&#xff1a; 選擇能使觀測數據出現概率最大的參數值作為估計值。 具體來說&#xff0c;假設數據 D x 1 , x 2 , … , x n D{x_1,x_2,…,x_n} Dx1?,x2?,…,xn?獨立且服從某個概率分布 P ( x ∣ θ ) P(…

用go從零構建寫一個RPC(3)--異步調用+多路復用實現

在前兩個版本中&#xff0c;我們實現了基礎的客戶端-服務端通信、連接池、序列化等關鍵模塊。為了進一步提升吞吐量和并發性能&#xff0c;本版本新增了 異步發送機制 和 多路復用支持&#xff0c;旨在減少資源消耗、提升連接利用率。 代碼地址&#xff1a;https://github.com/…

FFmpeg 安裝包全攻略:gpl、lgpl、shared、master 區別詳解

這些 FFmpeg 安裝包有很多版本和變種&#xff0c;主要區別在于以下幾個方面&#xff1a; ? 一、從名稱中看出的關鍵參數&#xff1a; 1. 版本號 master&#xff1a;開發版&#xff0c;最新功能&#xff0c;但可能不穩定。n6.1 / n7.1&#xff1a;正式版本&#xff0c;更穩定…

深度學習實戰:從圖像分類到文本生成的完整案例解析

1 圖像分類案例 1.1 CIFAR10數據集介紹 cifar數據是torchvision第三方包提供的數據集 訓練集5w 測試集1w y標簽 10個類別 10分類問題 一張圖形狀 (32, 32, 3) import torch import torch.nn as nn from torchvision.datasets import CIFAR10 from torchvision.transforms i…

Android 添加系統服務的完整流程

[應用程序] (應用進程)│↓ 調用簡單API [SoundManager] │ ├─ 代理模式門面模式&#xff08;應用進程&#xff09;│ ├─ 緩存數據 ←─ 裝飾器模式&#xff08;應用進程&#xff09;│ └─ 轉換異常 ←─ 適配器模式&#xff08;應用進程&#xff09;│↓ 通過Bind…

wan2.1代碼筆記

GPU內存不夠&#xff0c;可以先運行umt5&#xff0c;然后再運行wanpipeline&#xff0c;參考FLUX.1代碼筆記&#xff0c;或者使用ComfyUI。 下面使用隨機數代替umt5 embedding。 import torch from diffusers.utils import export_to_video from diffusers import Autoencoder…

環境搭建與工具配置

3.1 本地環境搭建 3.1.1 WAMP環境搭建漏洞靶場&#xff08;一、二&#xff09; WAMP&#xff08;Windows Apache MySQL PHP&#xff09;是搭建本地Web漏洞靶場的基礎環境。 安裝步驟&#xff1a; Apache&#xff1a;下載并安裝最新版Apache HTTP Server&#xff0c;配置監…

STM32F446主時鐘失效時DAC輸出異常現象解析與解決方案

—### 現象概述 在STM32F446微控制器應用中&#xff0c;若主時鐘&#xff08;HSE&#xff09;的晶體信號對地短路&#xff0c;但DAC&#xff08;數模轉換器&#xff09;仍能輸出變化信號&#xff0c;這一現象看似矛盾&#xff0c;實則與系統時鐘切換機制密切相關。本文將從硬件…

React 如何封裝一個可復用的 Ant Design 組件

文章目錄 前言一、為什么需要封裝組件&#xff1f;二、 仿antd組件的Button按鈕三、封裝一個可復用的表格組件 (實戰)1. 明確需求2. 設計組件 API3. 實現組件代碼4. 使用組件 三、封裝組件的最佳實踐四、進階優化 總結 前言 作為一名前端開發工程師&#xff0c;在日常項目中&a…

STC89C52RC/LE52RC

STC89C52RC 芯片手冊原理圖擴展版原理圖 功能示例LED燈LED燈的常亮效果LED燈的閃爍LED燈的跑馬燈效果&#xff1a;從左到右&#xff0c;從右到左 數碼管靜態數碼管數碼管計數mian.cApp.cApp.hCom.cCom.hDir.cDir.hInt.cInt.hMid.cMid.h 模板mian.cApp.cApp.hCom.cCom.hDir.cDir…

踩坑記錄:RecyclerView 局部刷新notifyItemChanged多次調用只觸發一次 onBindViewHolder 的原因

1. 問題背景 在做項目的時候&#xff0c;RecyclerView需要使用局部刷新&#xff0c;使用 notifyItemChanged(position, payload) 實現局部刷新&#xff0c;但發現調用多次只執行了一次&#xff0c;第二個刷新不生效。 2. 錯誤示例&#xff08;只處理 payloads.get(0)&#xff…

OpenLayers 加載鷹眼控件

注&#xff1a;當前使用的是 ol 5.3.0 版本&#xff0c;天地圖使用的key請到天地圖官網申請&#xff0c;并替換為自己的key 地圖控件是一些用來與地圖進行簡單交互的工具&#xff0c;地圖庫預先封裝好&#xff0c;可以供開發者直接使用。OpenLayers具有大部分常用的控件&#x…

WPF···

設置啟動頁 默認最后一個窗口關閉,程序退出,可以設置 修改窗體的icon圖標 修改項目exe圖標 雙擊項目名會看到代碼 其他 在A窗體點擊按鈕打開B窗體,在B窗體設置WindowStartupLocation=“CenterOwner” 在A窗體的代碼設置 B.Owner = this; B.Show(); B窗體生成在A窗體中間…

github公開項目爬取

import requestsdef search_github_repositories(keyword, tokenNone, languageNone, max_results1000):"""通過 GitHub API 搜索倉庫&#xff0c;支持分頁獲取所有結果&#xff08;最多 1000 條&#xff09;:param keyword: 搜索關鍵詞:param token: GitHub To…

防震基座在半導體晶圓制造設備拋光機詳細應用案例-江蘇泊蘇系統集成有限公司

在半導體制造領域&#xff0c;晶圓拋光作為關鍵工序&#xff0c;對設備穩定性要求近乎苛刻。哪怕極其細微的振動&#xff0c;都可能對晶圓表面質量產生嚴重影響&#xff0c;進而左右芯片制造的成敗。以下為您呈現一個防震基座在半導體晶圓制造設備拋光機上的經典應用案例。 企…

S32K開發環境搭建詳細教程(一、S32K IDE安裝注冊)

一、S32K IDE安裝注冊 1、進入恩智浦官網https://www.nxp.com.cn/&#xff08;需要在官網注冊一個賬號&#xff09; 2、直接搜索 “Standard Software”&#xff0c;找到S32K3 Standard Software&#xff0c;點擊進入 3、下載 (1)Automotive SW - S32K3 - S32 Design Studio…

Spring Cloud Gateway 微服務網關實戰指南

上篇文章簡單介紹了SpringCloud系列OpenFeign的基本用法以及Demo搭建&#xff08;Spring Cloud實戰&#xff1a;OpenFeign遠程調用與服務治理-CSDN博客&#xff09;&#xff0c;今天繼續講解下SpringCloud Gateway實戰指南&#xff01;在分享之前繼續回顧下本次SpringCloud的專…