FreeRTOS 空閒任務與阻塞延遲實現

2021-10-03 01:17:14 字數 4479 閱讀 2179

在裸機執行中,我們是使用軟體延時來實現延時的功能(delay()),即是讓cpu空等來達到延時的目的。使用rtos的很大優勢就是榨乾cpu效能,永遠不讓他閒著,任務需要延時也就不需要讓cpu空等來實現延時的效果。

rtos中的延時叫做阻塞延時,即任務需要延時的時候,任務會放棄cpu的使用權,cpu可以去幹其他的事情,當任務延時時間到,重新獲取cpu使用權,任務繼續執行。這樣就可以充分利用cpu資源了。

當任務進入阻塞狀態,如果沒有其他任務可以執行,rtos都會為cpu建立乙個空閒任務,這個時候cpu就去執行空閒任務。在freertos中,空閒任務是系統在【啟動排程器】的時候建立的優先順序最低的任務,空閒任務主要做一些系統記憶體清理的任務。

目前我們在建立任務時使用的棧和tcb都是使用的靜態記憶體,即預先定義好的記憶體,空閒任務也不例外。

空閒任務的棧在main.c 中定義:

/* 定義空閒任務的棧 */

#define configminimal_stack_size ( ( unsigned short ) 128 ) (2)

stacktype_t idletaskstack[configminimal_stack_size];(

1)

(1):空閒任務的棧是乙個定義好的陣列,大小由freertosconfig.h 中

定義的巨集 configminimal_stack_size 控制,大小為128,單位是字。

空閒任務的任務控制塊在main.c中定義:

/* 定義空閒任務的任務控制塊 */

tcb_t idletasktcb;

空閒任務在排程器啟動函式vtaskstartscheduler()中建立:

extern tcb_t idletasktcb;

void

( tcb_t *

*ppxidletasktcbbuffer,

stacktype_t *

*ppxidletaskstackbuffer,

uint32_t *pulidletaskstacksize )

;void

vtaskstartscheduler

(void

)}

void

( tcb_t *

*ppxidletasktcbbuffer,

stacktype_t *

*ppxidletaskstackbuffer,

uint32_t *pulidletaskstacksize )

(2):呼叫 xtaskcreatestatic()函式建立空閒任務。

(3):將空閒任務插入到就緒列表的開頭。

阻塞延時的阻塞是指任務呼叫該延時函式後,任務會被剝離cpu使用權,然後進入阻塞狀態,直到延時結束,任務重新獲取cpu使用權才可以繼續執行。在任務阻塞這段時間,cpu可以去執行其他的任務,如果其他任務也處於阻塞狀態,cpu就會執行空閒任務。

void

vtaskdelay

(const ticktype_t xtickstodelay )

(1):獲取當前任務控制塊。

(2):xtickstodelay是任務控制塊的乙個成員,用於記錄需要延時的時間,單位為systick的中斷週期。

xtickstodelay定義:

typedef

struct tsktaskcontrolblock

tsktcb;

(3):任務切換。呼叫taskyield()會產生pendsv中斷,在pendsv中斷服務函式終會呼叫任務切換函式vtaskswitchcontext(),該任務的作用是尋找最高優先順序的就緒任務,然後更新pxcurrenttcb.因為這一章比上一章多乙個空閒任務,需要讓pxcurrenttcb 在這三個任務中切換, 演算法需要改變,vtaskswitchcontext()函式修改如下:

void

vtaskswitchcontext

(void

)else

if(task2tcb.xtickstodelay ==0)

else

}else

/* 當前任務不是空閒任務則會執行到這裡 */(2

)else

if(pxcurrenttcb->xtickstodelay !=0)

else

}else

if(pxcurrenttcb ==

&task2tcb)

else

if(pxcurrenttcb->xtickstodelay !=0)

else}}

}

在任務上下文切換函式 vtaskswitchcontext ()中,會判斷每個任務的任務控制塊中的延時成員xtickstodelay的值是否為0,如果為0就要將對應的任務就緒,如果不為0就繼續延時。如果乙個任務延時,一開始xtickstodelay不為0,當xtickstodelay變為0後表示延時結束。在freertos中,作業系統中的最小時間單位是systick的中斷週期,我們稱之為乙個tick ,xtickstodelay就是以tick為週期遞減的。

systick 中斷服務函式

void

xportsystickhandler

(void

)

xtaskincrementtick()函式

void

xtaskincrementtick

(void)}

/* 執行一次任務切換 */(3

)portyield()

;}

systick 的中斷服務函式要想被順利執行,則 systick 必須先初始化systick 初始化函式在 port.c 中定義。

vportsetuptimerinterrupt()函式:

/* systick 控制暫存器 */(1

)#define portnvic_systick_ctrl_reg (*((volatile uint32_t *) 0xe000e010 ))

/* systick 重裝載暫存器暫存器 */

#define portnvic_systick_load_reg (*((volatile uint32_t *) 0xe000e014 ))

/* systick 時鐘源選擇 */

#ifndef configsystick_clock_hz

#define configsystick_clock_hz configcpu_clock_hz

/* 確保 systick 的時鐘與核心時鐘一致 */

#define portnvic_systick_clk_bit ( 1ul << 2ul )

#else

#define portnvic_systick_clk_bit ( 0 )

#endif

#define portnvic_systick_int_bit ( 1ul << 1ul )

#define portnvic_systick_enable_bit ( 1ul << 0ul )

void

vportsetuptimerinterrupt

(void)(

2)

systick 初 始 化 函 數 vportsetuptimerinterrupt() , 在

xportstartscheduler()中被呼叫。

basetype_t xportstartscheduler

(void

)

(2)-①:設定重裝載暫存器的值,決定systick 的中斷週期。

configcpu_clock_hz 與 configtick_rate_hz 巨集定義:

#define configcpu_clock_hz (( unsigned long ) 25000000) (1)

#define configtick_rate_hz (( ticktype_t ) 100) (2)

(1):系統時鐘大小,目前是軟體**,需要配置成與system_armcm3.c檔案中的 system_clock的一樣, 即等於 25m。如果有具體的硬體,則配置成與硬體系統時鐘一樣

(2):systick 每秒中斷多少次,目前配置為 100,即每 10ms 中斷一次。

(2)-②:設定系統定時器的時鐘等於核心時鐘,使能 systick 定時器中斷,使能 systick 定時器。

參考:[野火®]《freertos 核心實現與應用開發實戰—基於stm32》

freeRTOS 空閒任務與阻塞延時 1

rtos中的延時是在需要延時的時間內任務放棄cpu的使用權,超過延時時間後重新獲得cpu的使用權。叫做 阻塞延時。空閒任務是在啟動排程器後建立的,是cpu空閒時候執行的,是優先順序最低的。空閒任務主要做一些清理記憶體的的任務。空閒任務是不允許阻塞的。如何實現空閒任務?1.在main.c定義空閒任務棧...

四 FreeRTOS 空閒任務與阻塞延時

4.2 實現阻塞延時 4.3 systick 中斷服務 4.4 systick 初始化 4.5 案例 4.6 實驗現象 野火 freertos 核心實現與應用開發實戰 基於stm32 在 rtos 中,任務需要延時時,不能再讓 cpu 空等來實現延時效果。rtos 中的延時稱為阻塞延時,即任務需要延...

FreeRtos 空閒任務與空閒任務鉤子函式

以下基礎知識 自正點原子pdf資料。前面例子中建立的任務大部份時間都處於阻塞態。這種狀態下所有的任務都不可執行,所以也不能被排程器選中。但處理器總是需要 來執行 所以至少要有乙個任務處於執行態。為了保證這 一點,當呼叫 vtaskstartscheduler 時,排程器會自動建立乙個空閒任務。空閒任...