時間片輪詢法


時間片輪詢法

時間片輪詢法是一種比較簡單易用的系統架構之一,它對於系統中的任務調度算法是分時處理。核心思路是把 CPU 的時間分時給各個任務使用。我們常用的定時方法是定時器,把調度器放在定時中,可以簡單的實現時間片輪詢法。

需要注意的是,這種方法的前提是執行的 每個任務都是短小精悍的,要不然一個任務執行的時間過長,大於其它任務設置的時間片值,那其它任務就無法保證按它預設的時間片來執行。

尤其需要注意任務中延時的使用,可能會產生不可預料的結果。如果任務內部需要延時的時候,或者說單個任務過長,需要保存任務執行到一半的狀態,建議使用狀態機切割長任務。

時間片輪詢法架構

一個時間片輪詢應用程序的架構是非常簡單的,包括一個任務結構體,一個中斷處理函數,一個輪詢執行任務函數。

設計一個結構體:

// 任務結構
typedef struct {
    uint8_t task_id;                  // 任務 ID
    uint16_t task_interval;             // 任務運行間隔時間
    void (*task_entry)(void);           // 要運行的任務
    volatile uint16_t task_tick_ms;     // 計時器
}task_info_t;

定時器復用和中斷處理

定時器可以是任意的定時器,這里采用系統滴答定時器 (systick) 來定時。systick 的配置就不細講,假設定時器的定時中斷為 10ms(可以自行設定,中斷過於頻繁效率就低,中斷太長,實時性差)。

timing_task_tick 函數就相當於中斷服務函數,需要在定時器的中斷服務函數中調用此函數。

// 為每個任務計時,每次中斷加 10ms
void timing_task_tick(void)
{
    uint8_t task_index = 0;

    while (task_index < ARRAY_SIZE(timing_task_array))
    {
        timing_task_array[task_index].task_tick_ms += CONFIG_SYSTEM_TICK_PERIOD_MS;     // 每次加一個 systick 周期,即 10ms
        task_index++;
    }
}

時間片輪詢實例

下面我就就說說怎樣應用吧,假設我們有三個任務:時鍾顯示,按鍵掃描,和工作狀態顯示。

定義一個上面定義的那種結構體數組

// 計算任務個數
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))

// 定義了 3 個任務
static task_info_t timing_task_array[] =
{
    {0, 100, task_disp_clock_running, 0},    // 顯示時鍾
    {1, 20, task_scan_key_running, 0},      // 按鍵掃描
    {2, 30, task_disp_ws_running, 0},       // 工作狀態顯示
};

在定義變量時,我們已經初始化了值,這些值的初始化,非常重要,跟具體的執行時間優先級等都有關系,這個需要自己掌握。

  1. 大概意思是,我們有三個任務,每 1s 執行一下時鍾顯示,因為我們的時鍾最小單位是 1s,所以在秒變化后才顯示一次就夠了。

  2. 由於按鍵在按下時會參數抖動,而我們知道一般按鍵的抖動大概是 20ms,那么我們在順序執行的函數中一般是延伸 20ms,而這里我們每 20ms 掃描一次,是非常不錯的出來,即達到了消抖的目的,也不會漏掉按鍵輸入。

  3. 為了能夠顯示按鍵后的其他提示和工作界面,我們這里設計每 30ms 顯示一次,如果你覺得反應慢了,你可以讓這些值小一點。后面的名稱是對應的函數名,你必須在應用程序中編寫這函數名稱和這三個一樣的任務。

編寫任務函數

//Description : 顯示任務
void task_disp_clock_running(void)
{

}

//Description : 掃描任務
void task_scan_key_running(void)
{

}

//Description : 工作狀態顯示
void task_disp_ws_running(void)
{

}

任務處理

// 任務計划表,輪詢執行任務
void timing_task_scheduler(void)
{
    uint8_t task_index = 0;

    while (1)
    {
        for (task_index = 0 ; task_index < ARRAY_SIZE(timing_task_array); task_index++)
        {
            if (timing_task_array[task_index].task_tick_ms >= timing_task_array[task_index].task_interval)
            {
                timing_task_array[task_index].task_tick_ms = 0;
                timing_task_array[task_index].task_entry();
            }
        }
    }
}

程序陷入死循環,依次判斷每個任務是否符合執行要求。如果是,則執行相應的任務函數;否則等待計時。


免責聲明!

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



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