以下內容轉載自安富萊電子:http://forum.armfly.com/forum.php
1、 調 度 鎖
調度鎖就是 RTOS 提供的調度器開關函數,如果某個任務調用了調度鎖開關函數,處於調度鎖開和調度鎖關之間的代碼在執行期間是不會被高優先級的任務搶占的,即任務調度被禁止。這一點要跟臨界段的作用區分開,調度鎖只是禁止了任務調度,並沒有關閉任何中斷,中斷還是正常執行的。而臨界段進行了開關中斷操作。
2、 中 斷 鎖
中斷鎖就是 RTOS 提供的開關中斷函數,FreeRTOS 沒有專門的中斷鎖函數,使用 “中斷服務程序臨界段處理”函數就可以實現同樣效果。
3 、 任 務 鎖
簡單的說,為了防止當前任務的執行被其它高優先級的任務打斷而提供的鎖機制就是任務鎖。FreeRTOS 也沒有專門的任務鎖函數,但是使用 FreeRTOS 現有的功能有兩種實現方法:
通過給調度器加鎖實現
利用 FreeRTOS 的調度鎖功能給調度器加鎖的話,將關閉任務切換功能,從而高優先級任務也就無法搶占低優先級任務的執行,同時高優先級任務也是無法向低優先級任務切換的。另外特別注意,調度鎖只是禁止了調度器工作,並沒有關閉任何中斷。
通過關閉任務切換中斷 PendSV 和系統時鍾節拍中斷 Systick
利用 FreeRTOS 的任務代碼臨界段處理函數就可以關閉 PendSV 中斷和 Systick 中斷。因為進入臨界段前,操作寄存器 basepri 關閉了所有小於等於宏定義configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 所定義的中斷優先級(實現任務切換功能的 PendSV 中斷和滴答定時器中斷是最低優先級中斷,所以也是被關閉的),這樣低優先級任務在執行臨界段代碼期間是不會被高優先級任務打斷的,從而就實現了任務鎖的效果。
4、FreeRTOS調度鎖開啟
使用如下函數可以實現 FreeRTOS 的調度鎖開啟: vTaskSuspendAll()
關於這個函數的講解及其使用方法可以看 FreeRTOS 在線版手冊:
這里也對此函數進行下介紹。
函數原型:
void vTaskSuspendAll( void );
函數描述:
函數 vTaskSuspendAll 用於實現 FreeRTOS 調度鎖開啟。
使用這個函數要注意以下問題:
1. 調度鎖函數只是禁止了任務調度,並沒有關閉任何中斷。
2. 調度鎖開啟函數 vTaskSuspendAll 和調度鎖關閉函數 xTaskResumeAll 一定要成對使用。
3. 切不可在調度鎖開啟函數 vTaskSuspendAll 和調度鎖關閉函數 xTaskResumeAll 之間調用任何會引
起任務切換的 API,比如 vTaskDelayUntil、vTaskDelay、xQueueSend 等
使用舉例:
5、FreeRTOS 調 度 鎖 關 閉
使用如下函數可以實現 FreeRTOS 的調度鎖關閉:
xTaskResumeAll ()
關於這個函數的講解及其使用方法可以看 FreeRTOS 在線版手冊:
這里也對此函數進行下介紹。
函數原型:
BaseType_t xTaskResumeAll(void)
函數描述:
函數 xTaskResumeAll 用於實現 FreeRTOS 調度鎖關閉
調度鎖關閉后,如果需要任務切換,此函數返回 pdTRUE,否則返回 pdFALSE。
使用這個函數要注意以下問題:
1. 調度鎖函數只是禁止了任務調度,並沒有關閉任何中斷。
2. 調度鎖開啟函數 vTaskSuspendAll 和調度鎖關閉函數 xTaskResumeAll 一定要成對使用。
3. 切不可在調度鎖開啟函數 vTaskSuspendAll 和調度鎖關閉函數 xTaskResumeAll 之間調用任何會引
起任務切換的 API,比如 vTaskDelayUntil、vTaskDelay、xQueueSend 等。
使用舉例:
FreeRTOSConfig.h 文件中的幾個重要選項說明:
#define configUSE_PREEMPTION 1
使能搶占式調度器
#define configCPU_CLOCK_HZ ( ( unsigned long ) 168000000 )
系統主頻 168MHz。
#define configTICK_RATE_HZ ( ( TickType_t ) 1000 )
系統時鍾節拍 1KHz,即 1ms。
#define configMAX_PRIORITIES ( 5 )
定義可供用戶使用的最大優先級數,如果這個定義的是 5,那么用戶可以使用的優先級號是 0,1,2,3,4,
不包含 5,對於這一點,初學者要特別的注意。
#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 30 * 1024 ) )
定義堆大小,FreeRTOS 內核,用戶動態內存申請,任務棧等都需要用這個空間。
configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 0x01
定義受 FreeRTOS 管理的最高優先級中斷。簡單的說就是允許用戶在這個中斷服務程序里面調用
FreeRTOS 的 API 的最高優先級。為了進一步說明這個宏定義的作用,解釋如下:
使用 CM 內核的 MCU,官方強烈建議將 NVIC 的優先級分組配置為全搶占式優先級,全部配置
為搶占式優先級的好處就是方便管理。
對於 STM32 來說,設置 NVIC 的優先級分組為 4 時,
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4)就是全部配置為搶占式優先級。又因為
STM32 的優先級設置僅使用 CM 內核 8bit 中的高 4bit,即只能區分 2^4 = 16 種優先級。因此
當優先級分組設置為 4 的時候可供用戶選擇搶占式優先級為 0 到 15,共 16 個優先級,配置為 0
表示最高優先級,配置為 15 表示最低優先級,不存在子優先級。
這里配置 configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 為 0x01 表示用戶可以在搶
占式優先級為 1 到 15 的中斷里面調用 FreeRTOS 的 API 函數,搶占式優先級為 0 的中斷里面是
不允許調用的。
創建任務函數:
實驗現象:LED閃,蜂鳴響,當按下K1時開啟調度鎖,執行串口打印,完成后關閉調度鎖。
當調用函數xTaskResumeAll()時; 如果有上下文切換,函數已經進行了上下文切換。函數返回pdTRUE,程序跳過上面框中的if函數,
如果沒有上下文切換函數返回pdFALSE,執行框中的if函數。taskYIELD();這個函數是強制上下文轉換:
這也就證明了,如果調用xTaskResumeAll()沒有進行上下文切換,我們將強制進行上下文切換,如果進行了上下文切換,這個if判斷是多余的。官方解釋:
另外需要注意,強制進行上下文切換,不代表本任務中xTaskResumeAll()后面的語句就不執行了,這里led燈的亮滅依舊會執行,只是調度器重新獲得了調度權限,可以在多個任務間進行調度和切換。還有注意調度鎖,不能鎖中斷(只是關閉了任務的調度)。
實驗效果:
按下k1后等依然在閃,蜂鳴也在響。后面的語句依然在執行。