advertisement

2014年10月17日

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

範例
task1,task2具相同優先權時,其時序圖如下:


void printTask1(void *ptr)
{
    int i;
    char *str="Task 1\n";
    while(1) {
        printf(str);
        for(i=0;i<10000;i++);
    }
}

void printTask2(void *ptr)
{
    int i;
    char *str="Task 2\n";
    while(1) {
        printf(str);
        for(i=0;i<10000;i++);
    }
}

int main(void) {
    xTaskCreat(printTask1,"Task 1",256,NULL,1,NULL);
    xTaskCreat(printTask1,"Task 2",256,NULL,1,NULL);
    vTaskStartScheduler();
    while(1);
    return 0;
}

不同工作共用工作程序
使用參數
上一範例Task1,Task2只有列印字串不同,故可以共用工作程序,將要列印字串以參數輸入
範例
void printTask(void *ptr)//空資料型態,讓程式碼可以接收任何資料型態,在程式碼中在予以轉型成所要的資料型態
{
    char *str;
    int i;
    str=(char *)ptr;
    while(1) {
        printf(str);
        for(i=0;i<10000;i++);
    }
}

int main(void) {
    char *str1="Task 1\n"
    char *str2="Task 2\n"
    xTaskCreat(printTask,"Task 1",256,(void *)str1,1,NULL);
    xTaskCreat(printTask,"Task 2",256,(void *)str2,1,NULL);
    vTaskStartScheduler();
    while(1);
    return 0;
}

void printTask(void *ptr)
{
char *str;
int i;
str=(char *)ptr;
while(1){
        printf(str);
        for(i=0;i<10000;i++);
        }
}
int main(void){
        char *str1="Task1 \n";
        char *str2="Task2 \n";
        xTaskCreate(printTask,"Task1",256,(void *)str1,1,NULL);
        xTaskCreate(printTask,"Task2",256,(void *)str2,1,NULL);
        vTaskStartScheduler();
        while(1);
        return 0;
}


clementyan@Lenovo-B480:~$ cd Document/micro/Posix_GCC_Simulator/FreeRTOS_Posix/Release/
clementyan@Lenovo-B480:~/Document/micro/Posix_GCC_Simulator/FreeRTOS_Posix/Release$ mkdir example
clementyan@Lenovo-B480:~/Document/micro/Posix_GCC_Simulator/FreeRTOS_Posix/Release$ cd example/
clementyan@Lenovo-B480:~/Document/micro/Posix_GCC_Simulator/FreeRTOS_Posix/Release/example$ mkdir ex1
clementyan@Lenovo-B480:~/Document/micro/Posix_GCC_Simulator/FreeRTOS_Posix/Release/example$ cd ex1/
clementyan@Lenovo-B480:~/Document/micro/Posix_GCC_Simulator/FreeRTOS_Posix/Release/example/ex1$
clementyan@Lenovo-B480:~/Document/micro/Posix_GCC_Simulator/FreeRTOS_Posix/Release/example/ex1$ vi main.c

將上述範例寫入main.c 注意:需使用數位學習網頁上之main.c模板

撰寫完成後把main.c複製到FreeRTOS_Posix
在至Release底下
make clean
make

clementyan@Lenovo-B480:~/Document/micro/Posix_GCC_Simulator/FreeRTOS_Posix/Release/example/ex1$ cp main.c ../../../main1.c
clementyan@Lenovo-B480:~/Document/micro/Posix_GCC_Simulator/FreeRTOS_Posix/Release/example/ex1$ cd ../../../
clementyan@Lenovo-B480:~/Document/micro/Posix_GCC_Simulator/FreeRTOS_Posix$
clementyan@Lenovo-B480:~/Document/micro/Posix_GCC_Simulator/FreeRTOS_Posix/Release$ make
clementyan@Lenovo-B480:~/Document/micro/Posix_GCC_Simulator/FreeRTOS_Posix/Release$ make clean

不同優先權時序圖如下:

大於Tick中斷→Task1進入Ready→排程管理員找所有Ready工作中優先權最高之工作來執行或輪流→Task1最高故執行Task1工作→低優先權工作將飢餓而死(starvation)

避免飢餓現象,高優先權工作需進入阻斷狀態(blocked state),即當高優先權工作進入等待時間需能讓出執行權,通常可經由阻斷API呼叫而達成

阻斷API有下列兩個
vTaskDelay(延遲滴答數)//延遲時間較不固定
vTaskDelayUntil(上次工作時間,延遲滴答數)//延遲時間較固定
排程管理元只看ready的工作,在阻斷狀態不會被檢查到,故不會執行,只有在ready狀態時被排程管理員看到才會被執行
方塊圖如下:


時序圖圖下:


void vTask1(void *ptr) {//priority=2
        char *str=(char *)ptr;
        while(1) {
                printf(str);
                vTaskDelay(20);
        }
}

void vTask2(void *ptr) {//priority=1
        char *str=(char *)ptr;
        int i;
        while(1) {
                printf(str);
                vTaskDelay(2);
        }
}

int main(void) {
        char *str1="Task 1\n";
        char *str2="Task 2\n";
        xTaskCreate(vTask1,"Task 1",256,(void *)str1,2,NULL);
        xTaskCreate(vTask2,"Task 2",256,(void *)str2,1,NULL);
        vTaskStartScheduler();
        while(1);
        return 0;
}

vTaskDelayUntil與vTaskDelay功能相似,但可以達到更精確之時間延遲

取得執行時間(目前系統之滴答數)其資料型態為portTickType故變數之宣告方式為portTicktype 變數名稱;

porTickType xLastWakeTime;
xLastWakeTime=xTaskGetTickCount();
使用vTaskDelayUntil之工作程序格式為
void 工作名稱(void *ptr) {
    portTickType xLastWake;
    xLastWake=xTaskGetTickCount();//會有一個Tick的時間誤差,但較精準
.
.
    while(1) {
.
.
    vTaskDelayUntil(xLastWake,延遲之Tick數);
}
}

透過工作指標改變工作優先權,一此方式亦可解決飢餓現象,其方法為高優先權之工作提升低優先權工作之優先權,使其可以取得工作時間,但也需低優先權工作需回覆自己之優先權,以維護程式之正常運作(由高優先權來決定是否要給低優先權工作,則可以提高低優先權之優先權)

工作指標(Task Handle)之資料型態為
xTaskHandle工作指標變數之宣告
xTaskHandle 工作指標變數名稱;
通常需宣告為全域變數

取得工作指標(由xTaskCreate函式之第六個參數位置可以取得)
如:
xTaskHandle task1Handle;
xTaskHandle task2Handle;
int main(void) {
    xTaskCreate(vTask1,"Task 1",256,NULL,2,&task1Handle);//&task1Handle指該task1Handle變數的位址
    xTaskCreate(vTask2,"Task 2",256,NULL,2,&task2Handle);
.
.
}
更改優先權
vTaskPrioritySet(工作指標,優先權值)要更改工作自己優先權時,工作指標為NULL

取得工作優先權之API
uxTaskPriorityGet(工作指標)
其回傳值之資料型態為portBASE.TYPE

porBASE.TYPE myPriority;
myPriority=uxTaskPriorityGet(NULL);//取得工作自己

更改優先權範例
原Task1優先權=2
    Task1優先權=1
執行Task1時將Task2之優先權提升為3
執行Task2時將Task2之優先權提升為1

xTaskHandle task2Handle;
void Task1(void *ptr) {
    char *str=(char *)ptr;
    int i;
    while(1) {
        printf(str);
        vTaskPrioritySet(&task2Handle,3);
        for(i=0;i<1000;i++);
    }
}
void Task2(void *ptr) {
    char *str=(char *)ptr;
    int i;
    while(1) {
        printf(str);
        vTaskPrioritySet(NULL,1);
        for(i=0;i<1000;i++);
    }
}

int main(void) {
        char *str1="Task 1\n";
        char *str2="Task 2\n";
        xTaskCreate(vTask1,"Task 1",256,(void *)str1,2,NULL);
        xTaskCreate(vTask2,"Task 2",256,(void *)str2,1,&task2Handle);
        vTaskStartScheduler();
        while(1);
        return 0;
}

上ㄧ篇     下一篇

沒有留言:

張貼留言

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