FreeRTOS---基礎知識2

1. FreeRTOS 調度機制概述

FreeRTOS 是一個實時操作系統(RTOS),其核心功能是通過?調度器(Scheduler)?管理多個任務的執行。調度機制決定了?何時切換任務?以及?如何選擇下一個運行的任務,以滿足實時性、優先級和資源共享的需求。以下是 FreeRTOS 調度機制的全面解析:


1.1.調度器的基本工作原理

FreeRTOS 調度器的主要職責是:

  1. 任務切換(Context Switching)保存當前任務的上下文(寄存器、棧等),并恢復下一個任務的上下文。

  2. 任務選擇:根據任務狀態(就緒、阻塞、掛起)和優先級,決定下一個運行的任務。

  3. 事件響應:處理中斷、信號量、隊列等事件觸發的任務狀態變化。

調度觸發條件

  • 主動讓出 CPU:任務調用?taskYIELD()?或阻塞(如?vTaskDelay()xQueueReceive())。

  • 系統心跳(Tick 中斷)SysTick?或定時器中斷觸發調度檢查。

  • 中斷服務程序(ISR):某些中斷(如?PendSV)強制觸發任務切換。


1.2?調度策略

FreeRTOS 支持兩種主要調度策略:

(1) 搶占式調度(Preemptive Scheduling)

  • 默認模式,高優先級任務可搶占低優先級任務。

  • 特點

    • 高優先級任務就緒時,立即獲得 CPU。

    • 適用于硬實時系統(如電機控制、傳感器采集)。


void vHighPriorityTask(void *pvParams) {while (1) {printf("High Priority Task Running!\n");vTaskDelay(100); // 短暫阻塞,讓出 CPU}
}void vLowPriorityTask(void *pvParams) {while (1) {printf("Low Priority Task Running...\n");vTaskDelay(1000); // 長時間阻塞}
}

?結果vHighPriorityTask?會頻繁搶占?vLowPriorityTask

(2) 協作式調度(Cooperative Scheduling)

  • 需手動調用?taskYIELD()?讓出 CPU,無搶占。

  • 特點

    • 任務必須主動放棄 CPU,否則一直運行。

    • 適用于簡單系統,但實時性較差。


1.3 任務狀態與調度

FreeRTOS 任務可能處于以下狀態:

狀態描述
就緒(Ready)任務準備就緒,等待調度器分配 CPU。
運行(Running)當前正在執行的任務(單核 CPU 同一時間只有一個)。
阻塞(Blocked)任務因等待事件(如延時、信號量、隊列)而暫停,不占用 CPU。
掛起(Suspended)任務被顯式掛起(vTaskSuspend()),不參與調度,需手動恢復(vTaskResume())。

調度器選擇任務的規則

  1. 優先選擇?最高優先級的就緒任務

  2. 同優先級任務按?時間片輪轉(Round-Robin)?分配 CPU(需啟用?configUSE_TIME_SLICING)。


1.4 調度器實現細節

(1) 任務切換的底層機制

  • PendSV 中斷
    FreeRTOS 使用?PendSV(可掛起的系統調用)進行任務切換,確保切換過程?原子化,避免在中斷中直接切換導致嵌套問題。

  • 上下文保存與恢復

    • 硬件自動保存部分寄存器(R0-R3,?R12,?LR,?PC,?xPSR)。

    • 軟件手動保存剩余寄存器(R4-R11)。

任務切換流程

  1. 觸發?PendSV?中斷。

  2. 保存當前任務的寄存器到其棧中。

  3. 調用?vTaskSwitchContext()?選擇新任務。

  4. 從新任務的棧恢復寄存器。

  5. 返回新任務繼續執行。

(2) 調度器啟動

調用?vTaskStartScheduler()?后:

  1. 創建?空閑任務(Idle Task)(優先級 0,用于清理資源)。

  2. 初始化系統心跳(SysTick?定時器)。

  3. 開始調度第一個任務。

2?FreeRTOS 中的 Tick 中斷詳解

Tick 中斷(系統心跳中斷)是 FreeRTOS 調度和任務管理的核心機制,它通過周期性中斷為系統提供時間基準,驅動任務調度、延時管理和超時檢測。以下是 Tick 中斷的全面解析:

2.1 Tick 中斷的作用

(1) 核心功能

  • 提供系統時間基準
    維護全局時鐘計數器?xTickCount,記錄系統啟動后的 Tick 次數(1 Tick =?configTICK_RATE_HZ?分之一秒)。

  • 任務延時管理
    檢查阻塞任務的超時時間(如?vTaskDelay()),喚醒到期任務。

  • 調度觸發
    在搶占式調度模式下,每個 Tick 中斷會檢查是否需要切換任務(如同優先級任務時間片輪轉)。

  • 軟件定時器
    驅動 FreeRTOS 的軟件定時器(xTimer)回調。

(2) 典型應用場景

  • 周期性任務(如每 100ms 采集一次傳感器數據)。

  • 超時控制(如等待信號量時設置超時時間)。

  • 低功耗模式(Tickless 模式下動態調整中斷間隔)。


2.2 Tick 中斷的硬件實現

(1) 硬件依賴

  • 定時器選擇:通常使用 MCU 的?SysTick?定時器(Cortex-M 內核內置),也可用通用定時器(如 TIMx)。

  • 中斷頻率:由?configTICK_RATE_HZ?定義(通常 100Hz~1kHz)。
    示例配置(FreeRTOSConfig.h):

    c

    復制

    下載

    #define configTICK_RATE_HZ 1000  // 1kHz Tick,每1ms中斷一次

(2) 初始化流程

FreeRTOS 啟動時(vTaskStartScheduler())會初始化 Tick 中斷:

  1. 配置定時器周期(如?SysTick_Config(SystemCoreClock / configTICK_RATE_HZ))。

  2. 設置中斷優先級(通常為最低優先級,避免影響其他中斷)。

  3. 啟用定時器和中斷。


2.3 Tick 中斷的處理流程

(1) 中斷服務程序(ISR)

當 Tick 中斷發生時:

  1. 遞增時鐘計數器xTickCount++

  2. 檢查任務延時列表

    • 遍歷阻塞任務列表,若有任務延時到期,則將其移至就緒列表

  3. 觸發調度(可選)

    • 若啟用搶占式調度(configUSE_PREEMPTION=1),檢查是否需要任務切換。

  4. 處理軟件定時器(可選)

    • 若啟用?configUSE_TIMERS=1,檢查定時器回調。

(2) 關鍵代碼(Cortex-M 示例)

void SysTick_Handler(void) {// 1. 進入中斷上下文portENTER_CRITICAL();  // 關中斷(防止嵌套)// 2. 調用 FreeRTOS 的 Tick 處理函數if (xTaskIncrementTick() != pdFALSE) {portYIELD();  // 觸發任務切換(通過 PendSV)}// 3. 退出中斷portEXIT_CRITICAL();
}

2.4 Tick 中斷與任務調度

(1) 時間片輪轉(Round-Robin)

  • 同優先級任務共享 CPU
    每個 Tick 中斷會檢查當前任務是否用完時間片(configUSE_TIME_SLICING=1),若用完則切換任務。

  • 示例
    兩個同優先級任務?TaskA?和?TaskB?會交替運行(每 1 Tick 切換一次)。

Tick中斷函數的作用:
(1)取出下一個Task
(2)切換:
a.保存當前Task
b.恢復新的Task

(2) 延時與阻塞

  • vTaskDelay()?的實現
    任務調用?vTaskDelay(ticks)?后,會被移入阻塞列表,直到?xTickCount?遞增到指定值

    void vTaskDelay(TickType_t xTicksToDelay) {vTaskSuspendAll();  // 暫停調度器xTickCount += xTicksToDelay;prvAddCurrentTaskToDelayedList(xTicksToDelay);xTaskResumeAll();   // 恢復調度器
    }

例如存在以下三個任務,其中任務1和任務2優先級相同,任務3優先級最高。

#include <stdio.h>/* Scheduler includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"/* Library includes. */
#include "stm32f10x_it.h"extern 	void UART_Init(unsigned long ulWantedBaud);/* Demo app includes. */
static void prvSetupHardware( void );static volatile int flagIdleTaskrun = 0;  // 空閑任務運行時flagIdleTaskrun=1
static volatile int flagTask1run = 0;     // 任務1運行時flagTask1run=1
static volatile int flagTask2run = 0;     // 任務2運行時flagTask2run=1
static volatile int flagTask3run = 0;     // 任務3運行時flagTask3run=1/*-----------------------------------------------------------*/void vTask1( void *pvParameters )
{/* 任務函數的主體一般都是無限循環 */for( ;; ){flagIdleTaskrun = 0;flagTask1run = 1;flagTask2run = 0;flagTask3run = 0;/* 打印任務的信息 */printf("T1\r\n");				}
}void vTask2( void *pvParameters )
{	/* 任務函數的主體一般都是無限循環 */for( ;; ){flagIdleTaskrun = 0;flagTask1run = 0;flagTask2run = 1;flagTask3run = 0;/* 打印任務的信息 */printf("T2\r\n");				}
}void vTask3( void *pvParameters )
{	const TickType_t xDelay5ms = pdMS_TO_TICKS( 5UL );		/* 任務函數的主體一般都是無限循環 */for( ;; ){flagIdleTaskrun = 0;flagTask1run = 0;flagTask2run = 0;flagTask3run = 1;/* 打印任務的信息 */printf("T3\r\n");				// 如果不休眠的話, 其他任務無法得到執行vTaskDelay( xDelay5ms );}
}void vApplicationIdleHook(void)
{flagIdleTaskrun = 1;flagTask1run = 0;flagTask2run = 0;flagTask3run = 0;	/* 故意加入打印讓flagIdleTaskrun變為1的時間維持長一點 *///printf("Id\r\n");				
}int main( void )
{prvSetupHardware();xTaskCreate(vTask1, "Task 1", 1000, NULL, 0, NULL);xTaskCreate(vTask2, "Task 2", 1000, NULL, 0, NULL);xTaskCreate(vTask3, "Task 3", 1000, NULL, 2, NULL);/* 啟動調度器 */vTaskStartScheduler();/* 如果程序運行到了這里就表示出錯了, 一般是內存不足 */return 0;
}
/*-----------------------------------------------------------*/static void prvSetupHardware( void )
{/* Start with the clocks in their e

如果在任務3中調用vTaskDelay(ticks),這里設定延遲5ms,運行后可以看到,任務1,2,3是交替運行的,如下圖所示。

如果不調用vTaskDelay(ticks),因為任務3的優先級最高,任務1和2將無法運行,如下所示:

注:若任務1,任務2和任務3的優先級相同,則這三個任務輪流執行,且是任務3先執行,然后是任務1,最后是任務2執行。?

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

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

相關文章

Docker安裝(精簡述版)

1. 安裝&#xff1a;Docker 環境&#xff08;Docker desktop&#xff09; #Windows架構版本查看&#xff0c;Win R? 輸入 ?cmd? 打開命令提示符&#xff1b;輸入命令?&#xff1a; bash echo %PROCESSOR_ARCHITECTURE%#安裝Docker desktop&#xff08;安裝時勾選 WSL2&am…

Postman-win64-7.3.5-Setup.exe安裝教程(附詳細步驟+桌面快捷方式設置)?

Postman 是一款超常用的接口調試工具&#xff0c;程序員和測試人員用它來發送網絡請求、測試API接口、調試數據交互? 1. 雙擊安裝包? 安裝包下載地址&#xff1a;https://pan.quark.cn/s/4b2960d60ae9&#xff0c;找到你下的 Postman-win64-7.3.5-Setup.exe 文件&#xff08…

149. Java Lambda 表達式 - Lambda 表達式的序列化

文章目錄149. Java Lambda 表達式 - Lambda 表達式的序列化為什么要序列化 Lambda 表達式&#xff1f;Lambda 表達式的序列化規則示例代碼&#xff1a;序列化 Lambda 表達式代碼解析&#xff1a;Lambda 序列化的限制總結&#xff1a;149. Java Lambda 表達式 - Lambda 表達式的…

頤頓機電攜手觀遠BI數據:以數據驅動決策,領跑先進制造智能化升級

頤頓機電簽約觀遠數據&#xff0c;聚焦財務分析、銷售管理等場景&#xff0c;以 BI 數據解決方案推進數據驅動決策&#xff0c;助力先進制造企業提效與競爭力升級。一、合作官宣&#xff1a;頤頓機電 觀遠數據&#xff0c;開啟數據應用新征程浙江頤頓機電有限公司&#xff08;…

【PHP】幾種免費的通過IP獲取IP所在地理位置的接口(部分免費部分收費)

目錄 一、獲取客戶端IP地址 二、獲取IP所在地理位置接口 1、IP域名歸屬地查詢 2、騰訊地圖 - IP定位 3、聚合數據 - IP地址&#xff08;推薦&#xff09; 4、高德地圖 - IP定位&#xff08;推薦&#xff09; 5、360分享計劃 - IP查詢 6、天聚ip地址查詢 7、百度IP地址…

【Excel】制作雙重餅圖

一、效果話不多說&#xff0c;直接上數據和效果圖&#xff01;&#xff08;示例軟件&#xff1a;WPS Office&#xff09;類別現金刷卡小計蘋果10.005.0015.00荔枝20.0015.0035.00西瓜30.0025.0055.00總計60.0045.00105.00二、步驟&#xff08;一&#xff09;制作底圖插入餅圖&a…

gcc-arm-none-eabi安裝后,找不到libgcc.a的拉置

位置在&#xff1a;/usr/lib/gcc/arm-none-eabi/6.3.1/libgcc.a查找方法&#xff1a;arm-none-eabi-gcc --print-libgcc-file-name以前沒找到&#xff0c;是因為進錯目錄&#xff1a;/usr/lib/arm-none-eabi/lib

上證50期權2400是什么意思?

本文主要介紹上證50期權2400是什么意思&#xff1f;“上證50期權2400”通常指上證50ETF期權的某個具體合約代碼&#xff0c;其中“2400”是合約代碼的一部分&#xff0c;需結合完整代碼格式理解其含義。上證50期權2400是什么意思&#xff1f;一、上證50期權合約代碼的組成上證5…

發那科機器人P點位置號碼自動變更功能為禁用狀態

通過改變變量的狀態&#xff0c;發那科機器人可以實現&#xff0c;當在程序中進行記錄、修改、插入、刪除、復制/粘貼包含有P點位置號碼的行時&#xff0c;P點位置號碼會自動從小到大自動排列&#xff0c;可以實現自動排列&#xff0c;或者點擊編輯變更編號也可以下圖所示女變量…

什么叫湖倉一體

文章目錄概念一、理解湖倉一體&#xff1a;先搞懂“數據湖”和“數據倉庫”1. 數據倉庫&#xff08;Data Warehouse&#xff09;2. 數據湖&#xff08;Data Lake&#xff09;3. 傳統架構的痛點&#xff1a;“湖”與“倉”的割裂二、湖倉一體的核心特點&#xff1a;融合“湖”與…

網絡安全突發事件應急預案方案

最近有要求需要出一個網絡安全突發事件應急預案方案&#xff0c;本文僅就應急預案問題提出一點初步思考&#xff0c;意在拋磚引玉&#xff0c;盼各位讀者不吝賜教&#xff0c;共同完善對這一領域的認識。一、總則 &#xff08;一&#xff09;目的 為有效應對規劃建筑設計院企業…

【基于3D Gaussian Splatting的三維重建】保姆級教程 | 環境安裝 | 制作-訓練-測試自己數據集 | torch | colmap | ffmpeg | 全過程圖文by.Akaxi

目錄 一.【3DGS環境配置】 1.1 克隆3DGS倉庫 1.2 安裝Visual Studio 2022 1.2.1 下載Visual Studio 2022 1.2.2 更改環境變量 1.3 創建環境 1.3.1 創建python環境 1.3.2 離線安裝torch包 1.3.3 安裝依賴包 1.3.4安裝子模塊 &#xff08;1&#xff09;報錯解決&…

C#泛型委托講解

1. 泛型&#xff08;Generics&#xff09; 泛型允許編寫類型安全且可重用的代碼&#xff0c;避免裝箱拆箱操作&#xff0c;提高性能。 泛型類 // 定義泛型類 public class GenericList<T> {private T[] items;private int count;public GenericList(int capacity){items …

【DL學習筆記】DL入門指南

DL入門指南 資料課程 李沐老師 《動手學深度學習》 https://tangshusen.me/Dive-into-DL-PyTorch/李宏毅老師課程 https://speech.ee.ntu.edu.tw/~hylee/ml/2021-spring.php DL入門必掌握知識點 數據處理 &#xff1a; numpy、torch地址處理 &#xff1a; os、pathlib文件處…

在 uni-app 中進行路由跳轉前的權限驗證(檢查用戶是否登錄)

使用場景&#xff1a; 適用于需要登錄才能訪問的 uni-app 應用保護需要認證的頁面不被未授權用戶訪問統一處理路由跳轉的權限控制 /utils/cookies.js下的部分代碼內容&#xff1a; // #ifdef H5 import Cookies from js-cookie // #endif// ums const tokenKey user_center_to…

垃圾收集器ParNewCMS與底層三色標記算法詳解

垃圾收集技術詳解筆記 1. 分代收集理論 當前虛擬機的垃圾收集采用分代收集算法&#xff0c;根據對象存活周期將內存分為不同代區&#xff0c;以優化回收效率。 核心分區&#xff1a; 新生代&#xff08;Young Generation&#xff09;&#xff1a;對象存活周期短&#xff0c;約9…

全排列(回溯算法)

本文參考代碼隨想錄 給定一個 沒有重復 數字的序列&#xff0c;返回其所有可能的全排列。 示例: 輸入: [1,2,3] 輸出: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ] 思路 排列是有序的&#xff0c;在排列問題中不需要startIndex&#xff1b;但排列問題需要一個…

在線任意長度大整數計算器

具體請前往&#xff1a;在線大整數計算器--支持超大整數的加減乘除,冪運算/模運算,最大公約數&#xff0c;最小公倍數

AT6668B芯片說明書

這顆北斗專用單芯片解決方案AT6668B&#xff0c;采用射頻前端與基帶處理一體化設計&#xff0c;集成北斗二號/三號雙模B1IB1C信號處理器。通過優化星歷解碼算法實現秒級衛星鎖定&#xff0c;配合硬件加速的干擾監測模塊&#xff0c;在電磁環境復雜的應用場景中仍可維持10Hz高頻…

谷歌Chrome瀏覽器安裝插件

因為google瀏覽器的應用市場(https://chrome.google.com/webstore/category/extensions)在國內無法訪問,所以無法在線安裝插件,這里提供開發者模式離線安裝插件的方法。 1、下載crx腳本 谷歌瀏覽器的插件離線文件的擴展名為:crx(Firefox火狐瀏覽器的插件擴展名為fpi)。…