您当前的位置:五五电子网电子知识单片机-工控设备嵌入式系统-技术基于MC68HC908GP32的μC/OS-II移植 正文
基于MC68HC908GP32的μC/OS-II移植

基于MC68HC908GP32的μC/OS-II移植

点击数:7449 次   录入时间:03-04 11:59:12   整理:http://www.55dianzi.com   嵌入式系统-技术

  #define    STACK_DIR    stack_dir

  static void

  find_stack_direction ()

  {

  static char *addr = NULL;    /* Address of first `dummy', once known.  */

  auto char dummy;        /* To get stack address.  */

  if (addr == NULL)

  {                /* Initial entry.  */

  addr = ADDRESS_FUNCTION (dummy);

  find_stack_direction ();    /* Recurse once.  */

  }

  else

  {

  /* Second entry.  */

  if (ADDRESS_FUNCTION (dummy) > addr)

  stack_dir = 1;        /* Stack grew upward.  */

  else

  stack_dir = -1;        /* Stack grew downward.  */

  }

  }

  #endif /* STACK_DIRECTION == 0 */

  (4)OS_TASK_SW()函数的定义

  在μC/OS-II中,OS_TASK_SW()用来实现任务切换。就绪任务的堆栈初始化应该模拟一次中断发生后的样子,堆栈中应该按进栈次序设置好各个寄存器的内容。OS_TASK_SW()函数模拟一次中断过程,在中断返回的时候进行任务切换。GP32中可采用软中断指令SWI实现任务切换。中断服务程序的入口点必须指向汇编函数OSCtxSw()。

  OS_TASK_SW()的定义:

  #define OS_TASK_SW() asm swi

  3.OS_CPU08.ASM文件

  μC/OS-II的移植需要改写OS_CPU08.ASM中的4个函数:OSStartHighRdy()、OSCtxSw()、OSINTCtxSw()和OSTickISR()。

  (1)OSStartHighRdy()函数

  该函数由SStart()函数调用,功能是运行优先级最高的就绪任务。在调用OSStart()之前,必须先调用OSInit(),并且已经至少创建了一个任务。为了启动任务,OSStartHighRdy()首先找到当前就绪的优先级最高的任务(OSTCBHighRdy中保存有优先级最高任务的任务控制块-TCB的地址),并从任务的任务控制块(OS_TCB)中找到指向堆栈的指针,然后从堆栈中弹出全部寄存器的内容,运行RTE中断返回。需要说明的是,由于GP32中有512字节RAM,所以地址指针必须是16位的;而GP32中累加寄存器A为8位,所以用累加器A传递地址必须进行两次读入、输出操作。

  Void OSStartHighRdy(void)

  {asm

  {

  jsr OSTaskSwHook //调用用户定义接口函数

  lda OSRunning //设置OSRunning变量,标志进入多任务模式

  inca

  sta OSRunning

  ldx OSTCBHighRdy //取得最高优先级就绪任务TCB地址

  stx OSTCBCur //保存到OSTCBCur中

  pshx

  ldx OSTCBHighRdy:1//保存地址的第二个字节

  stx OSTCBCur:1

  pulh

  lda 0,X //载放就绪任务堆栈指针

  psha

  ldx 1,X //载入就绪任务堆栈指针第二个字节

  pulh

  txs

  pulh //恢复索引寄存器内容

  rti //中断返回,运行新任务

  }}

  (2)OSCtxSw()函数

  OSCtxSw()是一个任务级的任务切换函数(在任务中调用,区别于在中断程序中调用的OSIntCtxSw())。在GP32上实现,可通过执行一条软中断指令SWI来实现任务切换。软中断向量指向OSCtxSw()。如果OSSched()将查找当前就绪的优先级最高的任务,若不是当前任务,则判断是否需要进行任务调度,并找到该任务控制块OS_TCB的地址,将该地址拷贝到变量OSTCBHighRdy中,然后通过宏OS_TASK_SW()执行软中断进行任务切换。在此过程中,变量OSTCBCur始终包含一个指向当前运行任务OS_TCB的指针。OSCtxSw()的汇编代码如下:

  Void OSCtxSw(void)

  {asm

  {pshh //保存X寄存器

  tsx

  pshx

  pshh

  dx OSTCBCur //载入当前任务的TCB指针

  pshx

  ldx OSTCBCur:1 //载入TCB的第二个字节

  pulh

  pula

  sta 0,x //保存当前堆栈指针

  pula

  sta 1,x

  jsr OSTaskSwHook //调用用户定义的接口函数

  lda OSPrioHighRdy //设置OSPrioCur=OSPrioHighRdy

  sta OSPrioCur

  pshx

  ldx OSTCBHighRdy:1

  stx OSTCBCur:1

  pulh

  lda 0,x //载入堆栈指针

  psha

  ldx,1,x

  pulh

  txs

  pulh //恢复索引寄存器内容

  rti //中断返回,切换任务

  }}

  (3)OSTickISR()函数

  在μC/OS-II中,当调用OSStart()启动多任务环境后,时钟中断的使用是非常重要的。在时钟中断程序中负责处理所有与定时相关的工作,如任务的延时、等待操作等等。在时钟中断中将查询处于等待状态的任务,判断是否延时结束,否则将重新进行任务调度。

  为GP32编写的函数OSTickISR()的代码如下:

  void OSTickISR()void{

  asm{

  pshh

  LDA T1SC

  BCLR 7,T1SC //允许中断嵌套

  }

  OsintEnter(); /*标志进入中断*/

  OSTimeTick(); /*调用时钟节拍函数*/

  OSlntExit(); /*标志退出中断*/

  Asm{

  Pulh

  Rti

  }}

  和μC/OS-II中的其他中断服务程序一样,OSTickISR()首先在被中断任务堆栈中保存CPU寄存器的值,然后调用OSIntEnter()。μC/OS-II要求在中断服务程序开头调用OSIntEnter(),其作用是将记录中断嵌套层数的全局变量OSIntNesting加1。如果不调用OSIntEnter(),直接将OSIntNesting加1也是允许的。随后,OSTickISR()调用OSTimeTick(),检查所有处于延时等待状态的任务,判断是否有延时结束就绪的任务。在OSTickISR()的最后调用OSIntExit(),如果在中断中(或其他嵌套的中断)有更高优先级的任务就绪,并且当前中断为中断嵌套的最后一层,OSIntExit()将进行任务调度。如果当有中断不是中断嵌套的最后一层,或中断中没有改变任务的就绪状态,OSIntExit()将返回调用者OSTickISR(),最后OSTickISR()返回被中断的任务。

  4.OS_CPU08.C文件

  μC/OS-II的移植需要用户在OS_CPU08.C中定义6个函数:

  OSTaskStkInit()

  OSTaskCreateHook()

  OSTaskDelHook()

  OSTaskSwHook()

  OSTaskStatHook()

  OSTimeTickHook()

  OSTaskStkInit()函数由任务创建函数OSTaskCreate()或OSTaskCreateExt()调用,用来初始化任务的堆栈。初始状态的堆栈模拟发生一次中断后的堆栈结构,按照中断后的进栈次序预留各个寄存器存储空间;而中断返回地址指向任务代码的起始地址。当调用OSTaskCreate()或OSTaskCreateExt()创建一个新任务时,需要传递的参数是:任务代码的起始地址、参数指针(pdata)、任务堆栈顶端的地址、任务的优先级。堆栈初始化工作结束后,OSTaskStkInit()返回新的堆栈栈顶指针,OSTaskCreate()OSTaskCreateExt()将指针保存在任务的OS_TCB中。

  Void*OSTaskStklint(void(*task)(void*pd),void*pdata,void*ptos,INT16U opt)

  {

  INT16U *stk;

  stk=(INT16U*)ptos; /*保存堆栈指针*/

  *--stk=(INT16U)(task); /保存程序计数器内容*/

  *--stk=(INT16U)(0x00); /初始化X和A寄存器内容*/

  --stk=(INT16U)(0x00); /*初始化CCR和H寄存器*/

  return((void*)stk);

  }

  其余的几个函数:OSTaskCreateHook()、OSTaskDelHook()、OSTaskSwHook()、OSTaskStatHook和OSTimeTickHook()均由用户自定义。

  四、制作用户自己的项目

  在为内核编写了上述与硬件相关的代码以后,用户就可以为自己的项目编写实际的代码了。在本例中,用户任务共有两个。任务1在初始化时钟中断以后,就进入了一人死循环。在这个循环里,任务1一方面以1s(秒)为周期改变并行I/O口PORTA第0个引脚的输出电压,另一方面每隔4s便向任务2发送1个信号。而任务2则始终等待任务1发来的信号,一旦收到信号,便改变并行I/O口PORTA第1个引脚的输出电压。具体的代码如下:

  /*****************************************

  * EXE2.C

  *******************************************/

  #include<hidef.h>

  #include "includes.h"

  Byte PORTA @0x0000; /*并口A地址$0000*/

  Byte DDRA @0x0004; /*并口A方向寄存器地址$0004*/

  Byte T1SC @0x0020; /*定时器控制寄存器地址$0020*/

  Byte T1MODH@0x0023; /*定时器模式寄存器地址$0023*/

  OS_EVENT *Semaphore;

  #define TASK_STK_SIZE 64 /*任务堆栈大小64字节*/

  INT8U Task1Stk[TASK_STK_SIZE]; /*定义任务1堆栈*/

  INT8U Task2Stk[TASK_STK_SIZE]; /*定义任务2堆栈*/

  Void Hardwareinit(void);

  Void Task1(void*pdata)

  {int count=0;

  /*int count=0;

  /*初始化定时器*/

  asm{

  LDA #0x50

  STA T1SC

  LDHX #0x0333 //设定定时器间隔100ms

  STHX T1MODH

上一页  [1] [2] [3]  下一页


本文关键字:暂无联系方式嵌入式系统-技术单片机-工控设备 - 嵌入式系统-技术