搜索
您的当前位置:首页在51系列单片机上移植uCOS-II(二)

在51系列单片机上移植uCOS-II(二)

来源:乌哈旅游
在51系列单片机上移植uCOS-II(二)

(6)编写测试程序Demo(YY.C)

Demo程序创建了3个任务A,B,C优先级分别为2,3,4,A每秒显示一次,B每3秒显示一次,C每6秒显示一次.从显示结果看,显示3个A后显示1个B,显 示6个A和2个B后显示1个C,结果显然正确. 显示结果如下:

AAAAAA111111 is active AAAAAA111111 is active AAAAAA111111 is active BBBBBB333333 is active AAAAAA111111 is active AAAAAA111111 is active AAAAAA111111 is active BBBBBB333333 is active CCCCCC666666 is active AAAAAA111111 is active AAAAAA111111 is active AAAAAA111111 is active BBBBBB333333 is active AAAAAA111111 is active AAAAAA111111 is active AAAAAA111111 is active BBBBBB333333 is active CCCCCC666666 is active

Demo程序经Keil701编译后,代码量为7-8K,可直接在KeilC51上仿真运行. 编译时要将OS_CPU_C.C,UCOS_II.C,OS_CPU_A.ASM,YY.C加入项目 文件名 : OS_CPU_A.ASM $NOMOD51

EA BIT 0A8H.7 SP DATA 081H B DATA 0F0H ACC DATA 0E0H DPH DATA 083H DPL DATA 082H PSW DATA 0D0H TR0 BIT 088H.4 TH0 DATA 08CH TL0 DATA 08AH

NAME OS_CPU_A ;模块名 ;定义重定位段

PR OSStartHighRdy OS_CPU_A SEGMENT CODE PR OSCtxSw OS_CPU_A SEGMENT CODE PR OSIntCtxSw OS_CPU_A SEGMENT CODE

PR OSTickISR OS_CPU_A SEGMENT CODE PR _ serial OS_CPU_A SEGMENT CODE ;声明引用全局变量和外部子程序 EXTRN IDATA (OSTCBCur) EXTRN IDATA (OSTCBHighRdy) EXTRN IDATA (OSRunning) EXTRN IDATA (OSPrioCur) EXTRN IDATA (OSPrioHighRdy) EXTRN CODE (_ OSTaskSwHook) EXTRN CODE (_ serial) EXTRN CODE (_ OSIntEnter) EXTRN CODE (_ OSIntExit) EXTRN CODE (_ OSTimeTick) ;对外声明4个不可重入函数 PUBLIC OSStartHighRdy PUBLIC OSCtxSw PUBLIC OSIntCtxSw PUBLIC OSTickISR ;PUBLIC SerialISR

;分配堆栈空间.只关心大小,堆栈起点由keil决定,通过标号可以获得keil分配的SP起点.

STACK SEGMENT IDATA RSEG STACK OSStack: DS 40H

OSStkStart IDATA OSStack-1 ;定义压栈出栈宏 PUSHALL MACRO PUSH PSW PUSH ACC PUSH B PUSH DPL PUSH DPH

MOV A,R0 ;R0-R7入栈 PUSH ACC MOV A,R1 PUSH ACC MOV A,R2 PUSH ACC MOV A,R3 PUSH ACC MOV A,R4 PUSH ACC MOV A,R5

PUSH ACC MOV A,R6 PUSH ACC MOV A,R7 PUSH ACC

;PUSH SP ;不必保存SP,任务切换时由相应程序调整 ENDM

POPALL MACRO

;POP ACC ;不必保存SP,任务切换时由相应程序调整 POP ACC ;R0-R7出栈 MOV R7,A POP ACC MOV R6,A POP ACC MOV R5,A POP ACC MOV R4,A POP ACC MOV R3,A POP ACC MOV R2,A POP ACC MOV R1,A POP ACC MOV R0,A POP DPH POP DPL POP B POP ACC POP PSW ENDM ;子程序

;-------------------------------------------------------------------------

RSEG PR OSStartHighRdy OS_CPU_A OSStartHighRdy:

USING 0 ;上电后51自动关中断,此处不必用CLR EA指令,因为到此处还未开中断,本程序退出后,开中断. LCALL _ OSTaskSwHook OSCtxSw_in:

;OSTCBCur ===> DPTR 获得当前TCB指针,详见C51.PDF第178页

MOV R0,#LOW (OSTCBCur) ;获得OSTCBCur指针低地址,指针占3字节.+0类型+1高8位数据+2低8位数据 INC R0

MOV DPH,@R0 ;全局变量OSTCBCur在IDATA中 INC R0

MOV DPL,@R0

;OSTCBCur->OSTCBStkPtr ===> DPTR 获得用户堆栈指针

INC DPTR ;指针占3字节.+0类型+1高8位数据+2低8位数据 MOVX A,@DPTR ;.OSTCBStkPtr是void指针 MOV R0,A INC DPTR

MOVX A,@DPTR MOV R1,A MOV DPH,R0 MOV DPL,R1 ;*UserStkPtr ===> R5 用户堆栈起始地址内容(即用户堆栈长度放在此处) 详见文档说明指针用法详见C51.PDF第178页

MOVX A,@DPTR ;用户堆栈中是unsigned char类型数据 MOV R5,A ;R5=用户堆栈长度 ;恢复现场堆栈内容 MOV R0,#OSStkStart restore_stack: INC DPTR INC R0

MOVX A,@DPTR MOV @R0,A

DJNZ R5,restore_stack ;恢复堆栈指针SP MOV SP,R0

;OSRunning=TRUE

MOV R0,#LOW (OSRunning) MOV @R0,#01 POPALL

SETB EA ;开中断 RETI

;-------------------------------------------------------------------------

RSEG PR OSCtxSw OS_CPU_A OSCtxSw: PUSHALL

OSIntCtxSw_in:

;获得堆栈长度和起址 MOV A,SP CLR C

SUBB A,#OSStkStart MOV R5,A ;获得堆栈长度

;OSTCBCur ===> DPTR 获得当前TCB指针,详见C51.PDF第178页

MOV R0,#LOW (OSTCBCur) ;获得OSTCBCur指针低地址,指针占3字节.+0类型+1高8位数据+2低8位数据 INC R0

MOV DPH,@R0 ;全局变量OSTCBCur在IDATA中 INC R0

MOV DPL,@R0

;OSTCBCur->OSTCBStkPtr ===> DPTR 获得用户堆栈指针

INC DPTR ;指针占3字节.+0类型+1高8位数据+2低8位数据 MOVX A,@DPTR ;.OSTCBStkPtr是void指针 MOV R0,A INC DPTR

MOVX A,@DPTR MOV R1,A MOV DPH,R0 MOV DPL,R1 ;保存堆栈长度 MOV A,R5

MOVX @DPTR,A

MOV R0,#OSStkStart ;获得堆栈起址 save_stack: INC DPTR INC R0 MOV A,@R0 MOVX @DPTR,A

DJNZ R5,save_stack ;调用用户程序

LCALL _ OSTaskSwHook ;OSTCBCur = OSTCBHighRdy MOV R0,#OSTCBCur MOV R1,#OSTCBHighRdy MOV A,@R1 MOV @R0,A INC R0 INC R1 MOV A,@R1 MOV @R0,A INC R0 INC R1 MOV A,@R1 MOV @R0,A

;OSPrioCur = OSPrioHighRdy 使用这两个变量主要目的是为了使指针比较变为字节比较,以便节省时间. MOV R0,#OSPrioCur MOV R1,#OSPrioHighRdy

MOV A,@R1 MOV @R0,A

LJMP OSCtxSw_in

;-------------------------------------------------------------------------

RSEG PR OSIntCtxSw OS_CPU_A OSIntCtxSw:

;调整SP指针去掉在调用OSIntExit(),OSIntCtxSw()过程中压入堆栈的多余内容

;SP=SP-4 MOV A,SP CLR C

SUBB A,#4 MOV SP,A

LJMP OSIntCtxSw_in

;-------------------------------------------------------------------------

CSEG AT 000BH ;OSTickISR LJMP OSTickISR ;使用定时器0 RSEG PR OSTickISR OS_CPU_A OSTickISR: USING 0 PUSHALL CLR TR0

MOV TH0,#70H ;定义Tick=50次/秒(即0.02秒/次) MOV TL0,#00H ;OS_CPU_C.C 和 OS_TICKS_PER_SEC SETB TR0

LCALL _ OSIntEnter LCALL _ OSTimeTick LCALL _ OSIntExit POPALL RETI

;-------------------------------------------------------------------------

CSEG AT 0023H ;串口中断

LJMP SerialISR ;工作于系统态,无任务切换. RSEG PR _ serial OS_CPU_A SerialISR: USING 0 PUSHALL CLR EA

LCALL _ serial SETB EA POPALL

RETI

;------------------------------------------------------------------------- END

;-------------------------------------------------------------------------

文件名 : OS_CPU_C.C

void *OSTaskStkInit (void (*task)(void *pd), void *ppdata, void *ptos, INT16U opt) reentrant {

OS_STK *stk;

ppdata = ppdata;

opt = opt; //opt没被用到,保留此语句防止告警产生 stk = (OS_STK *)ptos; //用户堆栈最低有效地址 *stk++ = 15; //用户堆栈长度

*stk++ = (INT16U)task & 0xFF; //任务地址低8位 *stk++ = (INT16U)task >> 8; //任务地址高8位 *stk++ = 0x00; //PSW *stk++ = 0x0A; //ACC *stk++ = 0x0B; //B *stk++ = 0x00; //DPL *stk++ = 0x00; //DPH *stk++ = 0x00; //R0 *stk++ = 0x01; //R1 *stk++ = 0x02; //R2 *stk++ = 0x03; //R3 *stk++ = 0x04; //R4 *stk++ = 0x05; //R5 *stk++ = 0x06; //R6 *stk++ = 0x07; //R7

//不用保存SP,任务切换时根据用户堆栈长度计算得出. return ((void *)ptos); }

#if OS_CPU_HOOKS_EN

void OSTaskCreateHook (OS_TCB *ptcb) reentrant {

ptcb = ptcb; }

void OSTaskDelHook (OS_TCB *ptcb) reentrant {

ptcb = ptcb; }

void OSTimeTickHook (void) reentrant {}

#endif

//初始化定时器0

void InitTimer0(void) reentrant {

TMOD=TMOD&0xF0;

TMOD=TMOD|0x01; //模式1(16位定时器),仅受TR0控制 TH0=0x70; //定义Tick=50次/秒(即0.02秒/次) TL0=0x00; //OS_CPU_A.ASM 和 OS_TICKS_PER_SEC ET0=1; //允许T0中断 TR0=1; }

文件名 : YY.C #include

#define MAX_STK_SIZE 64

void TaskStartyya(void *yydata) reentrant; void TaskStartyyb(void *yydata) reentrant; void TaskStartyyc(void *yydata) reentrant; OS_STK TaskStartStkyya[MAX_STK_SIZE+1];//注意:我在ASM文件中设置 STACK空间为40H即64,不要超出范围.

OS_STK TaskStartStkyyb[MAX_STK_SIZE+1];//用户栈多一个字节存长度 OS_STK TaskStartStkyyc[MAX_STK_SIZE+1]; void main(void) {

OSInit();

InitTimer0(); InitSerial();

InitSerialBuffer();

OSTaskCreate(TaskStartyya, (void *)0, &TaskStartStkyya[0],2); OSTaskCreate(TaskStartyyb, (void *)0, &TaskStartStkyyb[0],3); OSTaskCreate(TaskStartyyc, (void *)0, &TaskStartStkyyc[0],4); OSStart(); }

void TaskStartyya(void *yydata) reentrant {

yydata=yydata; clrscr();

PrintStr(\"\\n\\*******************************\\n\"); PrintStr(\"\\* Hello! The world. *\\n\");

PrintStr(\"\\*******************************\\n\\n\\n\"); for(;;){

PrintStr(\"\AAAAAA111111 is active.\\n\"); OSTimeDly(OS_TICKS_PER_SEC); } }

void TaskStartyyb(void *yydata) reentrant

{

yydata=yydata; for(;;){

PrintStr(\"\BBBBBB333333 is active.\\n\"); OSTimeDly(3*OS_TICKS_PER_SEC); } }

void TaskStartyyc(void *yydata) reentrant {

yydata=yydata; for(;;){

PrintStr(\"\CCCCCC666666 is active.\\n\"); OSTimeDly(6*OS_TICKS_PER_SEC); } }

因篇幅问题不能全部显示,请点此查看更多更全内容

Top