FreeRTOS — 系統時鍾節拍和時間管理


以下內容轉載自安富萊電子:http://forum.armfly.com/forum.php

1 、FreeRTOS 的 時鍾 節拍

  任何操作系統都需要提供一個時鍾節拍,以供系統處理諸如延時、超時等與時間相關的事件。

  時鍾節拍是特定的周期性中斷,這個中斷可以看做是系統心跳。中斷之間的時間間隔取決於不同的應用,一般是 1ms – 100ms。時鍾的節拍中斷使得內核可以將任務延遲若干個時鍾節拍,以及當任務等待事件發生時,提供等待超時等依據。時鍾節拍率越快,系統的額外開銷就越大。

  

FreeRTOS 的系統時鍾節拍可以在配置文件 FreeRTOSConfig.h 里面設置:
#define configTICK_RATE_HZ ( ( TickType_t ) 1000 )
如上所示的宏定義配置表示系統時鍾節拍是 1KHz,即 1ms。

2 、FreeRTOS 的 時 間 管 理

  時間管理功能是 FreeRTOS 操作系統里面最基本的功能,同時也是必須要掌握好的。

  2.1 時間延遲

  FreeRTOS 中的時間延遲函數主要有以下兩個作用:

       

             

上面就是一個簡單的任務運行狀態的切換過程。

   2.2 FreeRTOS 的時間相關函數

FreeRTOS 時間相關的函數主要有以下 4 個:
 vTaskDelay ()
 vTaskDelayUntil ()
 xTaskGetTickCount()
 xTaskGetTickCountFromISR()
下面我們對這 4 個函數依次進行說明:

   2.3 函數 vTaskDelay

使用舉例:

  2.4 函數 vTaskDelayUntil

函數原型:
void vTaskDelayUntil( TickType_t *pxPreviousWakeTime, /* 存儲任務上次處於非阻塞狀態時刻的變量地址 */
          const TickType_t xTimeIncrement ); /* 周期性延遲時間 */


函數描述:
函數 vTaskDelayUntil 用於周期性延遲。
 第 1 個參數,存儲任務上次處於非阻塞狀態時刻的變量地址。
 第 2 個參數,周期性延遲時間。
使用這個函數要注意以下問題:
1. 使用此函數需要在 FreeRTOSConfig.h 配置文件中配置如下宏定義為 1
#define INCLUDE_vTaskDelayUntil 1

2. 用戶要注意此函數跟 vTaskDelay 的區別,2.7 小節詳細講解。

使用舉例:

 

2.5 函 數 xTaskGetTickCount

函數原型:
volatile TickType_t xTaskGetTickCount( void );
函數描述:
函數 xTaskGetTickCount 用於獲取系統當前運行的時鍾節拍數。
使用這個函數要注意以下問題:
1. 此函數用於在任務代碼里面調用,如果在中斷服務程序里面調用的話,需要使用函數xTaskGetTickCountFromISR,這兩個函數切不可混用

使用舉例:

  2.6 函 數 xTaskGetTickCountFromISR

函數原型:
volatile TickType_t xTaskGetTickCountFromISR( void );
函數描述:
函數 xTaskGetTickCountFromISR 用於獲取系統當前運行的時鍾節拍數。
使用這個函數要注意以下問題:
1. 此函數用於在中斷服務程序里面調用,如果在任務里面調用的話,需要使用函數 xTaskGetTickCount,
這兩個函數切不可混用。

使用舉例:

 

/*
*********************************************************************************************************
*  函 數 名: TIM6_IRQHandler
*  功能說明: TIM6 中斷服務程序。
*  形 參: 無
*  返 回 值: 無
*********************************************************************************************************
*/
void TIM6_IRQHandler( void )
{
TickType_t xTickCount;
xTickCount = xTaskGetTickCountFromISR();
}

 

  2.7 函數 vTaskDelay 和 vTaskDelayUntil 的區別

函數 vTaskDelayUntil 實現的是周期性延遲,而函數 vTaskDelay 實現的是相對性延遲,反映到實際
應用上有什么區別呢,下面就給大家舉一個簡單的例子。
運行條件:
 有一個 bsp_KeyScan 函數,這個函數處理時間大概耗時 2ms。
 有兩個任務,一個任務 Task1 是用的 vTaskDelay 延遲,延遲 10ms,另一個任務 Task2 是用的
vTaskDelayUntil 延遲,延遲 10ms。
 不考慮任務被搶占而造成的影響。
實際運行過程效果:
 Task1:
bsp_KeyScan+ vTaskDelay (10) ---> bsp_KeyScan + vTaskDelay (10)
|----2ms + 10ms 為一個周期------| |----2ms + 10ms 為一個周期----|
這個就是相對性的含義
 Task2:
bsp_KeyScan + vTaskDelayUntil ---------> bsp_KeyScan + vTaskDelayUntil
|----10ms 為一個周期(2ms 包含在 10ms 內)---| |----10ms 為一個周期------|
這就是周期性的含義。
下面我們通過函數 vTaskDelay 來實現 vTaskDelayUntil,會有一個更加全面的認識:

/*
*********************************************************************************************************
*  函 數 名: vTaskMsgPro
*  功能說明: 消息處理,這里是用作 LED 閃爍 
*  形 參: pvParameters 是在創建該任務時傳遞的形參
*  返 回 值: 無
* 優 先 級: 3
*********************************************************************************************************
*/
static void vTaskMsgPro(void *pvParameters)
{
  TickType_t xDelay, xNextTime;
  const TickType_t xFrequency = 200;
  /* 獲取 xFrequency 個時鍾節拍后的時間 */
  xNextTime = xTaskGetTickCount() + xFrequency;
  while(1)
  {
    bsp_LedToggle(3);
    /* 用 vTaskDelay 實現 vTaskDelayUntil() */
    xDelay = xNextTime - xTaskGetTickCount();
    xNextTime += xFrequency;
    if(xDelay <= xFrequency)
    {
      vTaskDelay(xDelay);
    }
  }
}

3、實驗 例程

實驗目的:
1. 學習 FreeRTOS 的周期性延遲和相對性延遲函數。
2. 注意相對性延遲函數 vTaskDelay 和周期性延遲函數 vTaskDelayUntil 的區別。

實驗內容:
1. K1 按鍵按下,串口打印任務執行情況(波特率 115200,數據位 8,奇偶校驗位無,停止位 1)。
2. K2 鍵按下,串口打印系統時鍾節拍數。

 

static void vTaskTaskUserIF(void *pvParameters)
{
    uint8_t ucKeyCode;
    uint8_t pcWriteBuffer[500];

    while(1)
    {
        ucKeyCode = bsp_GetKey();
        
        if (ucKeyCode != KEY_NONE)
        {
            switch (ucKeyCode)
            {
                /* K1鍵按下 打印任務執行情況 */
                case KEY_DOWN_K1:             
                    printf("=================================================\r\n");
                    printf("任務名      任務狀態 優先級   剩余棧 任務序號\r\n");
                    vTaskList((char *)&pcWriteBuffer);
                    printf("%s\r\n", pcWriteBuffer);
                
                    printf("\r\n任務名       運行計數         使用率\r\n");
                    vTaskGetRunTimeStats((char *)&pcWriteBuffer);
                    printf("%s\r\n", pcWriteBuffer);
                    break;
                
                /* K1鍵按下 打印系統時鍾節拍數 */
                case KEY_DOWN_K2:             
                    printf("當前的系統時鍾節拍數 = %d\r\n", xTaskGetTickCount());
                    break;
                
                /* 其他的鍵值不處理 */
                default:                     
                    break;
            }
        }
        
        vTaskDelay(20);
    }
}

 

 

 


免責聲明!

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



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