advertisement

2014年10月24日

2014/10/24進階微控制器應用

vTaskDelay(延遲時間)從他呼叫開始計時
vTaskUntil(上次Task開始時間,延遲時間)從上次Task開始時間計時

Task2(void *ptr) {
    .//假設中間程式碼需50Ticks
    .
    vTaskDelay(100);
}

Task1(void *ptr) {
    取得執行開始時間
    .
    .//假設中間程式碼需50Ticks
    vTaskUntil(開始執行時間,100);
}

時序圖如下:


工作排程之方式(Scheduling)
主要有三種:

  1. Preemptive強佔式:以高優先權為主,只要高優先權之工作在就緒狀態,則高優先權工作將先執行,直到其進入阻斷或擱置狀態為止(作業系統多以此為主,其反應較快,有饑餓現象)
  2. Selecting選擇式:單調速率排程(Rate Montonic Sechedule)(反應速度中)高優先權工作具有高CPU執行頻率,低優先權工作具有低CPU執行頻率,例:O.S.每秒執行100次工作切換,優先權分別為1,2,3,之工作分配到的工作次數分別為17,33,50
  3. Co-operative合作式:沒有優先權,輪流執行,工作執行後,進入就緒狀態。(較安全的作業系統,不易當機,反應較慢)
第二、三、四節------------------------------------------------------------------------------------------------------------
FreeRTOS使用強佔式排程法

Delete A Task 刪除工作

API: vTaskDelete(工作處理指標)

範例:
主迴圈執行工作1
工作1產生工作2
工作2執行後,結束工作。

時序圖如下:


xTaskHandle hTask2;//宣告hTask2為全域變數,代表位址
void Task1(void *ptr) {
        char *str=(char *)ptr;
        while(1) {
                printf(str);
                xTaskCreate(Task2,"Task2",256,NULL,2,&hTask2);//Task2的位址在hTask2,256堆疊指標大小取決Task2函式內是否有push/pop,或呼叫副程式
                vTaskDelay(10);
        }
}

void Task2(void *ptr) {
        printf("Task2\n");
        vTaskDelete(hTask2);
}

int main(void) {
        char *str="Task1\n";
        xTaskCreate(Task1,"Task1",256,(void *)str1,1,NULL);
        vTaskStartScheduler();
        while(1);
        return 0;
}

Queue(佇列/排隊)

queue基本上為FIFO(first in first out)資料緩衝區

以上圖為列
資料由左邊進入後將會存放在最右邊第一個有空之格位,資料提取時,將提取最右邊之格住,最右邊格住資料被提取後,其他資料儲存格住需往右移一格。

Task1與Task2資料傳遞如圖:

Tassk之間透過Queue溝通資料

建立Queue
Queue處理指標之資料型態
xQueueHandle
建立Queue之API
使用xQueueCreate(unsigned portBASE_TYPE uxQueueLength,unsigned portBASE_TYPE uxItemSize)//uxQueueLength長度取決於頻率速度與存取速度,當進入速率快於讀取速率,則需把長度提高

上述API呼叫後會回傳Queue之處理指標,例:
xQueueHandle hQueueq;
hQueue1=xQueueCreate(10,256);

寫資料到Queue
主要有
xQueueSendToBack(Queue指標,(const void *)資料指標,等待之tick數)//資料指標需小於uxItemSize(每格容量)
xQueueSendToFront(Queue指標,(const void *)資料指標,等待之tick數)//插隊放置最右邊

正常資料寫入Queue之尾部,故需使用xQueueSendToBack(或xQueueSend)
當有一筆特殊資料需被優先處理可以使用xQueueSendToFront將資料寫入Queue之最右邊格位

當要寫入之Queue滿格,無法寫入時,Task會進入阻斷狀態,直到等待之ticks數之滴答數為止,重新進入就緒狀態

例:
void Task(void *ptr) {
        .
        .
        char data[256];
        .
        .
        xQueueSendToBack(hQueue1,(const void *)data,50);
}

由Queue讀取資料有
xQueueReceive(Queue指標,(const void *)資料指標,等待tick數)//讀取完後資料會清除
xQueuePeak(Queue指標,(const void *)資料指標,等待tick數)//讀取完後資料不會清除

xQueueReceive提取Queue最右邊(頭部)資料後,會將頭部資料刪除,Queue其他儲存格會往前移一格
但xQueuePeak只會讀取Queue頭部資料,但不會刪除
當讀取資料時,若Queue為空時,Task會進入阻斷狀態,直到等待tick數會再進入就緒狀態

xQueueMessageWating(Queue之指標)此API可以讀取Queue中有資料之格位數

範例:
Task1產生資料寫入Queue
Task2從Queue讀取資料

xQueueHandle xQueue;
void vSendTask(void *ptr) {
        long valueToSend; 
        portBASE_TYPE status;
        valueToSend=*((long *)ptr);
        while(1) {
                status=xQueueSendToBack(xQueue,&valueToSend,0);//0表示不等待
                if(status!=pdPASS) {
                        printf("Queue is full\n");
                }       
                taskYIELD();//讓出工作權
        }       
}   

xQueueHandle xQueue;
void vReceiveTask(void *ptr) {
        long ReceivedValue;
        portBASE_TYPE status;
        if(xQueueMessageWaiting(xQueue)!=0) {
                printf("Queue not empty\n");
        }       
        while(1) {
                status=xQueueReceive(xQueue,&ReceiveValue,10);//0表示不等待
                if(status==pdPASS) {
                        printf("Received Value=%l\n",ReceivedValue);
                }       
        }       

沒有留言:

張貼留言

文章有誤或有問題麻煩您留言告知! 謝謝您~~