性无码一区二区三区在线观看,少妇被爽到高潮在线观看,午夜精品一区二区三区,无码中文字幕人妻在线一区二区三区,无码精品国产一区二区三区免费

小麥大叔
認(rèn)證:普通會(huì)員
所在專題目錄 查看專題
基于CubeIDE快速整合FreeRTOS創(chuàng)建第一個(gè)任務(wù)
【FreeRTOS學(xué)習(xí)02】源碼結(jié)構(gòu)/數(shù)據(jù)類型/命名規(guī)則總結(jié)
【FreeRTOS學(xué)習(xí)03】Task Management 任務(wù)管理基本概念介紹
【FreeRTOS學(xué)習(xí)04】Queue Management 消息隊(duì)列使用詳解
【FreeRTOS學(xué)習(xí)05】深度解剖FreeRTOSConfig.h實(shí)現(xiàn)對(duì)系統(tǒng)的自定義剪裁
【FreeRTOS學(xué)習(xí)06】深度解剖中斷與任務(wù)之間同步的具體使用場(chǎng)景
作者動(dòng)態(tài) 更多
一款輕量級(jí)的開源GUI項(xiàng)目——SimpleGUI,可以完美適配單色屏
02-22 09:47
看到這100多個(gè)軟硬件開源項(xiàng)目,真是爽爆了
2024-11-30 14:12
推薦一個(gè)高效,可靠,安全的串口通訊開源方案
2024-11-27 11:17
推薦一款開源hack硬件平臺(tái)工具
2024-11-26 13:58
新手學(xué)STM32的話,先學(xué)標(biāo)準(zhǔn)庫(kù)還是HAL庫(kù)?
2024-10-18 15:09

【FreeRTOS學(xué)習(xí)04】Queue Management 消息隊(duì)列使用詳解

1 前言

任務(wù)之間的同步(同步就是任務(wù)之間做數(shù)據(jù)交互,或?yàn)閮蓚€(gè)任務(wù)之間的通訊),任務(wù)和中斷之間的同步都可以依靠消息隊(duì)列,從而實(shí)現(xiàn)異步處理,FreeRTOS的隊(duì)列采用FIFO(先進(jìn)先出)緩沖區(qū),具體如下圖所示;

2 xQUEUE

FreeRTOS消息隊(duì)列的實(shí)現(xiàn)主要是queue.c,需要包含頭文件queue.h,下面先看一下queue.c中的數(shù)據(jù)類型xQUEUE,源碼如下所示;

typedef struct QueueDefinition
{
	int8_t *pcHead;					/*< Points to the beginning of the queue storage area. */
	int8_t *pcTail;					/*< Points to the byte at the end of the queue storage area.  Once more byte is allocated than necessary to store the queue items, this is used as a marker. */
	int8_t *pcWriteTo;				/*< Points to the free next place in the storage area. */

	union							/* Use of a union is an exception to the coding standard to ensure two mutually exclusive structure members don't appear simultaneously (wasting RAM). */
	{
		int8_t *pcReadFrom;			/*< Points to the last place that a queued item was read from when the structure is used as a queue. */
		UBaseType_t uxRecursiveCallCount;/*< Maintains a count of the number of times a recursive mutex has been recursively 'taken' when the structure is used as a mutex. */
	} u;

	List_t xTasksWaitingToSend;		/*< List of tasks that are blocked waiting to post onto this queue.  Stored in priority order. */
	List_t xTasksWaitingToReceive;	/*< List of tasks that are blocked waiting to read from this queue.  Stored in priority order. */

	volatile UBaseType_t uxMessagesWaiting;/*< The number of items currently in the queue. */
	UBaseType_t uxLength;			/*< The length of the queue defined as the number of items it will hold, not the number of bytes. */
	UBaseType_t uxItemSize;			/*< The size of each items that the queue will hold. */

	volatile int8_t cRxLock;		/*< Stores the number of items received from the queue (removed from the queue) while the queue was locked.  Set to queueUNLOCKED when the queue is not locked. */
	volatile int8_t cTxLock;		/*< Stores the number of items transmitted to the queue (added to the queue) while the queue was locked.  Set to queueUNLOCKED when the queue is not locked. */

	#if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
		uint8_t ucStaticallyAllocated;	/*< Set to pdTRUE if the memory used by the queue was statically allocated to ensure no attempt is made to free the memory. */
	#endif

	#if ( configUSE_QUEUE_SETS == 1 )
		struct QueueDefinition *pxQueueSetContainer;
	#endif

	#if ( configUSE_TRACE_FACILITY == 1 )
		UBaseType_t uxQueueNumber;
		uint8_t ucQueueType;
	#endif

} xQUEUE;

本文暫時(shí)不需要深入源碼,在queue.h的接口已經(jīng)封裝得相當(dāng)好,無需對(duì)細(xì)節(jié)太過于關(guān)注,下面會(huì)是對(duì)常用接口的使用的總結(jié),如果英文好,直接看源碼中的函數(shù)注釋也是很好的選擇。

3 相關(guān)概念

3.1 數(shù)據(jù)結(jié)構(gòu)

隊(duì)列可以保存有限個(gè)具有確定長(zhǎng)度的數(shù)據(jù)單元。隊(duì)列可以保存的最大單元數(shù)目被稱為隊(duì)列的“深度”。在隊(duì)列創(chuàng)建時(shí)需要設(shè)定其深度和每個(gè)單元的大小。通常情況下,隊(duì)列被作為 FIFO(先進(jìn)先出)使用,即數(shù)據(jù)由隊(duì)列尾寫入,從隊(duì)列首讀出。當(dāng)然,由隊(duì)列首寫入也是可能的。往隊(duì)列寫入數(shù)據(jù)是通過字節(jié)拷貝把數(shù)據(jù)復(fù)制存儲(chǔ)到隊(duì)列中;從隊(duì)列讀出數(shù)據(jù)使得把隊(duì)列中的數(shù)據(jù)拷貝刪除。1 如下圖所示;

注意上面提到的數(shù)據(jù)單元可以是一個(gè)charint類型的數(shù),但是相對(duì)比較合理的設(shè)計(jì)是,封裝成一個(gè)合理的類,或者稱之為結(jié)構(gòu)體,可以明確當(dāng)前數(shù)據(jù)單元的數(shù)據(jù)類型,數(shù)據(jù)來源(來自哪個(gè)任務(wù))等等,因?yàn)橐粋€(gè)隊(duì)列可以被多個(gè)任務(wù)進(jìn)行讀取和發(fā)送函數(shù),這樣就避免了傳輸數(shù)據(jù)出現(xiàn)混淆的情況。通常設(shè)計(jì)是一個(gè)隊(duì)列被多個(gè)任務(wù)寫入數(shù)據(jù),然后有一個(gè)任務(wù)讀取,暫時(shí)稱之為多寫一讀,反之,多讀一寫則較少遇到。

3.2 收發(fā)數(shù)據(jù)堵塞

當(dāng)某個(gè)任務(wù)試圖讀或者寫一個(gè)隊(duì)列時(shí),其可以指定一個(gè)阻塞超時(shí)時(shí)間,

  • 讀?。喝蝿?wù)讀取數(shù)據(jù)時(shí),在設(shè)置堵塞超時(shí)時(shí)間內(nèi),如果隊(duì)列為空,該任務(wù)將保持阻塞狀態(tài)以等待隊(duì)列數(shù)據(jù)有效。當(dāng)其它任務(wù)或中斷服務(wù)例程往其等待的隊(duì)列中寫入了數(shù)據(jù),該任務(wù)將自動(dòng)由阻塞態(tài)轉(zhuǎn)移為就緒態(tài)。

  • 寫入:如果隊(duì)列被多個(gè)任務(wù)寫入,那么將導(dǎo)致多個(gè)任務(wù)堵塞以等待隊(duì)列有效,當(dāng)隊(duì)列有效的時(shí)候,這些任務(wù)中的優(yōu)先級(jí)最高的任務(wù)優(yōu)先進(jìn)入就緒態(tài)。

4 常用函數(shù)

FreeRTOS的消息隊(duì)列常用接口都封裝在queue.h中,通過宏定義統(tǒng)一將接口函數(shù)的命名風(fēng)格整理得十分統(tǒng)一;具體如下圖所示;

這里有兩種需要注意;

  • 任務(wù)與任務(wù)之間同步:例如圖中處的API適用于任務(wù)間同步;
    • xQueueSendToFront
    • xQueueSendToFront
    • xQueueSend
    • xQueueOverwrite
  • 任務(wù)與中斷之間同步:圖中②處的API適用于任務(wù)于中斷間同步,xxxISR()后綴的函數(shù)都是FreeRTOS中保證了線程安全的;
    • xQueueSendToFrontFromISR
    • xQueueSendToBackFromISR
    • xQueueOverwriteFromISR
    • xQueueSendFromISR

4.1 創(chuàng)建隊(duì)列

  • QueueHandle_tQueueHandle_t是一個(gè)void類型的指針變量,定義在queue.h中,具體如下;
/**
 * Type by which queues are referenced.  For example, a call to xQueueCreate()
 * returns an QueueHandle_t variable that can then be used as a parameter to
 * xQueueSend(), xQueueReceive(), etc.
 */
typedef void * QueueHandle_t;

基本上每個(gè)隊(duì)列函數(shù)都會(huì)使用這個(gè)變量,這里我們統(tǒng)一稱為隊(duì)列的句柄;

  • xQueueCreate這個(gè)函數(shù)可以創(chuàng)建一個(gè)隊(duì)列,創(chuàng)建成功則會(huì)返回一個(gè)隊(duì)列句柄,如果創(chuàng)建失敗則返回NULL,其函數(shù)原型是xQueueGenericCreate,具體如下所示;
#define xQueueCreate( uxQueueLength, uxItemSize ) \
xQueueGenericCreate( ( uxQueueLength ), ( uxItemSize ), ( queueQUEUE_TYPE_BASE ) )

xQueueCreate如下所示;

 QueueHandle_t xQueueCreate(
							  UBaseType_t uxQueueLength,
							  UBaseType_t uxItemSize
						  );

4.2 發(fā)送數(shù)據(jù)

下面都是從任務(wù)發(fā)送數(shù)據(jù)到隊(duì)列,

  • xQueueSendToFront將數(shù)據(jù)發(fā)送至隊(duì)首,函數(shù)聲明如下;

 BaseType_t xQueueSendToBack(
								   QueueHandle_t	xQueue,
								   const void		*pvItemToQueue,
								   TickType_t		xTicksToWait
							   ); 
  • xQueueSendToBack將數(shù)據(jù)發(fā)送至隊(duì)尾,函數(shù)聲明如下;
 BaseType_t xQueueSendToFront(
							  QueueHandle_t xQueue,
							  const void * pvItemToQueue,
							  TickType_t xTicksToWait
						 );
  • xQueueSend與xQueueSendToBack入隊(duì)順序相同,函數(shù)聲明如下所示;
BaseType_t xQueueSend(
							  QueueHandle_t xQueue,
							  const void * pvItemToQueue,
							  TickType_t xTicksToWait
						 );

具體的參數(shù)描述如下:

  • xTicksToWait設(shè)為0 ,且隊(duì)列已滿,則xQueueSendToFront()與xQueueSendToBack()均會(huì)立即返回。阻塞時(shí)間是以系統(tǒng)心跳周期為單位的,所以絕對(duì)時(shí)間取決于系統(tǒng)心跳頻率。常量 portTICK_RATE_MS 可以用來把心跳時(shí)間單位轉(zhuǎn)換為毫秒時(shí)間單位。
  • xTicksToWait 設(shè)置為 portMAX_DELAY , 并且在FreeRTOSConig.h 中設(shè)定 INCLUDE_vTaskSuspend 為 1,那么阻塞等待將沒有超時(shí)限制。

4.3 接收數(shù)據(jù)

  • xQueueReceivexQueueReceive()用于從隊(duì)列中接收(讀取)數(shù)據(jù)單元。接收到的單元同時(shí)會(huì)從隊(duì)列中刪除。函數(shù)聲明如下;

 BaseType_t xQueueReceive(
								 QueueHandle_t xQueue,
								 void *pvBuffer,
								 TickType_t xTicksToWait
							); 
  • xQueuePeekxQueuePeek()也是從從隊(duì)列中接收數(shù)據(jù)單元,不同的是并不從隊(duì)列中刪出接收到的單元。 xQueuePeek()從隊(duì)列首接收到數(shù)據(jù)后,不會(huì)修改隊(duì)列中的數(shù)據(jù),也不會(huì)改變數(shù)據(jù)在隊(duì)列中的存儲(chǔ)序順。函數(shù)聲明如下;
 BaseType_t xQueuePeek(
							 QueueHandle_t xQueue,
							 void * const pvBuffer,
							 TickType_t xTicksToWait
						 );

具體的參數(shù)描述如下:

  • uxQueueSpacesAvailableuxQueueSpacesAvailable()用于查詢隊(duì)列中可用的空閑空間數(shù)量;函數(shù)聲明如下;
UBaseType_t uxQueueSpacesAvailable( const QueueHandle_t xQueue );

  • uxQueueMessagesWaitinguxQueueMessagesWaiting()用于查詢隊(duì)列中當(dāng)前有效數(shù)據(jù)單元個(gè)數(shù);函數(shù)聲明如下;
UBaseType_t uxQueueMessagesWaiting( const QueueHandle_t xQueue );

4.4 刪除隊(duì)列

  • vQueueDelete用來刪除一個(gè)隊(duì)列,直接傳入已創(chuàng)建的隊(duì)列句柄即可,函數(shù)聲明如下;
void vQueueDelete( QueueHandle_t xQueue );

5 舉例

多個(gè)任務(wù)寫入一個(gè)任務(wù)讀取的時(shí)候應(yīng)該怎么做呢?如下圖所示2;

這里有三個(gè)任務(wù),所以為了搞清楚數(shù)據(jù)來自哪個(gè)任務(wù),因此將數(shù)據(jù)單元封裝起來,使用iMeaning表示數(shù)據(jù)單元的源頭,當(dāng)然這里還是比較簡(jiǎn)單的應(yīng)用。

6 總結(jié)

本文介紹了FreeRTOS的消息隊(duì)列比價(jià)常用的方法,當(dāng)然是相對(duì)簡(jiǎn)單的,側(cè)重在了解概念上,需要實(shí)際的應(yīng)用從而加深理解,更加詳細(xì)已經(jīng)靈活的應(yīng)用可以參考FreeRTOS作者撰寫的Mastering_the_FreeRTOS_Real_Time_Kernel-A_Hands-On_Tutorial_Guide。

聲明:本內(nèi)容為作者獨(dú)立觀點(diǎn),不代表電子星球立場(chǎng)。未經(jīng)允許不得轉(zhuǎn)載。授權(quán)事宜與稿件投訴,請(qǐng)聯(lián)系:editor@netbroad.com
覺得內(nèi)容不錯(cuò)的朋友,別忘了一鍵三連哦!
贊 4
收藏 3
關(guān)注 145
成為作者 賺取收益
全部留言
0/200
成為第一個(gè)和作者交流的人吧