码迷,mamicode.com
首页 > 其他好文 > 详细

一步步开发自己的OS操作系统

时间:2015-09-12 08:30:34      阅读:193      评论:0      收藏:0      [点我收藏+]

标签:

我在MSP430单片机上调试的控制4个灯闪烁, 把原理搞清楚了一通则百通,可以举一返三;注:以下所讲的堆栈即栈,因为堆栈说习惯了 ,堆是堆栈是栈;

下面简单的介绍一下我的系统,其实还不能叫系统,因为太简单了,只有心脏在跳动,还没长大发育;

大家都知道切换任务时要保存现场,那现场到底要保存什么呢?

首先介绍一下我的任务栈怎么用的,在创建任务时先定义一个全局数组,如TASK1_TACK_SIZE[128];

|-------------------------------------------------------------------|

|func |   .....  |  ......  | .......  |   task stack......                           |

|-------------------------------------------------------------------|

高地址   ---->                                                                低地址

栈从高地址往低地址增长。

(1)创建任务时要传入 任务的入口地址 和 任务栈底地址。

任务入口地址(func)会存放在栈底部,任务创建好之后从第一个任务开始运行,第一个任务就是从任务栈里面取出func并调用,第一个任务就开始跑起来了。

(2)第二个任务怎么调用呢,当发生定时器中断时:

第一:首先自动把PC和SR压进当前的任务栈里;

|-------------------------------------------------------------------|

|func| ...|....|pc|sr | .......  |   task stack......                                 |

|---------------- ---  |----------------------------------------------|

高地址              |                                   -------->      低地址

                                |

                                |

                                |SP (此时栈指针可能指向这里)

第二:进入中断子函数,手动保存所有工作寄存器,除了中断会自动保存的PC和SR不需要保存其他都要保存,当然有人会问局部变量哪去了,需要保存吗,答应是不需要保存,因为局部变量就在栈里,在压入pc之前的就是局部变量或调用的子程序还没返回时被压栈的信息;

|-----------------------------------------------------------------------|

|func| ...|....|pc|sr |r4|r5|r6|r7|r8|r9| ...r14|r15|....  |   task stack.....  |

|---------------- -------------------------------- |---------------------|

高地址 -------->                                         |                       低地址

                                                                         |

                                                                         |

                                                                         |SP (此时栈指针指向这里)

此时需要保存当前的SP指针,把它指向的地址保存到任务块里的pTaskStk,下次恢复时只要把pTaskStk恢复到SP,我的任务描述是一个结构体;

//任务结构体

typedef struct 

{

  OSELK_STK *pTaskStk;// 任务栈指针

  volatile TaskSysTime   runTmr;//定时

  volatile TaskSysTime   runTmr_bak;//定时备份

  unsigned char taskId;

  unsigned char taskMode;//任务模式

  unsigned char taskState;//任务状态

  E_Task_func * func;//任务入口

}TaskFuncType, *PTaskFuncType;


第三:保存好当前任务现场时,取下一个任务块,把pTaskStk恢复给SP,sp指向哪里了呢, 怎么进入下一个任务入口呢,恢复下一个任务首先要POPALL 寄存器,任务初始化时要先初始化任务栈,pTaskStk要保存栈底地址+13,要预留12个寄存器的位置,因为切换任务时会POPALL 寄存器,栈会往高地址增长,最后POP PC时,即把PC 指向了func任务入口地址,下一个任务就被切换过来了,以此类推,每个任务切换都是这个过程,这样分时复用就开始跑起来了。



下面是中断代码:

/*<RBHead>

 ************************************************************************* 

 *                                                                                                                      * 

 *                                                                                           * 

 *                          STUTTGART                                                                            * 

 *                                                                                                                      * 

 *          Alle Rechte vorbehalten - All rights reserved                                               * 

 *                                                                                                                      * 

 ************************************************************************* 

   

 ************************************************************************* 

 *    

 ************************************************************************* 

 *

 * $Filename__:main.c$ 

 * 

 * $Author____:rao jun$ 

 * 

 * $Function__:TME ISR SW task  $ 

 * 

 ************************************************************************* 

 * $User______:jun.rao$ 

 * $Date______:31.08.2015$ 

 * $Class_____:$ 

 * $Name______:

 * $Variant___:1.0.0$ 

 * $Revision__:0$ 

 * $Type______:asm$ 

 * $State_____:debug$ 

 * $Generated_:$ 

 ************************************************************************* 

 * 

 * 

 ************************************************************************* 

 * List Of Changes 

 * 

 * $History

 * 

 * 

 * $ 

 * 

 ************************************************************************* 

 </RBHead>*/


#include <msp430f5247.h>


;********************************************************************************************************

;********************************************************************************************************

extern LKOS_TaskProcISR

extern pTaskStk

;********************************************************************************************************

;********************************************************************************************************

        RSEG    CODE            ; Program code

;********************************************************************************************************

;Interrupt ISR

;********************************************************************************************************

TIMER1_ISR


    dint;关闭中断

    push.w r4;保存工作寄存器

    push.w r5

    push.w r6

    push.w r7

    push.w r8

    push.w r9

    push.w r10

    push.w r11

    push.w r12

    push.w r13

    push.w r14

    push.w r15

    mov.w  sp,pTaskStk;保存当前的任务栈指针

    calla #LKOS_TaskProcISR;调用c语言 取一下任务栈指针

    mov.w pTaskStk,sp;恢复任务栈指针

    pop.w r15

    pop.w r14

    pop.w r13

    pop.w r12

    pop.w r11

    pop.w r10

    pop.w r9

    pop.w r8

    pop.w r7

    pop.w r6

    pop.w r5

    pop.w r4

    eint;开中断

    reti;这条指令中断返回指令,会自动执行 POP SR  ,POP PC,当POP PC时即任务被切换到下一个断点了

;********************************************************************************************************

;                                 

;

;  Interrupt vectors

;********************************************************************************************************

            COMMON  INTVEC


            ORG     TIMER1_A0_VECTOR

WDT_VEC     DW      TIMER1_ISR                 


            END

/**

 ***************************************************************************************************

 * create_task

 *

 * \param          func fun \ uint8 mode  \  uint32 tmr_ms  \  uint8 priority

 * \return          void

 *

 ***************************************************************************************************

 */

int create_task(E_Task_func* fun , unsigned int taskId , unsigned int *pStk , unsigned char mode , TaskSysTime tmr)

{

    PTaskFuncType  ptask_fun;

  

    if ((NULL == fun ) || (NULL == pStk))

        return (-1);


    ptask_fun = &Task_funcTab[taskId];//依次往数组里放

    if (taskId < MAX_TASK)

    {

        if (ptask_fun->taskMode == 0)

        {

            ptask_fun->func = fun;

            ptask_fun->taskMode = mode;

            ptask_fun->runTmr = tmr;

            ptask_fun->runTmr_bak =tmr;

            ptask_fun->pTaskStk = LKOS_TaskStackInit(fun,pStk,taskId); //初始化堆栈  

            ptask_fun->taskId = taskId;

            Task_Ctrl.CurTaskLens = taskId;

            return (ptask_fun->taskId);

        }

  }

  return (-1);

}

OSELK_STK * LKOS_TaskStackInit(E_Task_func* fun , OSELK_STK*stk,unsigned int taskId)

{

    memset(stk,0,strlen((char const*)stk));//栈清0,调用库比较慢


    *stk = (unsigned int)fun;//初始化时先把每个任务的入口地址存在栈底,切换任务的时候才能知道下一个任务在哪里

    

    return (stk-13);//初始化完栈让SP 跳过13个字节(sr 和r4-r15) ,因为在调用下一个任务时要POP 13个字节

}

/**

 ***************************************************************************************************

 * LKOS_TaskProcISR 中断调用的函数

 *                      轮询调度

 * \param          

 * \return          next_taskStk

 *

 ***************************************************************************************************

 */

void  LKOS_TaskProcISR(void)

{

    PTaskFuncType next_task=NULL;

    *Task_Ctrl.ppTaskStk = pTaskStk;//保存当前任务的SP

    if(Task_Ctrl.task_cnt < Task_Ctrl.CurTaskLens)

        Task_Ctrl.task_cnt++;  

    else

        Task_Ctrl.task_cnt = 0;

    next_task = LKOS_GetTaskTCBPtr(Task_Ctrl.task_cnt);

    Task_Ctrl.ppTaskStk = &next_task->pTaskStk;//一下个任务栈

    pTaskStk = next_task->pTaskStk;

    ConfigureTimerA();

}

/*----------------------------------------------------------------------------------------

 * TASK

 *----------------------------------------------------------------------------------------

 */

unsigned int  TASK1_STACK_SIZE[200]={0,0,};

unsigned int  TASK2_STACK_SIZE[200]={0,0,};

unsigned int  TASK3_STACK_SIZE[200]={0,0,};

unsigned int  TASK4_STACK_SIZE[200]={0,0,};

void LKOS_Task1(void);

void LKOS_Task2(void);

void LKOS_Task3(void);

void LKOS_Task4(void);

/*----------------------------------------------------------------------------------------

 * MAIN

 *----------------------------------------------------------------------------------------

 */

int main( void )

{


    TaskSysTime taskTmr;

  

    sys_BspInit();

    

    LKOS_TaskInit();

  

    taskTmr.ms = 15;

    create_task(LKOS_Task1,LKOS_Task1_ID,&TASK1_STACK_SIZE[200-1],TMR_MODE,taskTmr);

    

    taskTmr.ms = 25;

    create_task(LKOS_Task2,LKOS_Task2_ID,&TASK2_STACK_SIZE[200-1],TMR_MODE,taskTmr);

    

    taskTmr.ms = 25;

    create_task(LKOS_Task3,LKOS_Task3_ID,&TASK3_STACK_SIZE[200-1],TMR_MODE,taskTmr);

    

    taskTmr.ms = 15;

    create_task(LKOS_Task4,LKOS_Task4_ID,&TASK4_STACK_SIZE[200-1],TMR_MODE,taskTmr);

    

    LKOS_FirstTaskInit();


    while(1);

  

    return 0;

}

/**

 ***************************************************************************************************

 * LKOS_Task1

 *

 * \param          void

 * \return          void

 *

 ***************************************************************************************************

 */

void LKOS_Task1(void)

{

    int b = 6;

    int c = 1;

    int buf[10]={1,2,3,4,5,6,7,8,9};

    while(1)

    {

        if(b++<20)

        led1_on();

        Delayms(500);

        led1_off();

        Delayms(500);

    } 

}

/**

 ***************************************************************************************************

 * LKOS_Task2

 *

 * \param          void

 * \return          void

 *

 ***************************************************************************************************

 */

void LKOS_Task2(void)

{

  int a = 6;

  int c =  9;

  int tmp[10]={1,2,3,4,5,6,7,8,9};

  _EINT();

  while(1)

  {

    a++;

    led2_on();

    Delayms(100);

    a++;

    led2_off();

    Delayms(100);

  }

}


一步步开发自己的OS操作系统

标签:

原文地址:http://my.oschina.net/u/2457912/blog/505190

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!