中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

網(wǎng)絡(luò)服務(wù)機(jī)構(gòu)seo數(shù)據(jù)優(yōu)化

網(wǎng)絡(luò)服務(wù)機(jī)構(gòu),seo數(shù)據(jù)優(yōu)化,做網(wǎng)站前期工作,網(wǎng)站規(guī)劃內(nèi)容包括提示:文章寫完后,目錄可以自動(dòng)生成,如何生成可參考右邊的幫助文檔 文章目錄 前言一、隊(duì)列是什么?而在freertos中,隊(duì)列是什么呢?①如果要進(jìn)行中斷、任務(wù)的交流,那我用全局變量行嗎?②…

提示:文章寫完后,目錄可以自動(dòng)生成,如何生成可參考右邊的幫助文檔

文章目錄

  • 前言
  • 一、隊(duì)列是什么?
    • 而在freertos中,隊(duì)列是什么呢?
      • ①如果要進(jìn)行中斷、任務(wù)的交流,那我用全局變量行嗎?
      • ②那為什么隊(duì)列就可以代替全局變量的功能呢?
      • ③看一看在freertos中隊(duì)列的結(jié)構(gòu)
      • ④問題:當(dāng)多個(gè)任務(wù)寫入消息給一個(gè)“滿隊(duì)列”時(shí),這些任務(wù)都會(huì)進(jìn)入阻塞狀態(tài),也就是說有多個(gè)任務(wù) 在等待同一 個(gè)隊(duì)列的空間。那當(dāng)隊(duì)列中有空間時(shí),哪個(gè)任務(wù)會(huì)進(jìn)入就緒態(tài)?
      • ⑤數(shù)據(jù)寫隊(duì)列、讀隊(duì)列操作過程![在這里插入圖片描述](https://img-blog.csdnimg.cn/02032663fbd14548b0b9f6e699186440.png)
  • 二、隊(duì)列的結(jié)構(gòu)體
    • 1.結(jié)構(gòu)體內(nèi)容
    • 2.結(jié)構(gòu)體示意圖
  • 三、隊(duì)列相關(guān)API函數(shù)介紹
    • 1.創(chuàng)建隊(duì)列
    • 2.寫消息入隊(duì)列
      • (1)前三個(gè)函數(shù)
      • (2)后面的函數(shù)
    • 3.從隊(duì)列中讀取消息
      • 代碼例子:
  • 四、隊(duì)列入隊(duì)和出隊(duì)操作實(shí)驗(yàn)
    • 1.實(shí)驗(yàn)?zāi)繕?biāo)
    • 2.例程
      • ①main.c
      • ②freertos_demo();
      • ③操作隊(duì)列和存儲(chǔ)大數(shù)據(jù)塊
      • ④任務(wù)一:實(shí)現(xiàn)入隊(duì)
      • ⑤任務(wù)二:小數(shù)據(jù)出隊(duì)
      • ⑥任務(wù)三:大數(shù)據(jù)出隊(duì)
    • 3.例程運(yùn)行結(jié)果:
  • 五、隊(duì)列相關(guān)API函數(shù)解析
    • 1.隊(duì)列的創(chuàng)建API函數(shù):xQueueCreate( )
    • 2.往隊(duì)列寫入數(shù)據(jù)API函數(shù)(入隊(duì)):xQueueSend( )
    • 3.從隊(duì)列讀取數(shù)據(jù)API函數(shù)(出隊(duì)): xQueueReceive( )


前言

`本文包括以下內(nèi)容:
在這里插入圖片描述

一、隊(duì)列是什么?

綜述:隊(duì)列是一種特殊的數(shù)據(jù)結(jié)構(gòu),它遵循先進(jìn)先出(FIFO)的原則。隊(duì)列中的元素按照其插入的順序進(jìn)行訪問和處理,新元素被插入到隊(duì)列的末尾,而已存在的元素則在隊(duì)列的前端進(jìn)行操作和刪除。隊(duì)列的操作包括入隊(duì)(enqueue)和出隊(duì)(dequeue),入隊(duì)表示將元素插入到隊(duì)列的末尾,而出隊(duì)則表示將隊(duì)列的前端元素移除并返回。隊(duì)列常用于需要按照先后順序處理元素的場(chǎng)景,例如任務(wù)調(diào)度、消息傳遞等。

而在freertos中,隊(duì)列是什么呢?

隊(duì)列是任務(wù)到任務(wù)、任務(wù)到中斷、中斷到任務(wù)數(shù)據(jù)交流的一種機(jī)制(消息傳遞)
在這里插入圖片描述

①如果要進(jìn)行中斷、任務(wù)的交流,那我用全局變量行嗎?

答:不行。以這個(gè)圖為例,比如一個(gè)全局變量a=0,兩個(gè)任務(wù)里面都有對(duì)全局變量a的自增,如果兩個(gè)任務(wù)優(yōu)先級(jí)不同,當(dāng)運(yùn)行任務(wù)1時(shí)a++可能運(yùn)行到讀數(shù)據(jù)-修改數(shù)據(jù),但還沒有寫數(shù)據(jù)時(shí)就已經(jīng)被高優(yōu)先級(jí)的任務(wù)二打斷,導(dǎo)致a≠1,執(zhí)行任務(wù)二后才=1,這樣的話,執(zhí)行兩次任務(wù)卻讓全局變量a的值是錯(cuò)誤的。

所以全局變量的弊端:數(shù)據(jù)無保護(hù),導(dǎo)致數(shù)據(jù)不安全,當(dāng)多個(gè)任務(wù)同時(shí)對(duì)該變量操作時(shí),數(shù)據(jù)易受損

②那為什么隊(duì)列就可以代替全局變量的功能呢?

首先來看隊(duì)列的結(jié)構(gòu):
在這里插入圖片描述
可以看到,任務(wù)A和B是寫隊(duì)列操作,寫隊(duì)列這個(gè)函數(shù)呢,它會(huì)進(jìn)入臨界區(qū),完成實(shí)際操作后再退出臨界區(qū),所以:寫隊(duì)列時(shí)實(shí)際關(guān)閉了系統(tǒng)中斷,使得臨界區(qū)代碼可以完整的運(yùn)行不被打斷,而讀隊(duì)列也是同理。

所以,讀寫隊(duì)列具有程序保護(hù)功能,防止多任務(wù)同時(shí)訪問造成的數(shù)據(jù)沖突。

③看一看在freertos中隊(duì)列的結(jié)構(gòu)

在這里插入圖片描述
在隊(duì)列中可以存儲(chǔ)數(shù)量有限、大小固定的數(shù)據(jù)。隊(duì)列中的每一個(gè)數(shù)據(jù)叫做“隊(duì)列項(xiàng)目”,隊(duì)列能夠存儲(chǔ)“隊(duì)列項(xiàng)目”的最大數(shù)量稱為隊(duì)列的長(zhǎng)度。
所以隊(duì)列的核心特征:隊(duì)列長(zhǎng)度和每個(gè)隊(duì)列項(xiàng)目大小。需要我們自己創(chuàng)建時(shí)設(shè)置。
在Freertos中,隊(duì)列的特點(diǎn):
在這里插入圖片描述

(1)FIFO是First-In First-Out的縮寫,意為先進(jìn)先出。在隊(duì)列中,新元素被插入到隊(duì)列的末尾,而已存在的元素則在隊(duì)列的前端進(jìn)行操作和刪除。當(dāng)需要訪問或處理隊(duì)列中的元素時(shí),先訪問或處理隊(duì)列中最早插入的元素,然后按照插入的先后順序依次訪問或處理其他元素。這種先進(jìn)先出的特性使得隊(duì)列成為一種常用的數(shù)據(jù)結(jié)構(gòu),在任務(wù)調(diào)度、緩存管理、消息傳遞等場(chǎng)景中得到廣泛應(yīng)用。

(2)在FreeRTOS中,隊(duì)列可以采用實(shí)際值傳遞或者傳遞指針的方式進(jìn)行數(shù)據(jù)傳遞。實(shí)際值傳遞是指將數(shù)據(jù)的副本拷貝到隊(duì)列中進(jìn)行傳遞,這樣操作的是數(shù)據(jù)的副本,對(duì)原始數(shù)據(jù)沒有影響。而傳遞指針則是將指向?qū)嶋H數(shù)據(jù)的指針放入隊(duì)列中,這樣可以避免復(fù)制大量的數(shù)據(jù),但需要注意在使用指針傳遞時(shí),確保不會(huì)出現(xiàn)指針指向無效數(shù)據(jù)的情況。
在傳遞較大的數(shù)據(jù)時(shí),采用指針傳遞可以避免頻繁的數(shù)據(jù)復(fù)制,提高效率。但需要注意在使用指針傳遞時(shí),要確保數(shù)據(jù)的有效性,即確保指針指向的數(shù)據(jù)在傳遞過程中不會(huì)被修改或釋放,以免導(dǎo)致數(shù)據(jù)錯(cuò)誤或懸掛指針的情況。

(3)隊(duì)列在FreeRTOS中是一種通用的機(jī)制,可以被任何任務(wù)或中斷使用來發(fā)送和讀取消息。這是因?yàn)殛?duì)列是一種共享的數(shù)據(jù)結(jié)構(gòu),用于在不同的任務(wù)或中斷之間傳遞數(shù)據(jù)。任何任務(wù)或中斷都可以使用隊(duì)列的API函數(shù)來發(fā)送消息到隊(duì)列或從隊(duì)列中讀取消息,無論它們屬于哪個(gè)任務(wù)。
這種靈活性使得隊(duì)列成為一種常用的通信機(jī)制,在多任務(wù)或多中斷的系統(tǒng)中,可以方便地進(jìn)行任務(wù)間的數(shù)據(jù)傳遞和同步。通過隊(duì)列,任務(wù)和中斷可以安全地共享數(shù)據(jù),避免競(jìng)爭(zhēng)條件和數(shù)據(jù)沖突的問題。同時(shí),任務(wù)和中斷可以根據(jù)需要進(jìn)行阻塞或喚醒,以實(shí)現(xiàn)有效的同步和通信。

(4)當(dāng)任務(wù)向一個(gè)隊(duì)列發(fā)送消息時(shí),可以通過指定一個(gè)阻塞時(shí)間來控制任務(wù)的行為。
如果隊(duì)列已滿,無法將消息入隊(duì),任務(wù)可以選擇以下幾種行為
①阻塞等待:任務(wù)可以指定一個(gè)阻塞時(shí)間,如果隊(duì)列已滿,則任務(wù)會(huì)在隊(duì)列有空閑位置之前被阻塞。任務(wù)將等待,直到隊(duì)列有空閑位置并成功將消息入隊(duì),或者等待的超時(shí)時(shí)間到達(dá)。
②非阻塞立即返回:任務(wù)可以選擇在隊(duì)列已滿時(shí)立即返回,而不進(jìn)行阻塞等待。任務(wù)可以根據(jù)返回的結(jié)果來判斷是否消息成功發(fā)送到隊(duì)列中。
在這里插入圖片描述

④問題:當(dāng)多個(gè)任務(wù)寫入消息給一個(gè)“滿隊(duì)列”時(shí),這些任務(wù)都會(huì)進(jìn)入阻塞狀態(tài),也就是說有多個(gè)任務(wù) 在等待同一 個(gè)隊(duì)列的空間。那當(dāng)隊(duì)列中有空間時(shí),哪個(gè)任務(wù)會(huì)進(jìn)入就緒態(tài)?

在這里插入圖片描述

⑤數(shù)據(jù)寫隊(duì)列、讀隊(duì)列操作過程在這里插入圖片描述

二、隊(duì)列的結(jié)構(gòu)體

1.結(jié)構(gòu)體內(nèi)容

如下:

typedef struct QueueDefinition 
{int8_t * pcHead					/* 存儲(chǔ)區(qū)域的起始地址 */int8_t * pcWriteTo;        				/* 下一個(gè)寫入的位置 */union{QueuePointers_t     xQueue; SemaphoreData_t  xSemaphore; } u ;List_t xTasksWaitingToSend; 			/* 等待發(fā)送列表 */List_t xTasksWaitingToReceive;			/* 等待接收列表 */volatile UBaseType_t uxMessagesWaiting; 	/* 非空閑隊(duì)列項(xiàng)目的數(shù)量 */UBaseType_t uxLength;			/* 隊(duì)列長(zhǎng)度 */UBaseType_t uxItemSize;                 		/* 隊(duì)列項(xiàng)目的大小 */volatile int8_t cRxLock; 				/* 讀取上鎖計(jì)數(shù)器 */volatile int8_t cTxLock;			/* 寫入上鎖計(jì)數(shù)器 *//* 其他的一些條件編譯 */
} xQUEUE;

這段代碼是一個(gè)隊(duì)列的定義,具體的結(jié)構(gòu)體成員解釋如下:

int8_t * pcHead: 存儲(chǔ)區(qū)域的起始地址,即隊(duì)列的存儲(chǔ)空間的首地址。

int8_t * pcWriteTo: 下一個(gè)寫入位置的指針,用于指示下一個(gè)要寫入數(shù)據(jù)的位置。

union { QueuePointers_t xQueue; SemaphoreData_t xSemaphore; } u: 一個(gè)聯(lián)合體,用于保存隊(duì)列指針或信號(hào)量數(shù)據(jù)。

List_t xTasksWaitingToSend: 等待發(fā)送列表,用于存儲(chǔ)等待向隊(duì)列發(fā)送消息的任務(wù)。

List_t xTasksWaitingToReceive: 等待接收列表,用于存儲(chǔ)等待從隊(duì)列接收消息的任務(wù)。

volatile UBaseType_t uxMessagesWaiting: 非空閑隊(duì)列項(xiàng)目的數(shù)量,用于記錄當(dāng)前隊(duì)列中等待接收的消息數(shù)量。

UBaseType_t uxLength: 隊(duì)列長(zhǎng)度,表示隊(duì)列可以容納的最大項(xiàng)目數(shù)量。

UBaseType_t uxItemSize: 隊(duì)列項(xiàng)目的大小,表示每個(gè)項(xiàng)目占用的字節(jié)數(shù)。

volatile int8_t cRxLock: 讀取上鎖計(jì)數(shù)器,用于記錄當(dāng)前隊(duì)列被讀取操作鎖定的次數(shù)。

volatile int8_t cTxLock: 寫入上鎖計(jì)數(shù)器,用于記錄當(dāng)前隊(duì)列被寫入操作鎖定的次數(shù)。

2.結(jié)構(gòu)體示意圖

在這里插入圖片描述

三、隊(duì)列相關(guān)API函數(shù)介紹

使用隊(duì)列的主要流程:創(chuàng)建隊(duì)列 ->寫隊(duì)列 -> 讀隊(duì)列。主要包括創(chuàng)建隊(duì)列、寫隊(duì)列、讀隊(duì)列三個(gè)部分。

1.創(chuàng)建隊(duì)列

在這里插入圖片描述
參數(shù)說明:

uxQueueLength:隊(duì)列的長(zhǎng)度,即隊(duì)列可以容納的最大項(xiàng)目數(shù)量。
uxItemSize:隊(duì)列中每個(gè)項(xiàng)目的大小,即每個(gè)項(xiàng)目占用的字節(jié)數(shù)。
返回值:

成功創(chuàng)建隊(duì)列時(shí),返回一個(gè)有效的隊(duì)列句柄(QueueHandle_t)。
創(chuàng)建隊(duì)列失敗時(shí),返回 NULL。
在這里插入圖片描述
示例用法:

#include "FreeRTOS.h"
#include "queue.h"// 創(chuàng)建一個(gè)長(zhǎng)度為10,每個(gè)項(xiàng)目大小為4字節(jié)的隊(duì)列
QueueHandle_t xQueue = xQueueCreate(10, sizeof(int));
if (xQueue != NULL) {// 隊(duì)列創(chuàng)建成功
} else {// 隊(duì)列創(chuàng)建失敗
}

xQueueCreate() 函數(shù)用于在運(yùn)行時(shí)動(dòng)態(tài)創(chuàng)建一個(gè)隊(duì)列,并返回一個(gè)隊(duì)列句柄,該句柄可用于后續(xù)對(duì)隊(duì)列進(jìn)行操作,如發(fā)送消息和接收消息。注意,在使用完隊(duì)列后,需要使用 vQueueDelete() 函數(shù)來刪除隊(duì)列,以釋放相關(guān)的資源。

2.寫消息入隊(duì)列

在這里插入圖片描述
寫消息到隊(duì)列里,只能往隊(duì)列頭部、隊(duì)列尾部、覆寫方式寫入隊(duì)列這三種方法,覆寫只有在隊(duì)列的隊(duì)列長(zhǎng)度為 1 時(shí),才能夠使用

(1)前三個(gè)函數(shù)

xQueueSend()、xQueueSendToBack() 和 xQueueSendToFront() 函數(shù)都是用于向隊(duì)列中寫入消息的函數(shù),它們的作用類似,但有一些細(xì)微的差別。

這些函數(shù)的函數(shù)原型如下:

BaseType_t xQueueSend(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait);BaseType_t xQueueSendToBack(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait);BaseType_t xQueueSendToFront(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait);

參數(shù)說明:
xQueue:要寫入的隊(duì)列的句柄。
pvItemToQueue:指向要寫入隊(duì)列的消息的指針。
xTicksToWait:寫入操作的超時(shí)時(shí)間,如果隊(duì)列已滿,則等待一段時(shí)間再嘗試寫入??梢允褂?portMAX_DELAY 來表示無限等待。

返回值:
如果成功寫入消息到隊(duì)列,則返回 pdPASS。
如果寫入消息失敗(如隊(duì)列已滿),并且在指定的超時(shí)時(shí)間內(nèi)未能成功寫入,則返回 errQUEUE_FULL。

示例用法:

#include "FreeRTOS.h"
#include "queue.h"// 創(chuàng)建一個(gè)長(zhǎng)度為10,每個(gè)項(xiàng)目大小為4字節(jié)的隊(duì)列
QueueHandle_t xQueue = xQueueCreate(10, sizeof(int));int message = 42;// 向隊(duì)列尾部寫入消息
if (xQueueSend(xQueue, &message, portMAX_DELAY) == pdPASS) {// 消息寫入成功
} else {// 消息寫入失敗
}// 向隊(duì)列尾部寫入消息(與 xQueueSend() 等效)
if (xQueueSendToBack(xQueue, &message, portMAX_DELAY) == pdPASS) {// 消息寫入成功
} else {// 消息寫入失敗
}// 向隊(duì)列頭部寫入消息
if (xQueueSendToFront(xQueue, &message, portMAX_DELAY) == pdPASS) {// 消息寫入成功
} else {// 消息寫入失敗
}

這些函數(shù)用于將消息寫入隊(duì)列中,xQueueSend() 和 xQueueSendToBack() 將消息寫入隊(duì)列的尾部,而 xQueueSendToFront() 將消息寫入隊(duì)列的頭部。如果隊(duì)列已滿,則寫入操作將會(huì)阻塞,直到隊(duì)列有可用空間或超時(shí)。

(2)后面的函數(shù)

xQueueOverwrite() 和 xQueueOverwriteFromISR() 函數(shù)用于覆寫隊(duì)列中的消息,僅適用于隊(duì)列長(zhǎng)度為1的情況。

這些函數(shù)的函數(shù)原型如下:

BaseType_t xQueueOverwrite(QueueHandle_t xQueue, const void *pvItemToQueue);BaseType_t xQueueOverwriteFromISR(QueueHandle_t xQueue, const void *pvItemToQueue, BaseType_t *pxHigherPriorityTaskWoken);

參數(shù)說明:

xQueue:要操作的隊(duì)列的句柄。
pvItemToQueue:指向要寫入隊(duì)列的消息的指針。
pxHigherPriorityTaskWoken:一個(gè)指向 BaseType_t 類型變量的指針,用于指示是否有更高優(yōu)先級(jí)的任務(wù)需要喚醒。在 xQueueOverwriteFromISR() 中使用,可以設(shè)置為 NULL。
返回值:

如果成功覆寫隊(duì)列中的消息,則返回 pdPASS。
如果隊(duì)列為空或隊(duì)列長(zhǎng)度不為1,則返回 errQUEUE_FULL。
示例用法:

#include "FreeRTOS.h"
#include "queue.h"// 創(chuàng)建一個(gè)長(zhǎng)度為1,每個(gè)項(xiàng)目大小為4字節(jié)的隊(duì)列
QueueHandle_t xQueue = xQueueCreate(1, sizeof(int));int message = 42;// 覆寫隊(duì)列中的消息
if (xQueueOverwrite(xQueue, &message) == pdPASS) {// 消息覆寫成功
} else {// 消息覆寫失敗
}// 在中斷中覆寫隊(duì)列中的消息
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
if (xQueueOverwriteFromISR(xQueue, &message, &xHigherPriorityTaskWoken) == pdPASS) {// 消息覆寫成功
} else {// 消息覆寫失敗
}

xQueueOverwrite() 和 xQueueOverwriteFromISR() 函數(shù)用于覆寫隊(duì)列中的消息。在隊(duì)列長(zhǎng)度為1的情況下,可以使用這些函數(shù)來覆蓋隊(duì)列中的現(xiàn)有消息,而不需要等待或創(chuàng)建新的消息。請(qǐng)注意,這些函數(shù)只適用于隊(duì)列長(zhǎng)度為1的情況。

在中斷處理程序中使用 xQueueOverwriteFromISR() 函數(shù)時(shí),需要將 pxHigherPriorityTaskWoken 參數(shù)設(shè)置為非空指針,并且根據(jù)實(shí)際情況判斷是否需要喚醒更高優(yōu)先級(jí)的任務(wù)。

3.從隊(duì)列中讀取消息

在這里插入圖片描述

xQueueReceive()
從隊(duì)列頭部讀取消息,并將消息從隊(duì)列中刪除。
如果隊(duì)列為空,任務(wù)將進(jìn)入阻塞狀態(tài),直到隊(duì)列中有消息可讀取。
返回pdPASS表示成功讀取到消息,返回errQUEUE_EMPTY表示隊(duì)列為空。

xQueuePeek()
從隊(duì)列頭部讀取消息,但不刪除消息。
如果隊(duì)列為空,任務(wù)將進(jìn)入阻塞狀態(tài),直到隊(duì)列中有消息可讀取。
返回pdPASS表示成功讀取到消息,返回errQUEUE_EMPTY表示隊(duì)列為空。

xQueueReceiveFromISR()
在中斷中從隊(duì)列頭部讀取消息,并將消息從隊(duì)列中刪除。
與xQueueReceive()函數(shù)類似,但是特別適用于在中斷服務(wù)例程(ISR)中使用。
返回pdPASS表示成功讀取到消息,返回errQUEUE_EMPTY表示隊(duì)列為空。

xQueuePeekFromISR()
在中斷中從隊(duì)列頭部讀取消息,但不刪除消息。
與xQueuePeek()函數(shù)類似,但是特別適用于在中斷服務(wù)例程(ISR)中使用。
返回pdPASS表示成功讀取到消息,返回errQUEUE_EMPTY表示隊(duì)列為空。

這些函數(shù)都是用于讀取隊(duì)列中的消息,并根據(jù)需要?jiǎng)h除消息或者保留消息。其中,xQueueReceiveFromISR()和xQueuePeekFromISR()函數(shù)專門用于在中斷服務(wù)例程中使用。這些函數(shù)將任務(wù)或中斷服務(wù)例程阻塞直到隊(duì)列中有消息可讀取。如果隊(duì)列為空,任務(wù)或中斷服務(wù)例程將進(jìn)入阻塞狀態(tài),直到隊(duì)列中有消息可讀取。返回值用于指示讀取操作是否成功。

代碼例子:

下面是一個(gè)簡(jiǎn)單的示例代碼,展示了如何使用xQueueReceive()和xQueuePeek()函數(shù)從隊(duì)列中讀取消息:

#include <stdio.h>
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"// 定義一個(gè)全局隊(duì)列
QueueHandle_t queue;// 任務(wù)函數(shù)1,向隊(duì)列中發(fā)送消息
void task1(void *pvParameters) {int msg = 100;while(1) {// 發(fā)送消息到隊(duì)列中xQueueSend(queue, &msg, 0);// 任務(wù)延時(shí)1秒vTaskDelay(pdMS_TO_TICKS(1000));}
}// 任務(wù)函數(shù)2,從隊(duì)列中讀取消息并刪除
void task2(void *pvParameters) {int receivedMsg;while(1) {// 從隊(duì)列中讀取并刪除消息if(xQueueReceive(queue, &receivedMsg, portMAX_DELAY) == pdPASS) {printf("Received message: %d\n", receivedMsg);}// 任務(wù)延時(shí)500毫秒vTaskDelay(pdMS_TO_TICKS(500));}
}int main() {// 創(chuàng)建隊(duì)列queue = xQueueCreate(5, sizeof(int));// 創(chuàng)建任務(wù)1xTaskCreate(task1, "Task 1", configMINIMAL_STACK_SIZE, NULL, 1, NULL);// 創(chuàng)建任務(wù)2xTaskCreate(task2, "Task 2", configMINIMAL_STACK_SIZE, NULL, 2, NULL);// 啟動(dòng)調(diào)度器vTaskStartScheduler();// 如果調(diào)度器啟動(dòng)失敗,則打印錯(cuò)誤信息printf("Failed to start FreeRTOS scheduler!\n");return 0;
}

在這個(gè)示例中,我們創(chuàng)建了一個(gè)全局隊(duì)列queue,然后創(chuàng)建了兩個(gè)任務(wù)task1和task2。task1任務(wù)通過xQueueSend()函數(shù)將消息發(fā)送到隊(duì)列中,而task2任務(wù)使用xQueueReceive()函數(shù)從隊(duì)列中讀取并刪除消息。每個(gè)任務(wù)都使用vTaskDelay()函數(shù)延時(shí)一定的時(shí)間,以模擬任務(wù)執(zhí)行的過程。

當(dāng)task2任務(wù)成功從隊(duì)列中讀取到消息時(shí),將打印消息內(nèi)容。這里使用了portMAX_DELAY作為阻塞時(shí)間參數(shù),表示如果隊(duì)列為空,任務(wù)將一直阻塞,直到有消息可讀取。

這個(gè)示例展示了如何使用xQueueReceive()函數(shù)從隊(duì)列中讀取消息并刪除,以及如何使用xQueueSend()函數(shù)向隊(duì)列中發(fā)送消息。實(shí)際應(yīng)用中,可以根據(jù)需要在任務(wù)中使用這些函數(shù)來實(shí)現(xiàn)消息傳遞和同步。

四、隊(duì)列入隊(duì)和出隊(duì)操作實(shí)驗(yàn)

1.實(shí)驗(yàn)?zāi)繕?biāo)

在這里插入圖片描述
這次例程我會(huì)進(jìn)行一個(gè)非常細(xì)致的講解:

2.例程

①main.c

int main(void)
{HAL_Init();                                 /* 初始化HAL庫 */sys_stm32_clock_init(360, 25, 2, 8);        /* 設(shè)置時(shí)鐘,180Mhz */delay_init(180);                            /* 延時(shí)初始化 */usart_init(115200);                         /* 串口初始化為115200 */led_init();                                 /* 初始化LED */key_init();                                 /* 初始化按鍵 */sdram_init();                               /* SRAM初始化 */lcd_init();                                 /* 初始化LCD */my_mem_init(SRAMIN);                        /* 初始化內(nèi)部?jī)?nèi)存池 */my_mem_init(SRAMEX);                        /* 初始化外部?jī)?nèi)存池 */my_mem_init(SRAMCCM);                       /* 初始化CCM內(nèi)存池 */freertos_demo();
}

除了那些裸機(jī)也用到的函數(shù)外,還有這些內(nèi)存初始化設(shè)置:
sdram_init():用于初始化SRAM(靜態(tài)隨機(jī)存取存儲(chǔ)器)。SRAM是一種高速的存儲(chǔ)器,通常用于存儲(chǔ)數(shù)據(jù)、變量或者代碼。

my_mem_init(SRAMIN):用于初始化內(nèi)部?jī)?nèi)存池。內(nèi)部?jī)?nèi)存池是指在芯片內(nèi)部的一塊存儲(chǔ)空間,用于存儲(chǔ)數(shù)據(jù)、變量或者代碼。

my_mem_init(SRAMEX):用于初始化外部?jī)?nèi)存池。外部?jī)?nèi)存池是指連接在芯片外部的一塊存儲(chǔ)空間,通常是使用外部存儲(chǔ)器(如SDRAM、NOR Flash)擴(kuò)展的存儲(chǔ)器。

my_mem_init(SRAMCCM):用于初始化CCM(Core-Coupled Memory)內(nèi)存池。CCM內(nèi)存是一種與CPU核心緊密耦合的存儲(chǔ)器,它具有低延遲和高帶寬的特點(diǎn),適用于存儲(chǔ)關(guān)鍵數(shù)據(jù)和代碼。

最重要的當(dāng)然就是freertos_demo();函數(shù)了。

②freertos_demo();


/*** @brief       FreeRTOS例程入口函數(shù)* @param       無* @retval      無*/
void freertos_demo(void)
{    /* 隊(duì)列的創(chuàng)建 */key_queue = xQueueCreate( 2, sizeof(uint8_t) );if(key_queue != NULL){printf("key_queue隊(duì)列創(chuàng)建成功!!\r\n");}else printf("key_queue隊(duì)列創(chuàng)建失敗!!\r\n");big_date_queue = xQueueCreate( 1, sizeof(char *) );if(big_date_queue != NULL){printf("big_date_queue隊(duì)列創(chuàng)建成功!!\r\n");}else printf("big_date_queue隊(duì)列創(chuàng)建失敗!!\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();
}

這是一個(gè)名為freertos_demo()的函數(shù),用于演示FreeRTOS中隊(duì)列的創(chuàng)建和任務(wù)的創(chuàng)建與調(diào)度。

key_queue = xQueueCreate(2, sizeof(uint8_t)):創(chuàng)建一個(gè)容量為2,元素大小為uint8_t的隊(duì)列,用于存儲(chǔ)按鍵值。如果隊(duì)列創(chuàng)建成功,會(huì)打印"key_queue隊(duì)列創(chuàng)建成功!!“,否則打印"key_queue隊(duì)列創(chuàng)建失敗!!”。

big_date_queue = xQueueCreate(1, sizeof(char *)):創(chuàng)建一個(gè)容量為1,元素大小為char指針的隊(duì)列,用于存儲(chǔ)大數(shù)據(jù)塊。如果隊(duì)列創(chuàng)建成功,會(huì)打印"big_date_queue隊(duì)列創(chuàng)建成功!!“,否則打印"big_date_queue隊(duì)列創(chuàng)建失敗!!”.

xTaskCreate(start_task, “start_task”, START_TASK_STACK_SIZE, NULL, START_TASK_PRIO, &start_task_handler):創(chuàng)建一個(gè)名為"start_task"的任務(wù),使用start_task()函數(shù)作為任務(wù)函數(shù)。該任務(wù)的堆棧大小為START_TASK_STACK_SIZE,優(yōu)先級(jí)為START_TASK_PRIO。任務(wù)句柄start_task_handler用于后續(xù)操作。
vTaskStartScheduler():啟動(dòng)FreeRTOS調(diào)度器,開始執(zhí)行任務(wù)。

③操作隊(duì)列和存儲(chǔ)大數(shù)據(jù)塊

QueueHandle_t key_queue;        /* 小數(shù)據(jù)句柄 */
QueueHandle_t big_date_queue;   /* 大數(shù)據(jù)句柄 */
char buff[100] = {"我是一個(gè)大數(shù)組,大大的數(shù)組 124214 uhsidhaksjhdklsadhsaklj"};

key_queue和big_date_queue是隊(duì)列的句柄(或稱為隊(duì)列的指針),用于在程序中引用這兩個(gè)隊(duì)列。key_queue是一個(gè)指向小數(shù)據(jù)隊(duì)列的句柄,big_date_queue是一個(gè)指向大數(shù)據(jù)隊(duì)列的句柄。

另外,還定義了一個(gè)名為buff的字符數(shù)組,長(zhǎng)度為100,用于存儲(chǔ)大數(shù)據(jù)塊。該數(shù)組中包含了一個(gè)字符串,表示一個(gè)大數(shù)據(jù)塊的內(nèi)容。

④任務(wù)一:實(shí)現(xiàn)入隊(duì)

在這里插入圖片描述

/* 任務(wù)一,實(shí)現(xiàn)入隊(duì) */
void task1( void * pvParameters )
{uint8_t key = 0;char * buf;BaseType_t   err = 0;buf = &buff[0]; /* buf = &buff[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隊(duì)列發(fā)送失敗\r\n");}}else if(key == WKUP_PRES){err = xQueueSend( big_date_queue, &buf, portMAX_DELAY );if(err != pdTRUE){printf("key_queue隊(duì)列發(fā)送失敗\r\n");}}vTaskDelay(10);}
}

在任務(wù)函數(shù)開始時(shí),定義了一個(gè)key變量和一個(gè)buf指針變量。buf指針指向了之前提到的buff數(shù)組的第一個(gè)元素。

在任務(wù)的主循環(huán)中,首先調(diào)用key_scan(0)函數(shù)來獲取按鍵值,并將其賦值給key變量。然后通過條件判斷,判斷按鍵值是否為KEY0_PRES或KEY1_PRES,如果是,則將key值發(fā)送到key_queue隊(duì)列中,使用xQueueSend()函數(shù)來實(shí)現(xiàn)。如果發(fā)送失敗,則打印"key_queue隊(duì)列發(fā)送失敗"。

另外,如果按鍵值為WKUP_PRES,則將buf指針發(fā)送到big_date_queue隊(duì)列中,同樣使用xQueueSend()函數(shù)來實(shí)現(xiàn)。如果發(fā)送失敗,則打印"key_queue隊(duì)列發(fā)送失敗"。

最后,通過vTaskDelay(10)函數(shù)來延時(shí)10個(gè)系統(tǒng)時(shí)鐘周期,然后繼續(xù)下一次循環(huán)。

這個(gè)任務(wù)函數(shù)的功能是根據(jù)按鍵值將數(shù)據(jù)發(fā)送到不同的隊(duì)列中,實(shí)現(xiàn)了數(shù)據(jù)入隊(duì)的操作。

⑤任務(wù)二:小數(shù)據(jù)出隊(duì)

在這里插入圖片描述


/* 任務(wù)二,小數(shù)據(jù)出隊(duì) */
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隊(duì)列讀取失敗\r\n");}else {printf("key_queue讀取隊(duì)列成功,數(shù)據(jù):%d\r\n",key);}}
}

在任務(wù)函數(shù)開始時(shí),定義了一個(gè)key變量和一個(gè)err變量。

在任務(wù)的主循環(huán)中,調(diào)用xQueueReceive()函數(shù)從key_queue隊(duì)列中接收數(shù)據(jù),并將接收到的數(shù)據(jù)保存在key變量中。使用portMAX_DELAY作為阻塞時(shí)間,表示如果隊(duì)列為空,任務(wù)將一直阻塞直到有數(shù)據(jù)可用。

接收數(shù)據(jù)后,通過條件判斷,判斷數(shù)據(jù)接收是否成功。如果接收失敗,則打印"key_queue隊(duì)列讀取失敗"。如果接收成功,則打印"key_queue讀取隊(duì)列成功,數(shù)據(jù):"并打印出接收到的key值。

這個(gè)任務(wù)函數(shù)的功能是從key_queue隊(duì)列中接收數(shù)據(jù)并進(jìn)行處理

⑥任務(wù)三:大數(shù)據(jù)出隊(duì)

在這里插入圖片描述

/* 任務(wù)三,大數(shù)據(jù)出隊(duì) */
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隊(duì)列讀取失敗\r\n");}else {printf("數(shù)據(jù):%s\r\n",buf);}}
}

根據(jù)你提供的代碼,這是一個(gè)名為task3()的任務(wù)函數(shù),用于實(shí)現(xiàn)大數(shù)據(jù)出隊(duì)操作。

在任務(wù)函數(shù)開始時(shí),定義了一個(gè)buf指針變量和一個(gè)err變量。

在任務(wù)的主循環(huán)中,調(diào)用xQueueReceive()函數(shù)從big_date_queue隊(duì)列中接收數(shù)據(jù),并將接收到的數(shù)據(jù)保存在buf指針變量中。使用portMAX_DELAY作為阻塞時(shí)間,表示如果隊(duì)列為空,任務(wù)將一直阻塞直到有數(shù)據(jù)可用。

接收數(shù)據(jù)后,通過條件判斷,判斷數(shù)據(jù)接收是否成功。如果接收失敗,則打印"big_date_queue隊(duì)列讀取失敗"。如果接收成功,則打印"數(shù)據(jù):"并打印出接收到的字符串?dāng)?shù)據(jù)。

這個(gè)任務(wù)函數(shù)的功能是從big_date_queue隊(duì)列中接收大數(shù)據(jù)塊,并進(jìn)行處理。

3.例程運(yùn)行結(jié)果:

在這里插入圖片描述

五、隊(duì)列相關(guān)API函數(shù)解析

1.隊(duì)列的創(chuàng)建API函數(shù):xQueueCreate( )

xQueueCreate()函數(shù)是一個(gè)FreeRTOS中用于創(chuàng)建隊(duì)列的API函數(shù)。它的內(nèi)部實(shí)現(xiàn)過程如下:

首先,函數(shù)會(huì)檢查傳入的隊(duì)列長(zhǎng)度和隊(duì)列元素大小是否合法。如果不合法,函數(shù)會(huì)返回NULL,表示隊(duì)列創(chuàng)建失敗。

接著,函數(shù)會(huì)為隊(duì)列分配內(nèi)存空間,包括隊(duì)列控制塊和隊(duì)列存儲(chǔ)區(qū)。隊(duì)列控制塊是一個(gè)結(jié)構(gòu)體,用于管理隊(duì)列的各種屬性和狀態(tài)信息;隊(duì)列存儲(chǔ)區(qū)是一個(gè)連續(xù)的內(nèi)存塊,用于存儲(chǔ)隊(duì)列中的元素。

然后,函數(shù)會(huì)初始化隊(duì)列控制塊的各個(gè)字段。例如,設(shè)置隊(duì)列的長(zhǎng)度、元素大小、存儲(chǔ)區(qū)的起始地址等。

接下來,函數(shù)會(huì)初始化隊(duì)列的信號(hào)量,用于實(shí)現(xiàn)隊(duì)列的同步和互斥訪問。這個(gè)信號(hào)量用于控制任務(wù)對(duì)隊(duì)列的讀取和寫入操作,確保只有一個(gè)任務(wù)在訪問隊(duì)列的時(shí)候。

最后,函數(shù)會(huì)返回創(chuàng)建的隊(duì)列的指針。如果隊(duì)列創(chuàng)建失敗,函數(shù)將返回NULL。

需要注意的是,xQueueCreate()函數(shù)只是創(chuàng)建了隊(duì)列的數(shù)據(jù)結(jié)構(gòu),并沒有分配隊(duì)列存儲(chǔ)區(qū)的內(nèi)存空間。實(shí)際的內(nèi)存分配是在調(diào)用xQueueSend()和xQueueReceive()等函數(shù)時(shí)進(jìn)行的。這是因?yàn)殛?duì)列的存儲(chǔ)區(qū)大小是根據(jù)隊(duì)列長(zhǎng)度和元素大小動(dòng)態(tài)計(jì)算的,所以需要在運(yùn)行時(shí)動(dòng)態(tài)分配內(nèi)存空間。

2.往隊(duì)列寫入數(shù)據(jù)API函數(shù)(入隊(duì)):xQueueSend( )

xQueueSend()函數(shù)是一個(gè)FreeRTOS中用于往隊(duì)列寫入數(shù)據(jù)的API函數(shù),也被稱為入隊(duì)操作。它的內(nèi)部實(shí)現(xiàn)過程如下:

首先,函數(shù)會(huì)檢查傳入的隊(duì)列指針和待寫入的數(shù)據(jù)指針是否合法。如果隊(duì)列指針或數(shù)據(jù)指針為空,函數(shù)會(huì)返回一個(gè)錯(cuò)誤碼,表示寫入操作失敗。

接著,函數(shù)會(huì)嘗試獲取隊(duì)列的信號(hào)量。這是為了確保只有一個(gè)任務(wù)在訪問隊(duì)列的時(shí)候,避免多個(gè)任務(wù)同時(shí)寫入隊(duì)列導(dǎo)致數(shù)據(jù)混亂。

如果成功獲取到隊(duì)列的信號(hào)量,函數(shù)會(huì)將待寫入的數(shù)據(jù)復(fù)制到隊(duì)列的存儲(chǔ)區(qū)中。具體的復(fù)制方式取決于隊(duì)列的類型。例如,如果是一個(gè)字節(jié)隊(duì)列,直接將數(shù)據(jù)復(fù)制到存儲(chǔ)區(qū)即可;如果是一個(gè)結(jié)構(gòu)體隊(duì)列,需要按照結(jié)構(gòu)體的大小逐個(gè)成員進(jìn)行復(fù)制。

寫入數(shù)據(jù)后,函數(shù)會(huì)更新隊(duì)列的相關(guān)屬性,例如隊(duì)列中的元素?cái)?shù)量、讀取和寫入指針等。

最后,函數(shù)會(huì)釋放隊(duì)列的信號(hào)量,表示寫入操作完成。

需要注意的是,xQueueSend()函數(shù)在寫入數(shù)據(jù)時(shí),有兩種寫入模式可以選擇:阻塞模式和非阻塞模式。在阻塞模式下,如果隊(duì)列已滿,寫入操作將會(huì)阻塞當(dāng)前任務(wù),直到隊(duì)列有空閑位置可寫入;在非阻塞模式下,如果隊(duì)列已滿,寫入操作將會(huì)立即返回一個(gè)錯(cuò)誤碼,表示寫入操作失敗。這種模式由函數(shù)調(diào)用時(shí)傳入的阻塞時(shí)間參數(shù)決定。

3.從隊(duì)列讀取數(shù)據(jù)API函數(shù)(出隊(duì)): xQueueReceive( )

xQueueReceive()函數(shù)是一個(gè)FreeRTOS中用于從隊(duì)列讀取數(shù)據(jù)的API函數(shù),也被稱為出隊(duì)操作。它的內(nèi)部實(shí)現(xiàn)過程如下:

首先,函數(shù)會(huì)檢查傳入的隊(duì)列指針和接收數(shù)據(jù)的指針是否合法。如果隊(duì)列指針或接收數(shù)據(jù)的指針為空,函數(shù)會(huì)返回一個(gè)錯(cuò)誤碼,表示讀取操作失敗。

接著,函數(shù)會(huì)嘗試獲取隊(duì)列的信號(hào)量。這是為了確保只有一個(gè)任務(wù)在訪問隊(duì)列的時(shí)候,避免多個(gè)任務(wù)同時(shí)讀取隊(duì)列導(dǎo)致數(shù)據(jù)混亂。

如果成功獲取到隊(duì)列的信號(hào)量,函數(shù)會(huì)從隊(duì)列的存儲(chǔ)區(qū)中讀取數(shù)據(jù),并將讀取到的數(shù)據(jù)復(fù)制到接收數(shù)據(jù)的指針中。具體的復(fù)制方式取決于隊(duì)列的類型。例如,如果是一個(gè)字節(jié)隊(duì)列,直接從存儲(chǔ)區(qū)中讀取數(shù)據(jù)即可;如果是一個(gè)結(jié)構(gòu)體隊(duì)列,需要按照結(jié)構(gòu)體的大小逐個(gè)成員進(jìn)行復(fù)制。

讀取數(shù)據(jù)后,函數(shù)會(huì)更新隊(duì)列的相關(guān)屬性,例如隊(duì)列中的元素?cái)?shù)量、讀取和寫入指針等。

最后,函數(shù)會(huì)釋放隊(duì)列的信號(hào)量,表示讀取操作完成。

需要注意的是,xQueueReceive()函數(shù)在讀取數(shù)據(jù)時(shí),有兩種讀取模式可以選擇:阻塞模式和非阻塞模式。在阻塞模式下,如果隊(duì)列為空,讀取操作將會(huì)阻塞當(dāng)前任務(wù),直到隊(duì)列有數(shù)據(jù)可讀取;在非阻塞模式下,如果隊(duì)列為空,讀取操作將會(huì)立即返回一個(gè)錯(cuò)誤碼,表示讀取操作失敗。這種模式由函數(shù)調(diào)用時(shí)傳入的阻塞時(shí)間參數(shù)決定。

http://www.risenshineclean.com/news/34632.html

相關(guān)文章:

  • 想做淘寶 網(wǎng)站怎么做電商培訓(xùn)機(jī)構(gòu)推薦
  • 怎么做貨物收發(fā)的網(wǎng)站網(wǎng)站銷售怎么推廣
  • 龍崗 網(wǎng)站建設(shè)深圳信科青島seo結(jié)算
  • 企業(yè)網(wǎng)絡(luò)營(yíng)銷企業(yè)網(wǎng)站建設(shè)章節(jié)習(xí)題營(yíng)銷網(wǎng)頁設(shè)計(jì)公司
  • gbk網(wǎng)站轉(zhuǎn)utf8千牛怎么做免費(fèi)推廣引流
  • 關(guān)于網(wǎng)站建設(shè)的專家研討會(huì)品牌型網(wǎng)站設(shè)計(jì)推薦
  • 創(chuàng)意網(wǎng)站推薦網(wǎng)站開發(fā)
  • 借貸網(wǎng)站開發(fā)是否合法寧波seo外包服務(wù)
  • 15 企業(yè)網(wǎng)站優(yōu)化方案有哪些內(nèi)容sem什么意思
  • 做食品那些網(wǎng)站百度提交入口網(wǎng)站
  • 閱文集團(tuán)旗下哪個(gè)網(wǎng)站做的最好seo培訓(xùn)一對(duì)一
  • 企業(yè)網(wǎng)盤怎么下載文件seo是什么服
  • 網(wǎng)站設(shè)計(jì) 重慶seoul是啥意思
  • 嵐山網(wǎng)站建設(shè)報(bào)價(jià)老鐵外鏈
  • 微網(wǎng)站建設(shè)使用程序西安關(guān)鍵詞排名首頁
  • 門戶網(wǎng)站概念網(wǎng)絡(luò)營(yíng)銷推廣服務(wù)
  • 怎樣做類似淘寶網(wǎng)的網(wǎng)站汕頭網(wǎng)站優(yōu)化
  • 用html編寫淘寶網(wǎng)站怎么做seo友情鏈接
  • 漢子由來 外國(guó)人做的網(wǎng)站網(wǎng)站建設(shè)公司服務(wù)
  • 南和網(wǎng)站建設(shè)公司網(wǎng)絡(luò)推廣費(fèi)用計(jì)入什么科目
  • 程序開源網(wǎng)站關(guān)鍵詞列表
  • 新手學(xué)易語言多久可以做網(wǎng)站中國(guó)優(yōu)秀網(wǎng)頁設(shè)計(jì)案例
  • 本地旅游網(wǎng)站模版網(wǎng)絡(luò)營(yíng)銷網(wǎng)站推廣方法
  • 做公司網(wǎng)站多少錢站長(zhǎng)工具在線查詢
  • 網(wǎng)站背景色最新天氣預(yù)報(bào)最新消息
  • 如何做網(wǎng)站刷題西安網(wǎng)站建設(shè)
  • 做企業(yè)網(wǎng)站的架構(gòu)圖廣州王牌seo
  • 公司做網(wǎng)站流程關(guān)鍵詞挖掘工具愛網(wǎng)
  • 菲律賓有做網(wǎng)站的嗎seo優(yōu)化是做什么的
  • 安卓手機(jī) 做網(wǎng)站湘潭seo優(yōu)化