STM32---FreeRTOS消息隊列

一、簡介

1、隊列簡介:

隊列:是任務到任務,任務到中斷、中斷到任務數據交流的一種機制(消息傳遞)。

?FreeRTOS基于隊列,實現了多種功能,其中包括隊列集、互斥信號量、計數型信號量、二值信號量、遞歸互斥信號量,因此很有必要深入了解FreeRTOS的隊列。

(中斷一關閉,就不會出現任務切換,以防多個任務同時操作隊列)?

2、FreeRTOS隊列特點:

????????????????????????1.數據入隊出隊方式:先進先出

????????????????????????2.數據傳遞方式:實際值

????????????????????????3.多任務訪問

????????????????????????4. 出隊、入隊堵塞

問題:當多個任務寫入消息給一個“滿隊列”時,這些任務都會進入阻塞狀態,也就是說有多個任務?? ? ?在等待同一 個隊列的空間。那當隊列中有空間時,哪個任務會進入就緒態??

答: ?? ?1、優先級最高的任務 ?? ?2、如果大家的優先級相同,那等待時間最久的任務會進入就緒態?

注:我始終認為自己不是一個很聰明的人,所以這些理論知識,我都是淺嘗輒止,量力而行。

3、往隊列寫入消息API函數 :

4、從隊列讀取消息API函數:?

?二、實驗

1、實驗步驟

2、代碼:?

main.c

#include "stm32f10x.h"
#include "FreeRTOS.h"
#include "task.h"
#include "freertos_demo.h"
#include "Delay.h"
#include "sys.h"
#include "usart.h"
#include "LED.h"
#include "Key.h"int main(void){	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//設置系統中斷優先級分組 4 uart_init(115200);	 delay_init();Key_Init();LED_Init();// 創建任務FrrrRTOS_Demo();}

freertos_demo.c?

#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "LED.h"
#include "Key.h"
#include "usart.h"
#include "delay.h"/******************************************************************任務配置****************************************************/
//任務優先級
#define START_TASK_PRIO					1
//任務堆棧大小	
#define START_TASK_STACK_SIZE 	128  
//任務句柄
TaskHandle_t StartTask_Handler;
//任務函數
void start_task(void *pvParameters);//任務優先級
#define TASK1_PRIO							2
//任務堆棧大小	
#define TASK1_STACK_SIZE 				128  
//任務句柄
TaskHandle_t Task1_Handler;
//任務函數
void task1(void *pvParameters);//任務優先級
#define TASK2_PRIO							3
//任務堆棧大小	
#define TASK2_STACK_SIZE 				128  
//任務句柄
TaskHandle_t Task2_Handler;
//任務函數
void task2(void *pvParameters);//任務優先級
#define TASK3_PRIO							4
//任務堆棧大小	
#define TASK3_STACK_SIZE 				128  
//任務句柄
TaskHandle_t Task3_Handler;
//任務函數
void task3(void *pvParameters);char  task_buffer[500]; 							//用于存儲系統中任務信息表格/******************************************************************任務函數****************************************************/
QueueHandle_t		key_queue; 						//小數據句柄
QueueHandle_t		big_data_queue; 			//大數據	句柄
char buff[100] = {"蒼天已死,黃天當立;歲在甲子,天下大吉"};
void FrrrRTOS_Demo(void)
{key_queue = xQueueCreate(2, sizeof(uint8_t));if(key_queue != NULL){printf("\r\nkey_queue隊列創建成功!!!\r\n");}else{ printf("key_queue隊列創建失敗!!!\r\n");	}big_data_queue = xQueueCreate(1, sizeof(char *));if(big_data_queue != NULL){printf("big_data_queue隊列創建成功!!!\r\n");}else{ printf("big_data_queue隊列創建失敗!!!\r\n");	}//創建開始任務xTaskCreate((TaskFunction_t )start_task,            			//任務函數( char*         )"start_task",          			//任務名稱(uint16_t       )START_TASK_STACK_SIZE, 			//任務堆棧大小(void*          )NULL,                  			//傳遞給任務函數的參數(UBaseType_t    )START_TASK_PRIO,       			//任務優先級(TaskHandle_t*  )&StartTask_Handler);   			//任務句柄 // 啟動任務調度vTaskStartScheduler();}void start_task(void *pvParameters)
{taskENTER_CRITICAL();           //進入臨界區//創建1任務xTaskCreate((TaskFunction_t )task1,     	(const char*    )"task1",   	(uint16_t       )TASK1_STACK_SIZE, (void*          )NULL,				(UBaseType_t    )TASK1_PRIO,	(TaskHandle_t*  )&Task1_Handler); //創建2任務xTaskCreate((TaskFunction_t )task2,     (const char*    )"task2",   (uint16_t       )TASK2_STACK_SIZE, (void*          )NULL,(UBaseType_t    )TASK2_PRIO,(TaskHandle_t*  )&Task2_Handler);    //創建3任務xTaskCreate((TaskFunction_t )task3,     (const char*    )"task3",   (uint16_t       )TASK3_STACK_SIZE, (void*          )NULL,(UBaseType_t    )TASK3_PRIO,(TaskHandle_t*  )&Task3_Handler);  								vTaskDelete(NULL); 							//刪除開始任務taskEXIT_CRITICAL();            //退出臨界區
}//1 任務函數
void task1(void *pvParameters)
{uint8_t 	 key = 0;BaseType_t err;char *buf;buf = &buff[0];while(1){key = Key_GetNum();if(key == 1 || key == 2){err = xQueueSend( key_queue, &key, portMAX_DELAY );if(err != pdTRUE){printf("key_queue隊列發送失敗\r\n");}}else if(key == 3){err = xQueueSend( big_data_queue, &buf, portMAX_DELAY );if(err != pdTRUE){printf("key_queue隊列發送失敗\r\n");}}vTaskDelay(50);}
}// 任務2 小數據出隊函數
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 = %d\r\n",key);};}
}//不調用系統延時函數,因為xQueueReceive()函數如果讀取完隊列里面的數據,就會由就緒態轉變為阻塞態;// 任務3 大數據出隊函數
void task3(void *pvParameters)
{	char *    buf;BaseType_t err = 0;// 任務主循環while (1){err = xQueueReceive( big_data_queue, &buf, portMAX_DELAY);if(err != pdTRUE){printf("big_data_queue隊列讀取失敗\r\n");		}else{printf("key = %s\r\n",buf);};}
}

?key.c

#include "stm32f10x.h"                  // Device header
#include "FreeRTOS.h"
#include "task.h"
#include "usart.h"
#include "Delay.h"/*** 函    數:按鍵初始化* 參    數:無* 返 回 值:無* 按鍵:PB4/PB12/PB14*/
void Key_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure;/*開啟時鐘*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);		//開啟GPIOB的時鐘/*GPIO初始化*/GPIO_InitStructure.GPIO_Mode 	= GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin 	= GPIO_Pin_4 | GPIO_Pin_12 | GPIO_Pin_14;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);					}/*** 函    數:按鍵獲取鍵碼* 參    數:無* 返 回 值:按下按鍵的鍵碼值,范圍:0~3,返回0代表沒有按鍵按下* 注意事項:此函數是阻塞式操作,當按鍵按住不放時,函數會卡住,直到按鍵松手*/
uint8_t Key_GetNum(void)
{uint8_t KeyNum = 0;																				//定義變量,默認鍵碼值為0if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_4) == 0)			  //讀PB4輸入寄存器的狀態,如果為0,則代表按鍵1按下{KeyNum= GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_4);printf("KeyNum = %d\r\n",KeyNum);delay_xms(20);																					//延時消抖while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_4) == 0);	//等待按鍵松手delay_xms(20);																					//延時消抖KeyNum = 1;																							//置鍵碼為1}if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12) == 0)			{KeyNum= GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12);printf("KeyNum = %d\r\n",KeyNum);delay_xms(20);											while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12) == 0);	delay_xms(20);									KeyNum = 2;											}if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14) == 0)			{KeyNum= GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14);printf("KeyNum = %d\r\n",KeyNum);delay_xms(20);											while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14) == 0);	delay_xms(20);									KeyNum = 3;											}return KeyNum;																						//返回鍵碼值,如果沒有按鍵按下,所有if都不成立,則鍵碼為默認值0
}

?3、實驗結果解析

開始運行:

按下按鍵1(PB4):

按下按鍵1,就會往隊列key_queue里面寫入key值(1),然后任務切換到task2將隊列key_queue里面的數據讀取出來;;

按下按鍵2(PB12):

按下按鍵2,就會往隊列key_queue里面寫入key值(2),然后任務切換到task2將隊列key_queue里面的數據讀取出來;

按下按鍵3(PB14) :

按下按鍵2,就會往隊列big_data_queue里面寫入key值(3),然后任務切換到task3將隊列big_data_queue里面的數據讀取出來;

三、重點?

使用隊列相關函數時需要將下面宏置1(默認是1):

? ? #define configSUPPORT_DYNAMIC_ALLOCATION ? ?1

?隊列創建函數:

xQueueCreate( uxQueueLength, uxItemSize ) ;? ? ? ? ? ? ? ?//uxQueueLength:隊列長度;uxItemSize 隊列參數的大小

隊列寫入消息函數:

xQueueSend( xQueue, pvItemToQueue, xTicksToWait );? ? ? ? //xQueue:待寫入的隊列;pvItemToQueue:待寫入的消息;xTicksToWait:阻塞超時時間

隊列讀取消息函數:

xQueueReceive( QueueHandle_t xQueue,void * const pvBuffer,TickType_t xTicksToWait )?;? ? ? ? ??//xQueue:待讀取的隊列;pvBuffer:信息讀取緩沖區;xTicksToWait:阻塞超時時間

問題:任務2(task2)和任務3(task3)沒有系統延時函數(xTaskDelay()),按優先級來說應該一直執行任務3(task3),復位后卻先執行了任務1(task1)?

答:因為xQueueReceive()和xQueueSend()函數,如果讀取完或寫入完隊列里面的數據,自動會使任務由就緒態轉變為阻塞態,知道隊列里面有數據可以寫入或者讀出;

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

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

相關文章

2025年了,5G還有三個新變化

最近輿論開始討論5G為什么不火了?5G是不是停滯發展了。 實際上,5G不僅在發展,還迎來了它的升級版5G-A。 在今年西班牙舉行的世界移動通信大會上,5G-A就是焦點之一。 被譽為全球通信領域風向標的MWC,匯聚了華為、中興通…

SQLMesh SCD-2 時間維度實戰:餐飲菜單價格演化追蹤

場景背景:動態菜單價格管理 考慮某連鎖餐廳的菜單管理系統,需要記錄食品價格的歷史變更軌跡。業務需求包括: 記錄每次價格調整的時間點支持歷史價格查詢(如"2020年1月2日漢堡多少錢")維護當前有效價格清單…

失物招領|校園失物招領系統|基于Springboot的校園失物招領系統設計與實現(源碼+數據庫+文檔)

校園失物招領系統目錄 目錄 基于Springboot的校園失物招領系統設計與實現 一、前言 二、系統功能設計 三、系統實現 1、 管理員功能實現 (1) 失物招領管理 (2) 尋物啟事管理 (3) 公告管理 (4) 公告類型管理 2、用戶功能實現 (1) 失物招領 (2) 尋物啟事 (3) 公告 …

基于BClinux8部署Ceph 19.2(squid)集群

#作者&#xff1a;閆乾苓 文章目錄 1.版本選擇Ceph版本發布歷史目前官方在維護的版本 2.部署方法3.服務器規劃4.前置配置4.1系統更新4.2配置hosts cat >> /etc/hosts << EOFssh-keygenssh-copy-id ceph01ssh-copy-id ceph02ssh-copy-id ceph034.5 Python34.6 Syst…

安裝React開發者工具

我們在說組件之前&#xff0c;需要先安裝一下React官方推出的開發者工具&#xff0c;首先我們分享在線安裝方式 首先打開谷歌網上應用商店(針對谷歌瀏覽器)&#xff0c;在輸入框內搜索react&#xff0c;安裝如下插件&#xff1a; 注意安裝提供方為Facebook的插件&#xff0c;這…

linux中如何修改文件的權限和擁有者所屬組

目錄標題 chmod指令八進制形式權限修改文件擁有者所屬組的修改umask有關內容 chmod指令 chmod指令可以用來修改人員的權限其形式如下&#xff1a; u代表的是擁有者&#xff0c;g代表的是所屬組&#xff0c;o代表的是其他人&#xff0c;a表示所有人&#xff0c;如果你想增加權…

三主熱備架構

1.要求 角色主機名軟件IP地址用戶client192.168.72.90keepalivedvip192.168.72.100masterserverAkeepalived, nginx192.168.72.30backupserverBkeepalived, nginx192.168.72.31backupserverCkeepalived, nginx192.168.72.32webtomcat1tomcat192.168.72.41webtomcat2tomcat192.1…

windows 10 系統配置Node

目錄 什么是Node.js 什么是Npm Node.js環境搭建 下載 解壓 配置環境變量 npm配置 如何運行下載的Node.js項目 什么是Node.js 在 Node.js 之前&#xff0c;JavaScript 只能運行在瀏覽器中&#xff0c;作為網頁腳本使用&#xff0c;為網頁添加一些特效&#xff0c;或者和…

Windows Server 2025 使用 IIS 搭建 ASP.NET 3.5 網站

開啟遠程桌面 參考文章Windows server開啟遠程桌面教程打開服務管理器。ECS 配置安全組&#xff0c;開啟 3389Telnet 驗證網絡聯通性 telnet x.x.x.x 338安裝 Windows App&#xff0c;登錄驗證 安裝 ASP.NET 3.5 1.參考文章Windows Server 2012安裝 .NET Framework 3.5和 Wi…

開源模型應用落地-shieldgemma-2-4b-it模型小試-多模態內容安全檢測(一)

一、前言 在人工智能迅速發展的過程中,內容安全成為AI應用中的一個重要挑戰。谷歌團隊于2025年3月推出了一款名為ShieldGemma-2-4B-IT的模型,它以創新的多模態安全檢測能力,為行業樹立了新的開源責任AI標準。 與早期的僅支持文本審核的版本相比,ShieldGemma-2-4B-IT在谷歌的…

【數據預測】基于遺傳算法GA的LSTM光伏功率預測 GA-LSTM光伏功率預測【Matlab代碼#91】

文章目錄 【可更換其他算法&#xff0c;獲取資源請見文章第6節&#xff1a;資源獲取】1. 遺傳算法GA2. 長短期記憶網絡LSTM3. 基于GA-LSTM的光伏功率預測4. 部分代碼展示5. 運行結果展示6. 資源獲取 【可更換其他算法&#xff0c;獲取資源請見文章第6節&#xff1a;資源獲取】 …

openEuler24.03 LTS下安裝Hadoop3完全分布式

目錄 Linux準備 openEuler24.03 LTS簡介 下載openEuler24.03 LTS 安裝openEuler24.03 LTS Linux基本設置 關閉及禁用防火墻 修改主機名 靜態ip 映射主機名 創建普通用戶 目錄準備 克隆主機 配置機器之間免密登錄 編寫分發腳本 安裝Java 下載Java 解壓 設置環…

【Linux之Shell腳本實戰】Linux服務器輸出美觀漂亮的html巡檢報告

【Linux之Shell腳本實戰】Linux服務器輸出美觀漂亮的html巡檢報告 一、Shell腳本介紹1.1 Shell腳本簡介1.2 Shell腳本特點二、腳本要求三、檢查本地環境3.1 本地環境規劃3.2 檢查本地系統3.3 檢查系統內核版本四、編輯腳本五、執行及測試腳本5.1設置定時任務5.2 執行效果六、總…

坦克大戰(c++)

今天我給大家分享一個c游戲。 廢話不多說&#xff0c;作品展示&#xff1a; #include <stdio.h> #include <windows.h> #include <time.h> //里規格&#xff1a;長39*278 &#xff08;真坐標&#xff09;(假坐標寬為39) 高39 //外規格&#xff1a;長…

node-ddk, electron組件, 自定義本地文件協議,打開本地文件

node-ddk 文件協議 https://blog.csdn.net/eli960/article/details/146207062 也可以下載demo直接演示 http://linuxmail.cn/go#node-ddk 安全 考慮到安全, 本系統禁止使用 file:/// 在主窗口, 自定義文件協議,可以多個 import main, { NODEDDK } from "node-ddk/m…

論文閱讀:2023 arxiv Provable Robust Watermarking for AI-Generated Text

總目錄 大模型安全相關研究:https://blog.csdn.net/WhiffeYF/article/details/142132328 Provable Robust Watermarking for AI-Generated Text https://arxiv.org/pdf/2306.17439 https://github.com/XuandongZhao/Unigram-Watermark https://www.doubao.com/chat/211092…

一條sql語句在mysql中的執行流程(Mysql基礎架構)

mysql基礎架構 MySQL 主要分為 Server 層和 存儲引擎層&#xff1a; Server 層&#xff1a;主要包括 連接器、查詢緩存、分析器、優化器、執行器等&#xff0c;所有跨存儲引擎的功能都在這一層實現&#xff0c;比如存儲過程、觸發器、視圖&#xff0c;函數等&#xff0c;還有一…

GitLens with `Commit Graph`

文章目錄 GitLens with Commit Graph GitLens with Commit Graph 想要更直觀地查看 Git 提交歷史&#xff1f;我打包了一個支持 Commit Graph 的 GitLens 版本&#xff0c;讓你輕松在 VSCode 中查看分支、合并、變更記錄等內容&#xff0c;一目了然&#xff01; &#x1f4cc…

C#里使用libxl的數字格式

由于EXCEL里可以表示不同的數字格式, 比如表示貨幣數字時,與表示普通序號的數字就不一樣。 還有科學計算表示的數字使用小數點位數與普通貨幣也不一樣。 如下所示: 要使用這些格式, 下面創建一個例子來演示保存這些數字格式: private void button11_Click(object send…

CentOS 7擴容 /dev/shm

在 CentOS 7 中&#xff0c;/dev/shm 是基于內存的臨時文件系統&#xff08;tmpfs&#xff09;&#xff0c;其大小通常為系統內存的一半。要擴容 /dev/shm&#xff0c;可以通過重新掛載 tmpfs 并指定新的大小來實現。 擴容步驟 查看當前 /dev/shm 的大小&#xff1a; df -h /d…