<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 牛人業(yè)話 > 一步步寫STM32 OS【四】OS基本框架

          一步步寫STM32 OS【四】OS基本框架

          作者: 時間:2017-01-16 來源:網(wǎng)絡 收藏

            上一篇文章中,我們完成了兩個任務使用PendSV實現(xiàn)了互相切換的功能,下面我們接著其思路往下做。這次我們完成基本框架,即實現(xiàn)一個非搶占式(已經(jīng)調(diào)度的進程執(zhí)行完成,然后根據(jù)優(yōu)先級調(diào)度等待的進程)的任務調(diào)度系統(tǒng),至于搶占式的,就留給大家思考了。上次代碼中Task_Switch實現(xiàn)了兩個任務的切換,代碼如下:

          本文引用地址:http://www.ex-cimer.com/article/201701/342938.htm

            void Task_Switch()

            {

            if(g__Tcb_CurP == &TCB_1)

            g__Tcb_HighRdyP=&TCB_2;

            else

            g_OS_Tcb_HighRdyP=&TCB_1;

            OSCtxSw();

            }

            我們把要切換任務指針付給跟_OS_Tcb_HighRdyP,然后調(diào)用OSCtxSw觸發(fā)PendSV異常,就實現(xiàn)了任務的切換。如果是多個任務,我們只需找出就緒任務中優(yōu)先級最大的切換之即可。

            二、添加任務調(diào)度功能

            為了實現(xiàn)這一目標我們至少需要知道任務的狀態(tài)和時間等數(shù)據(jù)。我們定義了一個任務狀態(tài)枚舉類型OS_TASK_STA,方便添加修改狀態(tài)。在OS_TCB結構體中添加了兩個成員TimeDly和State,TimeDly是為了實現(xiàn)OS_TimeDly,至于State與優(yōu)先級一起是作為任務切換的依據(jù)。

            typedef enum OS_TASK_STA

            {

            TASK_READY,

            TASK_DELAY,

            } OS_TASK_STA;

            typedef struct OS_TCB

            {

            OS_STK *StkAddr;

            OS_U32 TimeDly;

            OS_TASK_STA State;

            }OS_TCB,*OS_TCBP;

            說到任務切換,我們必須面對臨界區(qū)的問題,在一些臨界的代碼兩端不加臨界區(qū)進去和退出代碼,會出現(xiàn)許多意想不到的問題。以下地方需要特別注意,對關鍵的全局變量的寫操作、對任務控制塊的操作等。進入臨界區(qū)和退出臨界區(qū)需要關閉和開啟中斷,我們采用uCOS中的一部分代碼:

            PUBLIC OS_CPU_SR_Save

            PUBLIC OS_CPU_SR_Restore

            OS_CPU_SR_Save

            MRS R0, PRIMASK

            CPSID I

            BX LR

            OS_CPU_SR_Restore

            MSR PRIMASK, R0

            BX LR

            #define OS_USE_CRITICAL OS_U32 cpu_sr;

            #define OS_ENTER_CRITICAL() {cpu_sr = OS_CPU_SR_Save();}

            #define OS_EXIT_CRITICAL() {OS_CPU_SR_Restore(cpu_sr);}

            #define OS_PendSV_Trigger() OSCtxSw()

            一個OS至少要有任務表,我們可以用數(shù)組,當然也可以用鏈表。為了簡單,我們使用數(shù)組,使用數(shù)組下表作為優(yōu)先級。當然,必要的地方一定要做數(shù)組越界檢查。

            #define OS_TASK_MAX_NUM 32

            OS_TCBP OS_TCB_TABLE[OS_TASK_MAX_NUM];

            為了使OS更完整,我們定義幾個全局變量,OS_TimeTick記錄系統(tǒng)時間,g_Prio_Cur記錄當前運行的任務優(yōu)先級,g_Prio_HighRdy記錄任務調(diào)度后就緒任務中的最高優(yōu)先級。

            OS_U32 OS_TimeTick;

            OS_U8 g_Prio_Cur;

            OS_U8 g_Prio_HighRdy;

            下面三個函數(shù)與PendSV一起實現(xiàn)了任務的調(diào)度功能。

            OS_Task_Switch函數(shù)功能:找出已就緒最高優(yōu)先級的任務,并將其TCB指針賦值給g_OS_Tcb_HighRdyP,將其優(yōu)先級賦值g_Prio_HighRdy。注意其中使用了臨界區(qū)。

            void OS_Task_Switch(void)

            {

            OS_S32 i;

            OS_TCBP tcb_p;

            OS_USE_CRITICAL

            for(i=0;i

            {

            tcb_p=OS_TCB_TABLE[i];

            if(tcb_p == NULL) continue;

            if(tcb_p->State==TASK_READY) break;

            }

            OS_ENTER_CRITICAL();

            g_OS_Tcb_HighRdyP=tcb_p;

            g_Prio_HighRdy=i;

            OS_EXIT_CRITICAL();

            }

            OS_TimeDly至當前任務為延時狀態(tài),并將延時時間賦值給當前TCB的TimeDly成員,并調(diào)用OS_Task_Switch函數(shù),然后觸發(fā)PendSV進行上下文切換。OS_Task_Switch找到就緒狀態(tài)中優(yōu)先級最高的,并將其賦值相關全局變量,作為上下文切換的依據(jù)。

            void OS_TimeDly(OS_U32 ticks)

            {

            OS_USE_CRITICAL

            OS_ENTER_CRITICAL();

            g_OS_Tcb_CurP->State=TASK_DELAY;

            g_OS_Tcb_CurP->TimeDly=ticks;

            OS_EXIT_CRITICAL();

            OS_Task_Switch();

            OS_PendSV_Trigger();

            }

            SysTick_Handler實現(xiàn)系統(tǒng)計時,并遍歷任務表,任務若是延時狀態(tài),就令其延時值減一,若減完后為零,就將其置為就緒狀態(tài)。

            void SysTick_Handler(void)

            {

            OS_TCBP tcb_p;

            OS_S32 i;

            OS_USE_CRITICAL

            OS_ENTER_CRITICAL();

            ++OS_TimeTick;

            for(i=0;i

            {

            tcb_p=OS_TCB_TABLE[i];

            if(tcb_p == NULL) continue;

            if(tcb_p->State==TASK_DELAY)

            {

            --tcb_p->TimeDly;

            if(tcb_p->TimeDly == 0)

            tcb_p->State=TASK_READY;

            }

            }

            OS_EXIT_CRITICAL();

            }

            當所有任務都沒就緒怎么辦?這時就需要空閑任務了,我們把它設為優(yōu)先級最低的任務。WFE指令為休眠指令,當來中斷時,退出休眠,然后看看有沒有已就緒的任務,有則調(diào)度之,否則繼續(xù)休眠,這樣可以減小功耗哦。

            void OS_Task_Idle(void)

            {

            while(1)

            {

            asm("WFE");

            OS_Task_Switch();

            OS_PendSV_Trigger();

            }

            }

            當一個任務只運行一次時(例如下面main.c的task1),結束時就會調(diào)用OS_Task_End函數(shù),此函數(shù)會調(diào)用OS_Task_Delete函數(shù)從任務表中刪除當前的任務,然后調(diào)度任務。

            void OS_Task_Delete(OS_U8 prio)

            {

            if(prio >= OS_TASK_MAX_NUM) return;

            OS_TCB_TABLE[prio]=0;

            }

            void OS_Task_End(void)

            {

            printf("Task of Prio %d Endn",g_Prio_Cur);

            OS_Task_Delete(g_Prio_Cur);

            OS_Task_Switch();

            OS_PendSV_Trigger();

            }

            三、OS實戰(zhàn)

            下面是完整的main.c代碼:

            #include "stdio.h"

            #include "stm32f4xx.h"

            #define OS_EXCEPT_STK_SIZE 1024

            #define TASK_1_STK_SIZE 128

            #define TASK_2_STK_SIZE 128

            #define TASK_3_STK_SIZE 128

            #define TASK_IDLE_STK_SIZE 1024

            #define OS_TASK_MAX_NUM 32

            #define OS_TICKS_PER_SECOND 1000

            #define OS_USE_CRITICAL OS_U32 cpu_sr;

            #define OS_ENTER_CRITICAL() {cpu_sr = OS_CPU_SR_Save();}

            #define OS_EXIT_CRITICAL() {OS_CPU_SR_Restore(cpu_sr);}

            #define OS_PendSV_Trigger() OSCtxSw()

            typedef signed char OS_S8;

            typedef signed short OS_S16;

            typedef signed int OS_S32;

            typedef unsigned char OS_U8;

            typedef unsigned short OS_U16;

            typedef unsigned int OS_U32;

            typedef unsigned int OS_STK;

            typedef void (*OS_TASK)(void);

            typedef enum OS_TASK_STA

            {

            TASK_READY,

            TASK_DELAY,

            } OS_TASK_STA;

            typedef struct OS_TCB

            {

            OS_STK *StkAddr;

            OS_U32 TimeDly;

            OS_U8 State;

            }OS_TCB,*OS_TCBP;

            OS_TCBP OS_TCB_TABLE[OS_TASK_MAX_NUM];

            OS_TCBP g_OS_Tcb_CurP;

            OS_TCBP g_OS_Tcb_HighRdyP;

            OS_U32 OS_TimeTick;

            OS_U8 g_Prio_Cur;

            OS_U8 g_Prio_HighRdy;

            static OS_STK OS_CPU_ExceptStk[OS_EXCEPT_STK_SIZE];

            OS_STK *g_OS_CPU_ExceptStkBase;

            static OS_TCB TCB_1;

            static OS_TCB TCB_2;

            static OS_TCB TCB_3;

            static OS_TCB TCB_IDLE;

            static OS_STK TASK_1_STK[TASK_1_STK_SIZE];

            static OS_STK TASK_2_STK[TASK_2_STK_SIZE];

            static OS_STK TASK_3_STK[TASK_3_STK_SIZE];

            static OS_STK TASK_IDLE_STK[TASK_IDLE_STK_SIZE];

            extern OS_U32 SystemCoreClock;

            extern void OSStart_Asm(void);

            extern void OSCtxSw(void);

            extern OS_U32 OS_CPU_SR_Save(void);

            extern void OS_CPU_SR_Restore(OS_U32);

            void task_1(void);

            void task_2(void);

            void task_3(void);

            void OS_Task_Idle(void);

            void OS_TimeDly(OS_U32);

            void OS_Task_Switch(void);

            void OS_Task_Create(OS_TCB *,OS_TASK,OS_STK *,OS_U8);

            void OS_Task_Delete(OS_U8);

            void OS_Task_End(void);

            void OS_Init(void);

            void OS_Start(void);

            void task_1(void)

            {

            printf("[%d]Task 1 Runing!!!n",OS_TimeTick);

            OS_Task_Create(&TCB_2,task_2,&TASK_2_STK[TASK_2_STK_SIZE-1],5);

            OS_Task_Create(&TCB_3,task_3,&TASK_3_STK[TASK_3_STK_SIZE-1],7);

            }

            void task_2(void)

            {

            while(1)

            {

            printf("[%d]Task 2 Runing!!!n",OS_TimeTick);

            OS_TimeDly(1000);

            }

            }

            void task_3(void)

            {

            while(1)

            {

            printf("[%d]Task 3 Runing!!!n",OS_TimeTick);

            OS_TimeDly(1500);

            }

            }

            void OS_Task_Idle(void)

            {

            while(1)

            {

            asm("WFE");

            OS_Task_Switch();

            OS_PendSV_Trigger();

            }

            }

            void OS_TimeDly(OS_U32 ticks)

            {

            OS_USE_CRITICAL

            OS_ENTER_CRITICAL();

            g_OS_Tcb_CurP->State=TASK_DELAY;

            g_OS_Tcb_CurP->TimeDly=ticks;

            OS_EXIT_CRITICAL();

            OS_Task_Switch();

            OS_PendSV_Trigger();

            }

            void OS_Task_Switch(void)

            {

            OS_S32 i;

            OS_TCBP tcb_p;

            OS_USE_CRITICAL

            for(i=0;i

            {

            tcb_p=OS_TCB_TABLE[i];

            if(tcb_p == NULL) continue;

            if(tcb_p->State==TASK_READY) break;

            }

            OS_ENTER_CRITICAL();

            g_OS_Tcb_HighRdyP=tcb_p;

            g_Prio_HighRdy=i;

            OS_EXIT_CRITICAL();

            }

            void OS_Task_Delete(OS_U8 prio)

            {

            if(prio >= OS_TASK_MAX_NUM) return;

            OS_TCB_TABLE[prio]=0;

            }

            void OS_Task_End(void)

            {

            printf("Task of Prio %d Endn",g_Prio_Cur);

            OS_Task_Delete(g_Prio_Cur);

            OS_Task_Switch();

            OS_PendSV_Trigger();

            }

            void OS_Task_Create(OS_TCB *tcb,OS_TASK task,OS_STK *stk,OS_U8 prio)

            {

            OS_USE_CRITICAL

            OS_STK *p_stk;

            if(prio >= OS_TASK_MAX_NUM) return;

            OS_ENTER_CRITICAL();

            p_stk = stk;

            p_stk = (OS_STK *)((OS_STK)(p_stk) & 0xFFFFFFF8u);

            *(--p_stk) = (OS_STK)0x01000000uL; //xPSR

            *(--p_stk) = (OS_STK)task; // Entry Point

            *(--p_stk) = (OS_STK)OS_Task_End; // R14 (LR)

            *(--p_stk) = (OS_STK)0x12121212uL; // R12

            *(--p_stk) = (OS_STK)0x03030303uL; // R3

            *(--p_stk) = (OS_STK)0x02020202uL; // R2

            *(--p_stk) = (OS_STK)0x01010101uL; // R1

            *(--p_stk) = (OS_STK)0x00000000u; // R0

            *(--p_stk) = (OS_STK)0x11111111uL; // R11

            *(--p_stk) = (OS_STK)0x10101010uL; // R10

            *(--p_stk) = (OS_STK)0x09090909uL; // R9

            *(--p_stk) = (OS_STK)0x08080808uL; // R8

            *(--p_stk) = (OS_STK)0x07070707uL; // R7

            *(--p_stk) = (OS_STK)0x06060606uL; // R6

            *(--p_stk) = (OS_STK)0x05050505uL; // R5

            *(--p_stk) = (OS_STK)0x04040404uL; // R4

            tcb->StkAddr=p_stk;

            tcb->TimeDly=0;

            tcb->State=TASK_READY;

            OS_TCB_TABLE[prio]=tcb;

            OS_EXIT_CRITICAL();

            }

            void SysTick_Handler(void)

            {

            OS_TCBP tcb_p;

            OS_S32 i;

            OS_USE_CRITICAL

            OS_ENTER_CRITICAL();

            ++OS_TimeTick;

            for(i=0;i

            {

            tcb_p=OS_TCB_TABLE[i];

            if(tcb_p == NULL) continue;

            if(tcb_p->State==TASK_DELAY)

            {

            --tcb_p->TimeDly;

            if(tcb_p->TimeDly == 0)

            tcb_p->State=TASK_READY;

            }

            }

            OS_EXIT_CRITICAL();

            }

            void OS_Init(void)

            {

            int i;

            g_OS_CPU_ExceptStkBase = OS_CPU_ExceptStk + OS_EXCEPT_STK_SIZE - 1;

            asm("CPSID I");

            for(i=0;i

            OS_TCB_TABLE[i]=0;

            OS_TimeTick=0;

            OS_Task_Create(&TCB_IDLE,OS_Task_Idle,&TASK_IDLE_STK[TASK_IDLE_STK_SIZE-1],OS_TASK_MAX_NUM-1);

            }

            void OS_Start(void)

            {

            OS_Task_Switch();

            SystemCoreClockUpdate();

            SysTick_Config(SystemCoreClock/OS_TICKS_PER_SECOND);

            OSStart_Asm();

            }

            int main()

            {

            OS_Init();

            OS_Task_Create(&TCB_1,task_1,&TASK_1_STK[TASK_1_STK_SIZE-1],2);

            OS_Start();

            return 0;

            }

           

            os_port.asm變化不大,具體內(nèi)容可以下載文章末尾提供的工程參考。

            老規(guī)矩,下載調(diào)試,全速運行,觀察Terminal IO窗口:

              

          QQ截圖20131103215553

           

            從輸出來看,我們已經(jīng)完成了目標。但不保證穩(wěn)定性,可能有不少Bugs。至此,可以說其實寫一個OS并不難,難的是寫一個穩(wěn)定安全高效的OS。所以,現(xiàn)在只是走了一小步,想要完成一個成熟的OS,還需要不斷測試,不斷優(yōu)化。例如,我們采用數(shù)組存儲任務表,也可以采用鏈表,各有優(yōu)缺點。我們只有一個任務表,也可以分成多個表,例如就續(xù)表,等待表等等。我們的任務調(diào)度部分運行時間不確定,對于實時OS,這是不可以的,怎么修改呢,例如像uCOS的查找表法那樣?,F(xiàn)在我們的系統(tǒng)只能創(chuàng)建并調(diào)度任務,還未加入其他功能,例如信號量、郵箱、隊列、內(nèi)存管理等。其實到了這里,大家完全可以發(fā)揮自己的創(chuàng)造力,參照本文開發(fā)自己的OS。如果以后有時間的話,還會再寫幾篇文章繼續(xù)完善我們的OS。



          關鍵詞: STM32 OS

          評論


          相關推薦

          技術專區(qū)

          關閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();