RT-Thread 的空閑線程和阻塞延時


RTOS中的延時叫阻塞延時,即線程需要延時的時候,線程會放棄CPU的使用權,CPU可以去干其他事情,當線程延時時間到,重新獲取CPU使用權,線程繼續運行,這樣就充分利用了CPU的使用權,而不是剛等着。

  當線程需要延時,CPU進入阻塞狀態,那CPU又去干什么事情了?如果沒有其它線程可以運行,RTOS都會為CPU創建一個空閑線程,這個時候CPU就運行空閑線程。在RT-Thread中,空閑線程是系統在初始化的時候創建的優先級最低的線程。空閑線程主體主要做一些系統內存的清理工作。在實際應用中,當系統進入空閑線程的時候,可在空閑線程中讓單片機進入休眠或者低功耗等操作。

1、實現空閑線程

1.1定義空閑線程的棧

  空閑線程的棧在idle.c文件中定義,

#include <rtthread.h>
#include <rthw.h>
#define IDLE_THREAD_STACK_SIZE 512
ALIGN(RT_ALIGN_SIZE)
static rt_uint8_t rt_thread_stack[IDLE_THREAD_STACK_SIZE];

空閑線程的棧是一個定義好的數組,大小由IDLE_THREAD_STACK_SIZE 這個宏控制,默認為512,即128個字。

1.2空閑線程的線程控制塊

/* 空閑線程的線程控制塊 */
 struct rt_thread idle;

2、實現阻塞延時

阻塞延時的阻塞是指線程調用該延時函數后,線程會被剝離CPU使用權,然后進入阻塞狀態,直到延時結束,線程重新獲取CPU使用權才可以繼續運行,在線程阻塞這段時間,CPU可以去執行其他的線程,如果其他的線程也在延時狀態,那么CPU就將運行空閑線程。阻塞延時函數在thread.c中定義。

void rt_thread_delay(rt_tick_t tick)
{ 
 struct rt_thread *thread; 

 /* 獲取當前線程的線程控制塊 */
 thread = rt_current_thread; (1) 

 /* 設置延時時間 */
 thread->remaining_tick = tick; (2)

 /* 進行系統調度 */
 rt_schedule(); (3)
 }

(1)獲取當前線程的線程控制塊。rt_current_thread 是一個在scheduler.c中定義的全局變量,用於指向當前正在運行的線程的線程控制塊。

(2)remaining_tick 是線程控制塊的一個成員,用於記錄線程需要延時的時間,單位為SysTick 的中斷周期。

3、SysTick_Handler中斷服務函數

在系統調度函數rt_schedule()中,會判斷每個線程的線程控制塊中的延時成員remaining_tick的值是否為0,如果為0,就要將對應的線程就緒,如果不為0,就繼續延時。如果一個線程要延時,一開始remaining_tick 肯定不為0,當remaining_tick為0就延時結束,那么remaining_tick是以什么周期在遞減?在哪里遞減?在RT-Thread中,這個周期由SysTick中斷提供,操作系統里面最小的時間單位就是SysTick的中斷周期,我們稱之為一個tick,SysTick中斷服務函數

/* 關中斷 */
rt_hw_interrupt_disable(); (1) 

/* SysTick 中斷頻率設置 */
SysTick_Config( SystemCoreClock / RT_TICK_PER_SECOND ); (2) 

void SysTick_Handler(void) (3)
{ 
    /* 進入中斷 */
     rt_interrupt_enter(); (3)-1
    /* 時基更新 */
     rt_tick_increase(); (3)-2
     /* 離開中斷 */
     rt_interrupt_leave(); (3)-3
 }

(1)關中斷。在程序開始的時候把中斷關掉是一個好習慣,等系統初始化完畢,線程創建完畢,啟動系統調度的時候會重新打開中斷。

(2)初始化SysTick,調用固件庫函數SysTick_Config來實現,配置中斷周期為10ms,中斷優先級為最低(無論中斷優先級分組怎么分都是最低,因為這里把表示SysTick中斷優先級的四個位全部配置為1,即15,在Cortex-M內核中,優先級越低,邏輯優先級最低),RT_TICK_PER_SECOND是一個在rtconfig.h中定義的宏,目前等於100。 

(3)更新系統時基,該函數在clock.c中實現。

進入和離開中斷,這兩個函數在irq.c 中實現。

SysTick 初始化函數(在core_cm3.h 中定義)
 

 

__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
 {
  /* 非法的重裝載寄存器值 */
 if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)
  { 
     return (1UL);

   } 
 /* 設置重裝載寄存器的值 */
 SysTick->LOAD = (uint32_t)(ticks - 1UL);
 /* 設置 SysTick 的中斷優先級 */
 NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL);
 /* 加載 SysTick 計數器值 */
 SysTick->VAL = 0UL;
 /* 設置系統定時器的時鍾源為 AHBCLK
 使能 SysTick 定時器中斷
 使能 SysTick 定時器 */
 SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
 SysTick_CTRL_TICKINT_Msk |
 SysTick_CTRL_ENABLE_Msk;
 return (0UL);
 }

 3.1系統時基更新函數

#include <rtthread.h>
#include <rthw.h>

static rt_tick_t rt_tick = 0; /* 系統時基計數器 */ (1) 
extern rt_list_t rt_thread_priority_table[RT_THREAD_PRIORITY_MAX];


void rt_tick_increase(void) 
{
    rt_ubase_t i;
    struct rt_thread *thread;
    rt_tick ++; (2)

     /* 掃描就緒列表中所有線程的 remaining_tick,如果不為 0,則減 1 */
     for(i=0; i<RT_THREAD_PRIORITY_MAX; i++) (3)
     {
       thread = rt_list_entry( rt_thread_priority_table[i].next,
                    struct rt_thread,
tlist);
if(thread->remaining_tick > 0)   {   thread->remaining_tick --;   } } /* 系統調度 */ rt_schedule(); (4) }

(1)系統時基計數器,是一個全局變量,用來記錄產生了多少次SysTick 中斷。

(2)系統時基計數器加1操作

(3)掃描就緒列表中的remaining_tick,如果不為0,則減 1。

(4)進行系統調度

進入和離開中斷函數

#include <rtthread.h>
#include <rthw.h>
 /* 中斷計數器 */
volatile rt_uint8_t rt_interrupt_nest; (1)  

/** * 當 BSP 文件的中斷服務函數進入時會調用該函數 * * @note 請不要在應用程序中調用該函數 * * @see rt_interrupt_leave */ void rt_interrupt_enter(void) (2) {   rt_base_t level;   /* 關中斷 */   level = rt_hw_interrupt_disable();   /* 中斷計數器 ++ */   rt_interrupt_nest ++;   /* 開中斷 */   rt_hw_interrupt_enable(level); } /** * 當 BSP 文件的中斷服務函數離開時會調用該函數 * * @note 請不要在應用程序中調用該函數 * * @see rt_interrupt_enter */ void rt_interrupt_leave(void) (3) {   rt_base_t level;   /* 關中斷 */   level = rt_hw_interrupt_disable();   /* 中斷計數器-- */   rt_interrupt_nest --;   /* 開中斷 */   rt_hw_interrupt_enable(level); }

(1)中斷計數器,是一個全局變量,用來記錄中斷嵌套次數。

(2)進入中斷函數,中斷計數器rt_interrupt_nest 加1 操作。當BSP文件的中斷服務函數進入時會調用該函數,應用程序不能調用,切記。

(3)離開中斷函數,中斷計數器rt_interrupt_nest 減1操作。當BSP文件的中斷服務函數進入時會調用該函數,應用程序不能調用,切記。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM