這個是全網(wǎng)最詳細(xì)的STM32項目教學(xué)視頻。
第一篇在這里:
視頻在這里
**V3:HAL庫開發(fā)、手把手教學(xué)下面功能:PID速度控制、PID循跡、PID跟隨、遙控、避障、PID角度控制、openmv視覺控制、電磁循跡、FreeRTOS、K210視覺智能車(更新中)、K230視覺智能車(更新中)、MSPM0G3507視覺智能車(更新中)**
21.1-RTOS和任務(wù)的一些概念
多任務(wù)運行基本機制(重點理解 這是RTOS精髓)
理解RTOS的調(diào)度算法是如何安排調(diào)度的
21.1.0-任務(wù)里面寫什么
在FreeRTOS中一個任務(wù)就是一個某種功能的函數(shù),任務(wù)函數(shù)內(nèi)部的一般是一個死循環(huán)結(jié)構(gòu)。任何時候不允許從任務(wù)函數(shù)退出。
可以把RTOS的任務(wù)理解成是裸機里面main的while循環(huán),一個任務(wù)就是一個裸機里面main的while循環(huán),他們在適合的時機切換執(zhí)行。
// 溫度傳感器任務(wù)
void vTemperatureSensorTask(void *pvParameters) {
for (;;) {
/*************下面是溫度控制****************/
//讀取傳感器數(shù)值
readTemperatureSensor();
/*************上面是溫度控制****************/
vTaskDelay(1000); // 1秒
}
}
21.1.0-多個任務(wù)如何在單核MCU"同時運行"
“分時復(fù)用”-實現(xiàn)了多個任務(wù)在單核MCU上的運行
PPT 78頁到115頁是動畫講解說明如何實現(xiàn)"分時復(fù)用"
如果某個任務(wù)延時時間達(dá)到,則稱為這個任務(wù)進入就緒狀態(tài)。
如果任務(wù)獲得CPU使用權(quán),則稱之為進入運行態(tài)。
21.1.1-如果兩個任務(wù)同時要運行 應(yīng)該運行那個?
假設(shè)某一個時刻按鍵掃描任務(wù)和溫度傳感器任務(wù)的阻塞延時時間同時達(dá)到,CPU會選擇那個任務(wù)先執(zhí)行?
- 優(yōu)先級不同執(zhí)行,優(yōu)先級高的。
- 優(yōu)先級相同,執(zhí)行先創(chuàng)建的
使用下面的PPT圖片講解
因為溫度傳感器任務(wù)和按鍵掃描任務(wù)優(yōu)先級一樣,所以CPU會根據(jù)任務(wù)創(chuàng)建先后順序執(zhí)行會先執(zhí)行溫度傳感器任務(wù)!
21.1.1-如果有任務(wù)十分耗時且不釋放CPU怎么辦
PPT從119頁到136頁
這里我們假設(shè)如果在傳感器讀取任務(wù)中,如果傳感器讀取函數(shù)一直超時阻塞獲得傳感器數(shù)據(jù),那么將無法執(zhí)行VtaskDelay()函數(shù),任務(wù)就一直占用CPU 無法讓出CPU
其他任務(wù)將遲遲得不到執(zhí)行,我們稱之為**“任務(wù)饑餓”**
如何解決這個問題那? 既然任務(wù)不讓出CPU,我們就每隔一段時間檢測,是否有同優(yōu)先級或者高優(yōu)先級任務(wù)就緒,然后進行調(diào)度,這就是FreeRTOS 的時間片輪轉(zhuǎn)調(diào)度機制
21.1.1-如何讓重要任務(wù)獲得更多CPU使用權(quán)
寫過按鍵檢測掃描的同學(xué),應(yīng)該都知道按鍵程序要求一定的實時性和及時性,程序設(shè)計時要盡力保證按鍵程序的快速相應(yīng)。
所以我們可以把前面設(shè)計程序里面的按鍵掃描任務(wù)的優(yōu)先級提高
這樣CPU就會在兩個同時執(zhí)行需要執(zhí)行的任務(wù)中,先執(zhí)行按鍵掃描任務(wù)(因為任務(wù)優(yōu)先級高的)—這就叫做基于優(yōu)先級的搶占式任務(wù)調(diào)度方法。
!!!總結(jié):前面我們介紹了時間片輪轉(zhuǎn)調(diào)度機制和基于優(yōu)先級的搶占式任務(wù)調(diào)度方法,其實FreeRTOS調(diào)度方式:采用使用時間片的搶占式任務(wù)調(diào)度方式
下面這段是剛剛演示的偽代碼。
#include "FreeRTOS.h"
//...省略頭文件
// 溫度傳感器任務(wù)
void vTemperatureSensorTask(void *pvParameters) {
for (;;) {
/*************下面是溫度控制****************/
//讀取傳感器數(shù)值
readTemperatureSensor();
/*************上面是溫度控制****************/
vTaskDelay(1000); // 1秒
}
}
// 溫度控制任務(wù)
void vTemperatureControllerTask(void *pvParameters) {
for (;;) {
/*************下面是溫度控制****************/
//根據(jù)閾值 控制加熱器
if (temperature > 50)
printf("Cooling system ON.n");
else
printf("Cooling system OFF.n");
/*************上面是溫度控制****************/
vTaskDelay(2000); // 2秒
}
}
// 按鍵掃描任務(wù)
void vButtonScanTask(void *pvParameters) {
for (;;) {
/*************下面是按鍵掃描內(nèi)容****************/
//通過GPIO輸入查詢 按鍵是否按下
state = HAL_GPIO_ReadPin(BUTTON_GPIO_PORT, BUTTON_GPIO_PIN);
/*************上面是按鍵掃描內(nèi)容****************/
vTaskDelay(100); // 100毫秒
}
}
int main(void) {
// 創(chuàng)建任務(wù)
xTaskCreate(vTemperatureSensorTask, "Temp Sensor", 1000, NULL, 1, NULL);
xTaskCreate(vTemperatureControllerTask, "Temp Controller", 1000, NULL, 1, NULL);
xTaskCreate(vButtonScanTask, "Button Scan", 1000, NULL, 1, NULL);
// 啟動調(diào)度器
vTaskStartScheduler();
// 如果調(diào)度器啟動失敗,則進入死循環(huán)
for (;;) {}
return 0;
}