FreeRTOS開發指南

1 FreeRTOS API
1.1 Time Delay
void vTaskDelay(portTickType xTicksToDelay);
延時參數:msecs / portTICK_RATE_MS,譬如延時500ms,vTaskDelay(500 / portTICK_RATE_MS)。

1.2 FreeRTOS定時器
FreeRTOS的定時器函數都是異步的(async)
xTimerStart()發送消息將TimerHandle_t添加到激活list中。
xTimerStop()發送消息將TimerHandle_t從激活list中刪除。
xTimerChangePeriod()發送消息將TimerHandle_t從激活list中刪除,修改超時時間,然後重新添加到激活list中。

1.3 睡眠喚醒
at kernel/rtos/FreeRTOS/Source/tasks.c
static portTASK_FUNCTION( prvIdleTask, pvParameters )
--->
portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime );

at kernel/rtos/FreeRTOS/Source/portable/GCC/XXX/port_tick.c
void tickless_handler(uint32_t xExpectedIdleTime)

2 FreeRTOS的隊列管理
2.1 基本概念
隊列是先進先出(FIFO, First-In-First-Out)的線性表。在具體應用中通常用鏈表或者數組來實現。隊列只允許在後端(稱爲rear)進行插入操作,在前端(稱爲front)進行刪除操作。隊列的操作方式和堆棧類似,唯一的區別在於隊列只允許新數據在後端進行添加。
在FreeRTOS中,對隊列有專門的管理機制及函數,在queue.h定義。使用隊列進行消息傳送,可以避免數據衝突與丟失等現象。如:有一個任務,需要根據另外三個任務的數據來執行它的操作或運行流程,且在這四個任務運行時,是不定時的,沒有任何規律可言,那麼按照傳統的公共變量的方式,就有可能產生數據丟失或數據訪問衝突。如果在這裏使用FreeRTOS的隊列來傳遞數據信息,則相當容易地把這種問題給解決了。在FreeRTOS中使用隊列,最簡單的應用,需要創建隊列、發送隊列消息、等待接收隊列消息、刪除隊列等操作。使用隊列,不僅可以傳送單字節消息,也可以傳送數據結構。在這裏,隊列管理相關的函數定義不就再進行說明了,需要時,可以參考queue.h。

2.2 FreeRTOS隊列的使用
有一組LED燈,在同一個物理操作端口上面,另外二個不同的任務,需要操作這組LED燈來指示系統狀態。這時,引入一個單獨的任務來操作這組LED燈,那二個不同的任務則向這一個LED燈操作任務發送消息來控制LED燈。應用程序框架如下所示:

1)定義消息數據結構及變量
typedef struct //定義一個需要傳遞的消息的數據結構
{
    u8 msg_src; // 消息來源編號
    u8 msg_val; // 消息值
} led_msg;

#define  TASK1_MSG  0x1 // 定義任務1所傳遞的消息
#define  TASK2_MSG  0x2 // 定義任務2所傳遞的消息

xQueueHandle  led_msg_handle; // 用於傳遞消息的一個公共Handle變量

2)在main程序中,創建一個消息用於消息的傳遞
led_msg_handle = xQueueCreate(10 , sizeof(led_msg)); // 創建一個消息,最多可以有10個值進行排隊,每個值的大小爲數據結構led_msg大小。

3)在LED燈操作的任務中等待消息並處理
void led_task(void *pvParameters)
{
    led_msg receive_msg;
    while (1) // 該任務是一個不退出的循環任務
    {
        while (xQueueReceive(led_msg_handle, &receive_msg, portMAX_DELAY) != pdPASS ); // 等待消息直到收到一個有效的消息數據,並放入receive_msg變量中
        switch (receive_msg.msg_src)
        {
            case TASK1_MSG:
                ; // 執行任務1傳遞過來的消息,對LED的操作
                break;
            case TASK2_MSG:
                ; // 執行任務2傳遞過來的消息,對LED的操作
                break;
            default:
                break;
        }
    }
}

4)消息的發送
void task1(void *pvParameters)
{
    led_msg send_msg;
    while (1)
    {
        ; //任務1的任務部份
        send_msg. msg_src = TASK1_MSG; //指定任務1消息編號
        send_msg. msg_val = 0x1; //假定該任務要傳遞的值爲0x1
        xQueueSend(led_msg_handle, &send_msg, portMAX_DELAY); //發送消息
    }
}

void task2(void *pvParameters)
{
    led_msg send_msg;
    while (1)
    {
        ; //任務2的任務部份
        send_msg. msg_src = TASK2_MSG; //指定任務2消息編號
        send_msg. msg_val = 0x2; //假定該任務要傳遞的值爲0x2
        xQueueSend(led_msg_handle, &send_msg, portMAX_DELAY); //發送消息
    }
}
到此,隊列的基本應用例子程序已完成。如果在應用程序中的某種條件下,不再需要這個隊列,則可以調用xQueueDelete(led_msg_handle)將該隊列刪除。

3 Abbreviations
AWS IOT:Amazon Web Service

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章