advertisement

2014年10月31日

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

Queue(佇列)



API
建立Queue
送到Queue
接收Queue

xQueueCreate(Queue長度,項目大小)//Queue長度:格位的個數,項目大小:格位容量
xQueueSendToBack(Queue指標,(void *)格位資料,等待之滴答次數)//若佇列滿的話,變會議值等待,等待多久即為等待之滴答次數
xQueueReceiveFrom(Queue指標,(void *)格位資料,等待之滴答次數)//若佇列為空即開始等待,否則無法接收資料
Queue主要用於資料同步(synchronigation)
確保資料進出順序是正確的

void Task1(void *ptr) {
        unsigned long valToSend;
        char *str=(char *)ptr;
        valToSend=0;
        while(1) {
                xQueueSendToBack(Queue1,(void *)&valToSend,0);//若沒有其他要處理的事情,其等待時間可以給他比較大的值,其有他事情則等待可以給低一點,若為0表示不會等待直接往下執行,若滿的話會回傳失敗,空的會回傳成功,本範例假設他絕對不會滿,故等待設成0
                printf("%s,valToSend=%ld\n",str,valToSend);
                valToSend++;
                taskYIELD();
        }
}

void Task2(void *ptr) {
        unsigned long rcvValue;
        char *str=(char *)ptr;
        portBASE_TYPE status;
        while(1) {
                status=xQueueReceive(Queue1,(void *)&rcvValue,50);
                if(status==pdPASS) {
                        printf("%s,rcvValue=%ld\n",str,rcvValue);
                }
                else {
                        printf("%s,Queue empty.\n",str);
                }
        }
}

int main() {//主程式主要建立工作跟佇列和初始值
        Queue1=xQueueCreate(10,sizeof(unsigned long));
        if(Queue1!=NULL) {//若等於NULL表示建立失敗
                xTaskCreate(Task1,"SendTask",256,"Task 1",1,NULL);
                xTaskCreate(Task2,"RcvTask",256,"Task 2",1,NULL);
                vTaskStartScheduler();
                while(1);
        }
        return 0;
}

第二節-----------------------------------------------------------------------
中斷管理(Interrupt Management)

目的:希望在中斷服務程式中的時間越短越好(目的為了讓外界的反應更加靈敏,才不會延延遲太久),並且處理事情不會減少
注意!原先需在中斷服務程式中執行的動作,需能在多工作業環境下執行

作法:推遲中斷defered interrupt當中斷產生時,在中斷服務程式(喚醒高優先權之工作,並執行文本切換,剩下的執行內容交由給工作Task執行,故中斷很快就完成,不會耽誤太久)中喚醒(去阻斷,unblock)一高優先權之工作,再由高優先權工作接手,原中斷服務程式需執行之動作,而中斷服務程式,喚醒高優先權工作後,需執行文本切換,之後即可結束中斷,與中斷搭配之高優先權工作通常稱為中斷處理工作(handlerTask)

要實作推遲中斷,需用到二元信號(binary semaphore)
semaphore為Queue之一種
binary semaphore為Queue長度=1之Queue


高優先權(中斷處理工作)一開始即會一直拿binary semaphore之資料並一直等待,直到中斷產生將訊號傳至binary semaphore,待高優先權接收後,即可被喚醒。

二元信號產生時,信號為空的,當中斷產生時,在中斷服務程式中寫入二元信號,此時高優先權工作讀到二元信號,即可被喚醒。

中斷

推遲中斷工作時序圖如下

二元信號API(應用程式介面=副程式)
二元信號處理指標xSemaphoreHandle
產生二元信號 vSemaphoreCreateBinary(xSemaphoreHandle 二元信號處理指標變數)
    成功時二元信號變數有值,否則二元信號變數為NULL
給信號
    在中斷服務程式中 xSemaphoreGiveFromISR (二元信號處理指標,portBASE_TYPE *TaskWoken)//portBASE_TYPE *TaskWoken表示此API執行是否成功

當中斷處理工作被喚醒成功且其優先權高於目前工作優先權,則TaskWoken等於pdTRUE(表示成功),此API會回傳
pdPASS ->表示丟入Queue給信號成功
pdFAIL ->表示二元信號Queue已滿

通常為中斷服務程式給信號,高優先權工作取信號

第三節-----------------------------------------------------------------

通常在工作中取信號
取信號API xSemaphoreTake(二元信號處理指標,等待滴答數)
例:
xSemaphoreHandle xBinarySemaphore1;
vSemaphoreCreateBinary(xBinarySemaphore1);
在中斷服務程式中給信號
xSemaphoreGiveFromISR(xBinarySemaphore1,&TaskWoken);TaskWoken需宣告portBASE_TYPE TaskWoken;

在處理工作中取信號
xSemaphoreTake(xBinarySemaphore1,100);


範例程式:此範例僅能在Dos下執行
有一週期工作,在此工作呼叫軟體中斷,在軟體中斷服務程式,將給一個二元信號並執行文本切換,喚醒中斷處理工作

xSemaphoreHandle xBinarySemaphore;
void periodTask(void *ptr) {//週期工作
        while(1) {
                vTaskDelay(500);
                printf("about to generate an interrupt\n");
                --asm{int 0x82}
                printf("interrupt fenerate\n");
        }
}
//中斷處理工作
void handlerTask(void *ptr) {
        while(1) {
                xSemaphoreTake(xBinarySemaphore,portMAX_DELAY);//portMAX_DELAY表示FreeRTOS最長的等待時間
                printf("Handle interrupt\n");//原先在中斷內所要執行的動作即加在此後執行
        }    
}    
//中斷服務程式ISR
static void __interrupt __far intISR() {//再不同的作業系統或程式語言會有不一樣的寫法
        static portBASE_TYPE TaskWoken;
        TaskWoken=pdFALSE;
        xSemaphoreGiveFromISR(xBinarySemaphore,&TaskWoken);
        if(TaskWoken==pdPASS) {//成功喚醒處理工作
                portSWITCH_CONTEXT();//文本切換
        }    
}    
//主程式
int main() {
        vSemaphoreCreateBinary(xBinarySemaphore);
        _dos_setvect(0x82,intISR);
        if(xBinarySemaphore!=NULL) {
                xTaskCreate(handlerTask,"ISR Handler",256,NULL,3,NULL);
                xTaskCreate(periodTask,"Periodic Task",256,NULL,1,NULL);
                vTaskStartScheduler();
                while(1);
        }    
        reeturn 0;
}

system tick為system計時中斷之計數器每次系統計時中斷產生時,system tick計數器會加1
多工作業系統一定會系統滴答(system tick)(優先權最高),系統滴答進入中斷後Tick就會加1

上一篇

沒有留言:

張貼留言

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