FreeRTOS的任務優先級、Tick以及狀態講解(尊敬的嵌入式工程師,不妨進來喝杯茶)

任務優先級和Tick

????????在FreeRTOS中,任務的優先級和Tick是兩個關鍵的概念,它們直接影響任務的調度和執行。

任務優先級

????????每個任務都被分配一個優先級,用于決定任務在系統中的調度順序。

????????優先級是一個無符號整數,通常從0開始,數值越小,優先級越高。最高優先級是0,最低是configMAX_PRIORITIES - 1。

????????優先級的取值范圍是:0~(configMAX_PRIORITIES – 1),數值越大優先級越高。

????????FreeRTOS的調度器可以使用2種方法來快速找出優先級最高的、可以運行的任務。使用不同的方法時,configMAX_PRIORITIES 的取值有所不同。

(1)通用方法
????????使用C函數實現,對所有的架構都是同樣的代碼。對configMAX_PRIORITIES的取值沒有限制。但是configMAX_PRIORITIES的取值還是盡量小,因為取值越大越浪費內存,也浪費時間。configUSE_PORT_OPTIMISED_TASK_SELECTION被定義為0、或者未定義時,使用此方法。
(2)架構相關的優化的方法
????????架構相關的匯編指令,可以從一個32位的數里快速地找出為1的最高位。使用這些指令,可以快速找出優先級最高的、可以運行的任務。使用這種方法時,configMAX_PRIORITIES的取值不能超過32。configUSE_PORT_OPTIMISED_TASK_SELECTION被定義為1時,使用此方法。

????????在FreeRTOS中,優先級為0的任務是IDLE任務,用于在沒有其他任務執行時占用CPU。

????????任務的創建時通過指定參數設置任務的優先級,如下所示:

xTaskCreate(vTask1, "Task1", configMINIMAL_STACK_SIZE, NULL, 1, &Task1_Handle);

Tick

????????Tick是FreeRTOS內核用于計時和任務調度的基本時間單元。

????????FreeRTOS通過硬件定時器或者軟件定時器,每隔一定時間(即Tick間隔)產生一次中斷。

????????Tick的間隔由configTICK_RATE_HZ定義,它表示每秒鐘產生的Tick數。

關系

????????任務的調度是基于優先級的,具有更高優先級的任務將在具有較低優先級的任務之前執行。

????????Tick間隔決定了系統時鐘的精度,同時也影響了任務的延時和時間控制。

????????任務在等待一定時間或進行延時時,使用vTaskDelay()等函數,參數是以Tick為單位的時間。

vTaskDelay(100 / portTICK_PERIOD_MS); // 暫停任務100ms

????????任務的優先級和Tick的概念結合在一起,形成了FreeRTOS中任務調度和時間控制的基礎。通過調整任務的優先級和配置Tick的間隔,可以靈活地控制系統中任務的執行順序和時間行為。

????????以下是一個基于FreeRTOS的STM32F103芯片的簡單優先級實驗案例代碼。該例子創建了兩個任務,分別以不同的優先級運行,以演示優先級如何影響任務的調度。

#include "stm32f1xx.h"
#include "FreeRTOS.h"
#include "task.h"// 函數原型
void SystemClock_Config(void);
static void MX_GPIO_Init(void);// 任務函數
TaskHandle_t Task1_Handle, Task2_Handle;void vTask1(void *pvParameters) {while (1) {// 任務1的處理邏輯HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13); // 切換LED狀態vTaskDelay(1000 / portTICK_PERIOD_MS); // 每隔1秒執行一次}
}void vTask2(void *pvParameters) {while (1) {// 任務2的處理邏輯vTaskDelay(2000 / portTICK_PERIOD_MS); // 每隔2秒執行一次}
}int main(void) {// 硬件初始化HAL_Init();SystemClock_Config();MX_GPIO_Init();// 創建任務1(優先級1)xTaskCreate(vTask1, "Task1", configMINIMAL_STACK_SIZE, NULL, 1, &Task1_Handle);// 創建任務2(優先級2)xTaskCreate(vTask2, "Task2", configMINIMAL_STACK_SIZE, NULL, 2, &Task2_Handle);// 啟動調度器vTaskStartScheduler();// 代碼不應該運行到這里,如果運行到這里說明發生了錯誤while (1) {// 處理錯誤}
}// 系統時鐘配置
void SystemClock_Config(void) {
}// GPIO初始化
static void MX_GPIO_Init(void) {
}

????????在這個例子中,任務1和任務2分別在不同的時間間隔內切換LED的狀態。任務1的優先級較高,它每隔1秒執行一次,而任務2的優先級較低,它每隔2秒執行一次。

任務狀態

????????在FreeRTOS中,較高優先級的任務將優先于較低優先級的任務執行。任務優先級是通過任務創建時指定的參數來設置的(在xTaskCreate函數的第5個參數)。在這個案例中,任務1的優先級為1,任務2的優先級為2。

????????FreeRTOS中的任務可以處于不同的狀態,這些狀態反映了任務在系統中的執行階段。任務的狀態是通過eTaskState枚舉類型表示的,定義在task.h頭文件中。以下是任務可能的狀態:

????????eRunning(運行中): 任務正在執行。這是任務處于活動狀態的時候。

????????eReady(就緒): 任務已經準備好執行,但由于有其他高優先級任務在運行,該任務暫時沒有被調度。

????????eBlocked(阻塞): 任務由于等待某些事件而被阻塞,例如等待定時器、消息隊列、信號量等。

????????eSuspended(掛起): 任務被顯式地掛起,不再參與調度。

????????eDeleted(已刪除): 任務已被刪除,但其資源尚未被釋放。

????????eInvalid(無效): 無效狀態,通常用于表示錯誤或未知狀態。

你可以使用eTaskGetState函數來獲取任務的當前狀態。以下是一個示例代碼:

#include "FreeRTOS.h"
#include "task.h"TaskHandle_t xTaskHandle;void vTaskFunction(void *pvParameters) {while (1) {// 任務的處理邏輯}
}int main(void) {// 創建任務xTaskCreate(vTaskFunction, "Task", configMINIMAL_STACK_SIZE, NULL, 1, &xTaskHandle);// 啟動調度器vTaskStartScheduler();// 代碼不應該運行到這里,如果運行到這里說明發生了錯誤while (1) {// 處理錯誤}
}void vApplicationIdleHook(void) {// 空閑鉤子函數eTaskState taskState = eTaskGetState(xTaskHandle);switch (taskState) {case eRunning:// 任務正在運行break;case eReady:// 任務就緒break;case eBlocked:// 任務被阻塞break;case eSuspended:// 任務被掛起break;case eDeleted:// 任務已刪除break;case eInvalid:// 無效狀態break;}
}

????????在這個例子中,vApplicationIdleHook是一個空閑鉤子函數,用于在系統空閑時檢查任務的狀態。函數eTaskGetState返回任務的當前狀態,然后可以根據任務的狀態進行相應的處理。

阻塞狀態(Blocked State)

????????在FreeRTOS中,任務的阻塞狀態(Blocked State)表示任務由于等待某些事件而無法執行。任務可以因為多種原因而被阻塞,包括等待定時器、等待消息隊列、等待信號量等。當任務處于阻塞狀態時,它將不會被調度執行,直到滿足了其阻塞條件。

????????以下是幾個常見的阻塞狀態的示例:

????????等待定時器:

// 創建定時器
TimerHandle_t xTimer = xTimerCreate("MyTimer", pdMS_TO_TICKS(1000), pdTRUE, 0, vTimerCallback);// 啟動定時器,在任務中使用xTimerPendFunctionCallFromISR等函數
xTimerStart(xTimer, 0);

????????在任務中可能會使用xTimerPendFunctionCallFromISR等函數等待定時器的超時事件。

????????等待消息隊列:

// 創建消息隊列
QueueHandle_t xQueue = xQueueCreate(5, sizeof(int));// 在任務中等待消息隊列
xQueueReceive(xQueue, &data, portMAX_DELAY);

????????任務通過xQueueReceive函數等待消息隊列中的消息,如果隊列為空,任務將被阻塞,直到隊列中有數據。

????????等待信號量:

// 創建信號量
SemaphoreHandle_t xSemaphore = xSemaphoreCreateBinary();// 在任務中等待信號量
xSemaphoreTake(xSemaphore, portMAX_DELAY);

????????任務通過xSemaphoreTake函數等待信號量,如果信號量被其他任務取得,當前任務將被阻塞,直到信號量可用。

????????在上述示例中,portMAX_DELAY表示任務將一直等待,直到滿足其阻塞條件為止。任務也可以使用超時值來設置阻塞的最大等待時間。一旦阻塞條件得到滿足,任務將被置為就緒狀態,等待調度器調度執行。

暫停狀態(Suspended State)

????????在FreeRTOS中,任務的暫停狀態(Suspended State)表示任務被顯式地掛起,使得該任務不再參與調度,即不會被執行。任務在創建后可以通過調用vTaskSuspend()函數將其掛起,然后通過調用vTaskResume()函數將其恢復執行。

以下是一個簡單的示例代碼,演示了任務的暫停和恢復:

#include "FreeRTOS.h"
#include "task.h"TaskHandle_t xTaskHandle;void vTaskFunction(void *pvParameters) {while (1) {// 任務的處理邏輯}
}int main(void) {// 創建任務xTaskCreate(vTaskFunction, "Task", configMINIMAL_STACK_SIZE, NULL, 1, &xTaskHandle);// 啟動調度器vTaskStartScheduler();// 代碼不應該運行到這里,如果運行到這里說明發生了錯誤while (1) {// 處理錯誤}
}// 在某個事件或條件下掛起任務
void vSuspendTask(void) {vTaskSuspend(xTaskHandle);
}// 在某個事件或條件下恢復任務
void vResumeTask(void) {vTaskResume(xTaskHandle);
}

????????在這個例子中,vTaskSuspend()函數用于掛起任務,vTaskResume()函數用于恢復任務。通常,這樣的操作可以用于在某些條件滿足或事件發生時掛起任務,然后在其他條件下恢復任務的執行。

????????需要注意的是,掛起任務不會立即停止任務的執行,而是在任務下一次被調度執行時生效。此外,掛起任務并不會釋放任務所占用的資源,因此在使用這些函數時需要謹慎,以免引起資源泄漏。

就緒狀態(Ready)

????????在FreeRTOS中,任務的就緒狀態(Ready State)表示任務已經準備好被調度執行,但由于有其他高優先級的任務正在運行,該任務暫時還未被調度。

????????在FreeRTOS中,任務被創建后,它的狀態一開始就是就緒狀態,等待調度器來選擇合適的時機執行它。任務的就緒狀態可以由以下幾種情況觸發:

????????任務創建: 任務被創建后,會進入就緒狀態,等待調度執行。

xTaskCreate(vTaskFunction, "Task", configMINIMAL_STACK_SIZE, NULL, 1, &xTaskHandle);

????????任務掛起狀態解除: 任務從掛起狀態(Suspended State)被恢復后,會進入就緒狀態。

vTaskResume(xTaskHandle);

????????等待事件結束: 任務等待某個事件的發生,一旦事件發生,任務從阻塞狀態切換到就緒狀態。

xSemaphoreTake(xSemaphore, portMAX_DELAY);

????????任務等待定時器超時: 任務等待一個定時器超時,一旦超時,任務從阻塞狀態切換到就緒狀態。

xTaskDelay(1000 / portTICK_PERIOD_MS);

????????在以上例子中,xTaskCreate創建了一個任務,vTaskResume恢復了一個掛起的任務,xSemaphoreTake和xTaskDelay是任務等待事件或超時的示例。

????????任務的就緒狀態是由FreeRTOS調度器根據任務的優先級和調度算法來決定的。當調度器判定某個任務處于就緒狀態時,該任務將會被調度器選中,并執行相應的任務函數。

任務狀態轉換圖

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

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

相關文章

Mysql- 流程函數-(If, CASE WHEN)的使用及練習

目錄 4.1 If函數語法格式 4.2 CASE WHEN 條件表達式格式 4.3 update與 case when 4.4 練習題1 4.5 練習題2 4.6 練習題3-行轉列 4.7 牛客練習題 4.8 LeetCode練習題 4.1 If函數語法格式 IF(expr1,expr2,expr3) 解釋&#xff1a; 如果表達式expr1true(expr1 <>…

力扣第 119 場雙周賽(Java)

文章目錄 T1 找到兩個數組中的公共元素代碼解釋 T2 消除相鄰近似相等字符代碼解釋 T3 最多 K 個重復元素的最長子數組代碼解釋 T4 關閉分部的可行集合數目代碼解釋 鏈接&#xff1a;第 119 場雙周賽 - 力扣&#xff08;LeetCode&#xff09; T1 找到兩個數組中的公共元素 給你…

Xcode doesn’t support iOS 16.6

xocde版本低&#xff0c;手動放入16.6的依賴文件 https://gitee.com/qiu1993/iOSDeviceSupport/blob/master/iOS16/16.6.zip 路徑 /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport

JAVA全棧開發 day21_JDBC與反射結合、設計模式

一、總結 一階段 day01 java 發展&#xff0c;java 環境( path, java_home, class_path)&#xff0c;java 原理&#xff0c; java 執行 &#xff0c; jvm , jre , jdk day02 變量 標識符命名規則 數據類型 數據類型的轉換 運算符 day03 選擇結構 if , switch day04 循環結…

分割回文串

分割回文串 描述 : 給你一個字符串 s&#xff0c;請你將 s 分割成一些子串&#xff0c;使每個子串都是 回文串 。返回 s 所有可能的分割方案。 回文串 是正著讀和反著讀都一樣的字符串。 題目 : LeetCode 131.分割回文串 : 131. 分割回文串 分析 : 字符串如何判斷回文本…

20 Redis進階 - 運維監控

1、理解Redis監控 Redis運維和監控的意義不言而喻&#xff0c;可以以下三個方面入手 1.首先是Redis自身提供了哪些狀態信息&#xff0c;以及有哪些常見的命令可以獲取Redis的監控信息; 2.一些常見的UI工具可以可視化的監控Redis; 3.理解Redis的監控體系;2、Redis自身狀態及命…

Vue3-02-ref() 響應式詳解

ref() 是什么 ref() 是一個函數&#xff1b; ref() 函數用來聲明響應式的狀態&#xff08;就是來聲明變量的&#xff09; ref() 函數聲明的變量&#xff0c;是響應式的&#xff0c;變量的值改變之后&#xff0c;頁面中會自動重新渲染。ref() 有什么特點 1.ref() 可以聲明基礎…

VUE語法--toRefs與toRef用法

1、功能概述 ref和reactive能夠定義響應式的數據&#xff0c;當我們通過reactive定義了一個對象或者數組數據的時候&#xff0c;如果我們只希望這個對象或者數組中指定的數據響應&#xff0c;其他的不響應。這個時候我們就可以使用toRefs和toRef實現局部數據的響應。 toRefs是…

算一算并輸出2到正整數n中每個數的質因子(for循環)

計算并輸出2到正整數n之間每個數的質因子&#xff0c;并以乘法形式輸出。 輸入格式: 輸入只有1個正整數即n。 輸出格式: 把2到正整數n間的每一個數分解成它的質因子&#xff0c;并以乘法的形式輸出。例如&#xff0c;輸入的正整數n值為10&#xff0c;則應輸出如下&#xff…

MIT線性代數筆記-第28講-正定矩陣,最小值

目錄 28.正定矩陣&#xff0c;最小值打賞 28.正定矩陣&#xff0c;最小值 首先正定矩陣是一個實對稱矩陣 由第 26 26 26講的末尾可知正定矩陣有以下四種判定條件&#xff1a; 所有特征值都為正左上角所有 k k k階子矩陣行列式都為正&#xff08; 1 ≤ k ≤ n 1 \le k \le n …

DDD系列 - 第6講 倉庫Repository及Mybatis、JPA的取舍(一)

目錄 一、領域層定義倉庫接口1.1 設計聚合1.2 定義倉庫Repository接口二 、基礎設施層實現倉庫接口2.1 設計數據庫2.2 集成Mybatis2.3 引入Convetor2.4 實現倉庫三、回顧一、領域層定義倉庫接口 書接上回,之前通過一個關于拆解、微服務、面向對象的故事,向大家介紹了如何從微…

簡單的WEB服務器

優質博文&#xff1a;IT-BLOG-CN 目的&#xff1a; 了解Java Web服務器是如何運行的。Web服務器使用HTTP與其客戶端&#xff0c;也就是Web瀏覽器進行通信。基于Java的Web服務器會使用兩個重要類&#xff1a;java.net.Socket類和java.net.ServerSocket類&#xff0c;并通過發送…

詳解Keras3.0 Models API: Model class

1、語法 keras.Model() 將不同層組為具有訓練/推理特征的對象的模型 2、示例一 inputs keras.Input(shape(37,)) x keras.layers.Dense(32, activation"relu")(inputs) outputs keras.layers.Dense(5, activation"softmax")(x) model keras.Model…

58.Nacos源碼分析2

三、服務心跳。 3.服務心跳 Nacos的實例分為臨時實例和永久實例兩種&#xff0c;可以通過在yaml 文件配置&#xff1a; spring:application:name: order-servicecloud:nacos:discovery:ephemeral: false # 設置實例為永久實例。true&#xff1a;臨時; false&#xff1a;永久ser…

MySQL-備份+日志:介質故障與數據庫恢復

目錄 第1關&#xff1a;備份與恢復 第2關&#xff1a;備份日志&#xff1a;介質故障的發生與數據庫的恢復 第1關&#xff1a;備份與恢復 任務描述 本關任務: 備份數據庫&#xff0c;然后再恢復它。 test1_1.sh # 你寫的命令將在linux的命令行運行 # 對數據庫residents作海…

【C/C++筆試練習】多態的概念、虛函數的概念、虛表地址、派生類的虛函數、虛函數的訪問、指針引用、動態多態、完全數計算、撲克牌大小

文章目錄 C/C筆試練習選擇部分&#xff08;1&#xff09;多態的概念&#xff08;2&#xff09;虛函數的概念&#xff08;3&#xff09;虛表地址&#xff08;4&#xff09;派生類的虛函數&#xff08;5&#xff09;虛函數的訪問&#xff08;6&#xff09;分析程序&#xff08;7&…

C# WPF上位機開發(會員管理軟件)

【 聲明&#xff1a;版權所有&#xff0c;歡迎轉載&#xff0c;請勿用于商業用途。 聯系信箱&#xff1a;feixiaoxing 163.com】 好多同學都認為上位機只是純軟件開發&#xff0c;不涉及到硬件設備&#xff0c;比如聽聽音樂、看看電影、寫寫小的應用等等。如果是消費電子&#…

HibernateJPA快速搭建

1. 先創建一個普通Maven工程&#xff0c;導入依賴 <dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><depe…

Java 匿名內部類使用的外部變量,為什么一定要加 final?

問題描述 Effectively final Java 1.8 新特性&#xff0c;對于一個局部變量或方法參數&#xff0c;如果他的值在初始化后就從未更改&#xff0c;那么該變量就是 effectively final&#xff08;事實 final&#xff09;。 這種情況下&#xff0c;可以不用加 final 關鍵字修飾。 …

報錯:Parsed mapper file: ‘file mapper.xml 導致無法啟動

報錯 &#xff1a; Logging initialized using class org.apache.ibatis.logging.stdout.StdOutImpl adapter. Registered plugin: com.github.yulichang.interceptor.MPJInterceptor3b2c8bda Parsed mapper file: file [/Mapper.xml] application無法啟動 我這邊產生原因是項…