最近开始了单片机之旅,使用的是STC公司最新推出的STC15系列的,型号为STC15F2K60S,在这里不再对这块单片机做具体介绍。由于移动机器人的需要,我想把UCOSII系统移植到51单片机上,之前在网上查资料,已经有人将UCOSII移植到51单片机,在此,本人也想尝试一下。
怀着好奇的心情在网上搜索关于UCOSII移植到51单片机的资料,步骤都是一样的,好多都是转载、转载,但是具体的内容并没有说清楚,好不容易搜到一个把移植过程说的很清楚的帖子,但是后面又说编译和运行过程中出现很多问题,我又绝望了。因为之前对51单片机只是简单的学了一下,对于移植UCOSII系统,还是得花点功夫的。由于我快毕业了,如果专研于UCOSII移植到51单片机,又得花上我一周的时间,想想那我的移动机器人得多久才能成功啊,于是,在CSDN上下载已经移植到51单片机上的源代码,起初我只是试着下来学习一下,学习怎样编写那些与cpu有关的函数的,我下载的那个源代码是将UCOSII移植到AT91系列上的,我果断编译了一下,成功编译,看一下输出的hex文件,才19kb。果然我又对源代码产生兴趣。我从始至终还是没有靠自己一步一步的将原版的UCOSII移植到51单片机上。我下面说说移植UCOSII需要做哪些工作吧,也是看书知道的。
一、准备工作
1. 开发环境: Keil C集成开发环境
2. 源代码:UCOSII的源代码,网上可以自己下载
3. 文件分析:
1)UCOSII文件中与处理器无关的文件:
OS_CORE.C
OS_FLAG.C
OS_MBOX.C
OS_MEM.C
OS_MUTEX.C
OS_Q.C
OS_SEM.C
OS_TASK.C
OS_TIME.C
UCOS_II.C
UCOS_II.H
以上这些文件在c51移植过程中只需给函数加上可重入性即可,即在每个函数后面添加关键字:reentrant
2)与应用相关的文件:
INCLUDES.H——其中包含51单片机头文件和相关应用头文件
OS_CFG.H——这个文件对于要应用系统中的相关工具,如邮箱,信号等,都要在这个头文件中把相关宏设置为1
3)与处理器相关的文件:
OS_CPU.H——相关的数据类型、关中断、任务堆栈方向、任务切换宏定义等
OS_CPU_A.ASM——一堆的汇编和伪指令,我表示没去深究,但是是整个移植的关键所在
OS_CPU_C.C——OSTaskStkInit()函数和系统中断定时器的编写。
还有一个重要的思想就是c51堆栈的设计,我对于这个有点头大,不清楚。
二、开始修改和编写代码移植。
我没有经历过移植的过程,所以我没有发言权,我只参考51单片机牛人的代码,学着应用就行
由于在CSDN上忘记移植者是谁了,我在这将重要文件中的代码贴出参考参考,只做交流使用。
includes.h
#ifndef __INCLUDES__
#define __INCLUDES__
#include "uCosii\os_cpu.h"
#include "uCosii\os_cfg.h"
#include "uCosii\ucos_ii.h"
#include "reg51.h"
#endif
OS_CFG.H
#ifndef __OS_CFG_H
#define __OS_CFG_H
#define MaxStkSize 64 /*根据修改,每个任务使用同样大小的堆栈,这就是每个堆栈的大小*/
#define OS_MAX_EVENTS 1 /* Max. number of event control blocks in your application ... */
/* ... MUST be > 0 */
#define OS_MAX_FLAGS 1 /* Max. number of Event Flag Groups in your application ... */
/* ... MUST be > 0 */
#define OS_MAX_MEM_PART 1 /* Max. number of memory partitions ... */
/* ... MUST be > 0 */
#define OS_MAX_QS 1 /* Max. number of queue control blocks in your application ... */
/* ... MUST be > 0 */
#define OS_MAX_TASKS 3 /* Max. number of tasks in your application ... */
/* ... MUST be >= 2 */
#define OS_LOWEST_PRIO 4 /* Defines the lowest priority that can be assigned ... */
/* ... MUST NEVER be higher than 63! */
#define OS_TASK_IDLE_STK_SIZE MaxStkSize /* Idle task stack size (# of OS_STK wide entries),使用相同的栈大小*/
#define OS_TASK_STAT_EN 0 /* Enable (1) or Disable(0) the statistics task */
#define OS_TASK_STAT_STK_SIZE MaxStkSize /* Statistics task stack size (# of OS_STK wide entries),使用相同的栈大小*/
#define OS_ARG_CHK_EN 0 /* Enable (1) or Disable (0) argument checking */
#define OS_CPU_HOOKS_EN 1 /* uC/OS-II hooks are found in the processor port files */
/* ----------------------- EVENT FLAGS ------------------------ */
#define OS_FLAG_EN 0 /* Enable (1) or Disable (0) code generation for EVENT FLAGS */
#define OS_FLAG_WAIT_CLR_EN 0 /* Include code for Wait on Clear EVENT FLAGS */
#define OS_FLAG_ACCEPT_EN 0 /* Include code for OSFlagAccept() */
#define OS_FLAG_DEL_EN 0 /* Include code for OSFlagDel() */
#define OS_FLAG_QUERY_EN 0 /* Include code for OSFlagQuery() */
/* -------------------- MESSAGE MAILBOXES --------------------- */
#define OS_MBOX_EN 1 /* Enable (1) or Disable (0) code generation for MAILBOXES */
#define OS_MBOX_ACCEPT_EN 0 /* Include code for OSMboxAccept() */
#define OS_MBOX_DEL_EN 0 /* Include code for OSMboxDel() */
#define OS_MBOX_POST_EN 1 /* Include code for OSMboxPost() */
#define OS_MBOX_POST_OPT_EN 0 /* Include code for OSMboxPostOpt() */
#define OS_MBOX_QUERY_EN 0 /* Include code for OSMboxQuery() */
/* --------------------- MEMORY MANAGEMENT -------------------- */
#define OS_MEM_EN 0 /* Enable (1) or Disable (0) code generation for MEMORY MANAGER */
#define OS_MEM_QUERY_EN 0 /* Include code for OSMemQuery() */
/* ---------------- MUTUAL EXCLUSION SEMAPHORES --------------- */
#define OS_MUTEX_EN 0 /* Enable (1) or Disable (0) code generation for MUTEX */
#define OS_MUTEX_ACCEPT_EN 0 /* Include code for OSMutexAccept() */
#define OS_MUTEX_DEL_EN 0 /* Include code for OSMutexDel() */
#define OS_MUTEX_QUERY_EN 0 /* Include code for OSMutexQuery() */
/* ---------------------- MESSAGE QUEUES ---------------------- */
#define OS_Q_EN 0 /* Enable (1) or Disable (0) code generation for QUEUES */
#define OS_Q_ACCEPT_EN 0 /* Include code for OSQAccept() */
#define OS_Q_DEL_EN 0 /* Include code for OSQDel() */
#define OS_Q_FLUSH_EN 0 /* Include code for OSQFlush() */
#define OS_Q_POST_EN 0 /* Include code for OSQPost() */
#define OS_Q_POST_FRONT_EN 0 /* Include code for OSQPostFront() */
#define OS_Q_POST_OPT_EN 0 /* Include code for OSQPostOpt() */
#define OS_Q_QUERY_EN 0 /* Include code for OSQQuery() */
/* ------------------------ SEMAPHORES ------------------------ */
#define OS_SEM_EN 0 /* Enable (1) or Disable (0) code generation for SEMAPHORES */
#define OS_SEM_ACCEPT_EN 0 /* Include code for OSSemAccept() */
#define OS_SEM_DEL_EN 0 /* Include code for OSSemDel() */
#define OS_SEM_QUERY_EN 0 /* Include code for OSSemQuery() */
/* --------------------- TASK MANAGEMENT ---------------------- */
#define OS_TASK_CHANGE_PRIO_EN 0 /* Include code for OSTaskChangePrio() */
#define OS_TASK_CREATE_EN 1 /* Include code for OSTaskCreate() */
#define OS_TASK_CREATE_EXT_EN 0 /* Include code for OSTaskCreateExt() */
#define OS_TASK_DEL_EN 0 /* Include code for OSTaskDel() */
#define OS_TASK_SUSPEND_EN 0 /* Include code for OSTaskSuspend() and OSTaskResume() */
#define OS_TASK_QUERY_EN 0 /* Include code for OSTaskQuery() */
/* --------------------- TIME MANAGEMENT ---------------------- */
#define OS_TIME_DLY_HMSM_EN 1 /* Include code for OSTimeDlyHMSM() */
#define OS_TIME_DLY_RESUME_EN 0 /* Include code for OSTimeDlyResume() */
#define OS_TIME_GET_SET_EN 0 /* Include code for OSTimeGet() and OSTimeSet() */
/* ---------------------- MISCELLANEOUS ----------------------- */
#define OS_VERSION_EN 0 /* Enable (1) or Disable (0) code generation for OSVersion() */
#define OS_SCHED_LOCK_EN 0 /* Include code for OSSchedLock() and OSSchedUnlock() */
#define OS_TICKS_PER_SEC 50 /* Set the number of ticks in one second */
typedef INT8U OS_FLAGS; /* Date type for event flag bits (8, 16 or 32 bits) */
#endif
OS_CPU.H
#ifndef __OS_CPU_H
#define __OS_CPU_H
#ifdef OS_CPU_GLOBALS
#define OS_CPU_EXT
#else
#define OS_CPU_EXT extern
#endif
/*
*********************************************************************************************************
* 数据类型
* (编译器相关)
*********************************************************************************************************
*/
//详见C51.PDF第176页
typedef unsigned char BOOLEAN; //注意:不要使用bit定义,因为在结构体里无法使用
typedef unsigned char INT8U; //无符号8位数
typedef signed char INT8S; //有符号8位数
typedef unsigned int INT16U; //无符号16位数
typedef signed int INT16S; //有符号16位数
typedef unsigned long INT32U; //无符号32位数
typedef signed long INT32S; //有符号32位数
typedef float FP32; //单精度浮点数
typedef double FP64; //双精度浮点数
typedef unsigned char OS_STK; //栈单元宽度为8比特
typedef unsigned char OS_CPU_SR; /* Define size of CPU status register (PSW = 8 bits) */
#define BYTE INT8S //兼容以前版本的数据类型
#define UBYTE INT8U //uC/OS-II可以不用这些数据类型
#define WORD INT16S
#define UWORD INT16U
#define LONG INT32S
#define ULONG INT32U
/*
*********************************************************************************************************
* 处理器相关代码 MCU-51 (大模式)
* 针对51单片机,只使用方法1(直接开关中断)
*********************************************************************************************************
*/
#define OS_CRITICAL_METHOD 1
#if OS_CRITICAL_METHOD == 1
#define OS_ENTER_CRITICAL() EA=0 //关中断
#define OS_EXIT_CRITICAL() EA=1 //开中断
#endif
#if OS_CRITICAL_METHOD == 2
/* As an undocumented keyword of keil c. __asm is supported in Keil C v6.20.
. No other means to define assemble language code in a macro, I have to use it here. If your compiler does not support __asm, use method 1 or 3 then. */
/* A2 AF MOV C, EA*/
/* C2 AF CLR EA */
/* C0 D0 PUSH PSW */
#define OS_ENTER_CRITICAL() __asm DB 0A2H, 0AFH, 0C2H, 0AFH, 0C0H, 0D0H
/* D0 D0 POP PSW */
/* 92 AF MOV EA, C */
#define OS_EXIT_CRITICAL() __asm DB 0D0H, 0D0H, 092H, 0AFH
#endif
#if OS_CRITICAL_METHOD == 3
#define OS_ENTER_CRITICAL() (cpu_sr = EA, EA=0) /* Disable interrupts */
#define OS_EXIT_CRITICAL() (EA=cpu_sr) /* Enable interrupts */
#endif
#define OS_STK_GROWTH 0 //MCU-51堆栈从下往上增长 1=向下,0=向上
#define OS_TASK_SW() OSCtxSw() //因为MCU-51没有软中断指令,所以用程序调用代替。两者的堆栈格式相同,
//RETI指令复位中断系统,RET则没有。实践表明,对于MCU-51,用子程序调
//用入栈,用中断返回指令RETI出栈是没有问题的,反之中断入栈RET出栈则
//不行。总之,对于入栈,子程序调用与中断调用效果是一样的,可以混用。
//在没有中断发生的情况下复位中断系统也不会影响系统正常运行。
//详见《uC/OS-II》第八章193页第12行
#define OS_ISR_PROTO_EXT 1
void OSCtxSw(void);
void InitHardware(void) reentrant; //初始化硬件时钟中断等,系统初始化工作
#endif //_OS_CPU_H
OS_CPU_A.ASM
;伪指令详细用法请查A51.PDF文件
;程序结构详见《uC/OS-II》193-198页
;不用此语句!!! $CASE ;标号和变量名区分大小写
$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 DATA (?C_XBP) ;仿真堆栈指针用于重入局部变量保存,为V2.51能被C使用定义在本模块中
EXTRN IDATA (OSTCBCur)
EXTRN IDATA (OSTCBHighRdy)
EXTRN IDATA (OSRunning)
EXTRN IDATA (OSPrioCur)
EXTRN IDATA (OSPrioHighRdy)
EXTRN CODE (_?OSTaskSwHook)
EXTRN CODE (_?OSIntEnter)
EXTRN CODE (_?OSIntExit)
EXTRN CODE (_?OSTimeTick)
; EXTRN CODE (_?serial)
;对外声明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 ACC
PUSH B
PUSH DPH
PUSH DPL
PUSH PSW
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 PSW
POP DPL
POP DPH
POP B
POP ACC
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
;恢复仿真堆栈指针?C_XBP
INC DPTR
MOVX A,@DPTR
MOV ?C_XBP,A ;?C_XBP 仿真堆栈指针高8位
INC DPTR
MOVX A,@DPTR
MOV ?C_XBP+1,A ;?C_XBP 仿真堆栈指针低8位
;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
;保存仿真堆栈指针?C_XBP
INC DPTR
MOV A,?C_XBP ;?C_XBP 仿真堆栈指针高8位
MOVX @DPTR,A
INC DPTR
MOV A,?C_XBP+1 ;?C_XBP 仿真堆栈指针低8位
MOVX @DPTR,A
;调用用户程序
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
END
OS_CPU_C.C
#define OS_CPU_GLOBALS
#include "source\includes.h"
/*
*********************************************************************************************************
* 初始化任务堆栈
*
* 描述 : 这个函数被OSTaskCreate()或OSTaskCreateExt()调用,以便初始化新创建任务的堆栈结构。本函数
* 与处理器高度相关。
*
* 参数 : task 指向任务代码的指针
*
* pdata 当任务第一次执行时将要传入任务的用户数据结构指针
*
* ptos 栈顶指针。ptos指针被默认为用户堆栈入口指针。如果OS_STK_GROWTH被置1,那么,
* ptos指向用户堆栈的最高有效地址。同样地,如果OS_STK_GROWTH清0,ptos将指向
* 用户堆栈的最低有效地址。
*
* opt 指定可以改变OSTaskStkInit()行为的选项。(见uCOS_II.H for OS_TASK_OPT_???)。
*
* 返回值 : 我修改了原来的程序,使函数总是返回用户堆栈空间的最低有效地址。这样修改提高了TCB换入换出
* 的效率。
*
* 注意 : 任务堆栈结构:
*
* ---------- -
* 用户栈最高地址---->| | |
* ---------- |
* | ... | 仿真堆栈空间
*---------- ---------- | 每任务一个
*|OSTCBCur| ?C_XBP---->| | | KEIL自动处理
*---------- ---------- -
* | |空闲间隔|
* | ----------------------- ---------- ----------
* \---->|OSTCBCur->OSTCBStkPtr| |?C_XBP低| SP---->| |
* ----------------------- ---------- ----------
* | |?C_XBP高| | |
* | ---------- - ----------
* | | | | | . |
* | ---------- | | . |
* | | | | | . |
* | ---------- | ----------
* | | . |长度 | | +1
* | | . | | ----------
* | | . | | OSStack---->| | 0
* | ---------- | ----------
* | | | | OSStkStart---->| 不关心 | -1 低地址
* | ---------- - ----------
* \------------->| 长度 | 低地址 系统硬件堆栈
* ----------
* 用户堆栈 长度=SP-OSStkStart
*********************************************************************************************************
*/
OS_STK *OSTaskStkInit (void (*task)(void *pd) reentrant, void *ppdata, OS_STK *ptos, INT16U opt) reentrant
{
OS_STK *stk;
ppdata = ppdata;
opt = opt; //opt没被用到,保留此语句防止告警产生
stk = ptos; //用户堆栈最低有效地址
*stk++ = 15; //用户堆栈长度
*stk++ = (INT16U)task & 0xFF; //任务地址低8位
*stk++ = (INT16U)task >> 8; //任务地址高8位
*stk++ = 0x0A; //ACC
*stk++ = 0x0B; //B
*stk++ = 0x00; //DPH
*stk++ = 0x00; //DPL
*stk++ = 0x00; //PSW
*stk++ = 0x00; //R0
//R3、R2、R1用于传递任务参数ppdata,其中R3代表存储器类型,R2为高字节偏移,R1为低字节位移。
//通过分析KEIL汇编,了解到任务的void *ppdata参数恰好是用R3、R2、R1传递,不是通过虚拟堆栈。
*stk++ = (INT16U)ppdata & 0xFF; //R1
*stk++ = (INT16U)ppdata >> 8; //R2
*stk++ = 0x01; //R3 因为我用的全是XDATA,所以存储器类型固定为1,见C51.PDF第178页说明。
*stk++ = 0x04; //R4
*stk++ = 0x05; //R5
*stk++ = 0x06; //R6
*stk++ = 0x07; //R7
//不用保存SP,任务切换时根据用户堆栈长度计算得出。
*stk++ = (INT16U) (ptos+MaxStkSize) >> 8; //?C_XBP 仿真堆栈指针高8位
*stk++ = (INT16U) (ptos+MaxStkSize) & 0xFF; //?C_XBP 仿真堆栈指针低8位
return ((void *)ptos);
}
#if OS_CPU_HOOKS_EN
/*
*********************************************************************************************************
* OS INITIALIZATION HOOK
* (BEGINNING)
*
* Description: This function is called by OSInit() at the beginning of OSInit().
*
* Arguments : none
*
* Note(s) : 1) Interrupts should be disabled during this call.
*********************************************************************************************************
*/
#if OS_VERSION > 203
void OSInitHookBegin (void) reentrant
{
}
#endif
/*
*********************************************************************************************************
* OS INITIALIZATION HOOK
* (END)
*
* Description: This function is called by OSInit() at the end of OSInit().
*
* Arguments : none
*
* Note(s) : 1) Interrupts should be disabled during this call.
*********************************************************************************************************
*/
#if OS_VERSION > 203
void OSInitHookEnd (void) reentrant
{
}
#endif
/*
*********************************************************************************************************
* 任务创建钩挂函数
*
* 描述 : 任务创建时调用
*
* 参数 : ptcb是指向将被创建任务的任务控制块的指针。
*
* 注意 : 1) 调用期间中断被禁止
*********************************************************************************************************
*/
void OSTaskCreateHook (OS_TCB *ptcb) reentrant
{
ptcb = ptcb; /* Prevent compiler warning */
}
/*
*********************************************************************************************************
* 任务删除钩挂函数
*
* 描述 : 任务删除时调用
*
* 参数 : ptcb是指向将被删除任务的任务控制块的指针。
*
* 注意 : 1) 调用期间中断被禁止
*********************************************************************************************************
*/
#if OS_TASK_DEL_EN > 0
void OSTaskDelHook (OS_TCB *ptcb) reentrant
{
ptcb = ptcb; /* Prevent compiler warning */
}
#endif
/*
*********************************************************************************************************
* 任务切换钩挂函数
*
* 描述 : 执行任务切换时调用。这允许你在上下文切换期间执行其它操作。
*
* 参数 : 无
*
* 注意 : 1) 调用期间中断被禁止
* 2) 假定全局指针'OSTCBHighRdy'已经指向了将要被换入的任务控制块(即:最高优先级任务),并且
* 'OSTCBCur'指向了将被换出的任务(即:当前任务)。
*********************************************************************************************************
*/
void OSTaskSwHook (void) reentrant
{
}
/*
*********************************************************************************************************
* 统计任务钩挂函数
*
* 描述 : 这个函数每秒钟被uC/OS-II统计任务调用。这么做使你的应用程序可以增加统计任务的功能。
*
* 注意 : 无
*********************************************************************************************************
*/
#if OS_TASK_STAT_EN > 0
void OSTaskStatHook (void) reentrant
{
}
#endif
/*
*********************************************************************************************************
* OSTCBInit() HOOK
*
* Description: This function is called by OSTCBInit() after setting up most of the TCB.
*
* Arguments : ptcb is a pointer to the TCB of the task being created.
*
* Note(s) : 1) Interrupts may or may not be ENABLED during this call.
*********************************************************************************************************
*/
#if OS_VERSION > 203
void OSTCBInitHook (OS_TCB *ptcb) reentrant
{
ptcb = ptcb; /* Prevent Compiler warning */
}
#endif
/*
*********************************************************************************************************
* 定时钩挂函数
*
* 描述 : 本函数每一滴答被调用一次。
*
* 参数 : 无
*
* 注意 : 1) 在本调用期间中断可以或不可以使能。
*********************************************************************************************************
*/
void OSTimeTickHook (void) reentrant
{
}
/*
*********************************************************************************************************
* IDLE TASK HOOK
*
* Description: This function is called by the idle task. This hook has been added to allow you to do
* such things as STOP the CPU to conserve power.
*
* Arguments : none
*
* Note(s) : 1) Interrupts are enabled during this call.
*********************************************************************************************************
*/
#if OS_VERSION >= 251
void OSTaskIdleHook (void) reentrant
{
}
#endif
#endif
/*
使用C语言的中断处理函数有助与提高程序的移植性。建议中断程序不要太长,如果长则使用信号量来与任务同步,
在外部任务中实现大量的处理。
中断处理例程都放在下面。
*/
void UserTickTimer(void)
{
TH0=0xB8; //普通51定时器方式1,必须在发生中断时,重新赋值并再次启动计时
TL0=0; //Tick=50次/秒(即0.02秒/次),晶振11.0592M 1ms
TR0=1;
}
/*
uCOS-II系统时钟中断处理程序
*/
void OSTickISR(void) interrupt 1
{
OSIntEnter(); // Must be called first at every hardware interrupt entry point
UserTickTimer(); // User functions can be called here.
OSTimeTick(); // Must be called during tick isr
OSIntExit(); // Must be called finally at every hardware interupt exit point
}
/*
设置硬件寄存器的初始值。
初始化定时器0,作为ucOS-II的系统时钟。
还有其他的与硬件相关的初始化也可以放在这里。
*/
void InitHardware(void) reentrant
{
TMOD &= 0xF0;
TMOD = 0X00; /* 初始化定时器0、1为模式0(16位自动重载) */
TH0 = 0xB8; //定义Tick=50次/秒(即0.02秒/次),TH,TL值与CPU的频率有关
TL0 = 0x00; //OS_CPU_C.C中定时器中断响应也要设置,OS_CFG.H中OS_TICKS_PER_SEC也有关系
ET0 = 1; //允许T0中断(在第一个任务开始执行时才开时钟中断,否则万一中断系统进入不可知状态)
TR0 = 1;
}
以上就是移植过程中的重要代码了,只作为讨论使用。
对于使用我想说两点:
1. 我之前还以为UCOSII默认支持邮箱、信号量、队列等的功能,但是当我使用邮箱时,编译出错,提示没有邮箱创建函数,花了一个晚上的时间终于解决,原来是OS_CFG.H中相关的宏开关没有打开,为了节约资源,用到什么功能就把其打开即可。
2. 对于OS_CPU_C.C中,有几个函数很重要,一个是系统定时器中断函数,这个函数对后面我们写中断函数有帮助(其实就是进中断和出中断加两个函数),之前我一直不晓得怎样在UCOSII中写自定义中断函数,这下学习了,如下所示:
//=============================================================================
//函数:INT0_SVC()
//描述:外部中断0服务程序
//参数:无
//返回:无
//日期:2013/5/4 1:00
//=============================================================================
void INT0_SVC() interrupt 0
{
OSIntEnter();
EX0 = 0; /* 屏蔽外部中断 */
GREEN = ~GREEN;
OSIntExit();
}二是
void UserTickTimer(void)
{
TH0=0xB8; //普通51定时器方式1,必须在发生中断时,重新赋值并再次启动计时
TL0=0; //Tick=50次/秒(即0.02秒/次),晶振11.0592M 1ms
TR0=1;
} /*
设置硬件寄存器的初始值。
初始化定时器0,作为ucOS-II的系统时钟。
还有其他的与硬件相关的初始化也可以放在这里。
*/
void InitHardware(void) reentrant
{
TMOD &= 0xF0;
TMOD = 0X00; /* 初始化定时器0、1为模式0(16位自动重载) */
TH0 = 0xB8; //定义Tick=50次/秒(即0.02秒/次),TH,TL值与CPU的频率有关
TL0 = 0x00; //OS_CPU_C.C中定时器中断响应也要设置,OS_CFG.H中OS_TICKS_PER_SEC也有关系
ET0 = 1; //允许T0中断(在第一个任务开始执行时才开时钟中断,否则万一中断系统进入不可知状态)
TR0 = 1;
}
需要根据相应的单片机设定。
对于我的STC15系列单片机我是这样设置的:
void UserTickTimer(void)
{
TH0=0xA2; //15系列单片机定时器0方式0,必须在发生中断时,重新赋值并再次启动计时
TL0=0x40; //Tick=50次/秒(即0.02秒/次),晶振12M 2m
/* 定时器定时时间计算公式:t = (1或12分频) * (定时器溢出最大值-定时器初值)/晶振频率 */
TR0=1;
}
void InitHardware(void) reentrant
{
TMOD &= 0xF0;
TMOD = 0X00; /* 初始化定时器0、1为模式0(16位自动重载) */
TH0 = 0xA2; /* 定义Tick=50次/秒(即0.02秒/次),TH,TL值与CPU的频率有关 */
TL0 = 0x40; /* OS_CPU_C.C中定时器中断响应也要设置,OS_CFG.H中OS_TICKS_PER_SEC也有关系 */
ET0 = 1; /* 允许T0中断(在第一个任务开始执行时才开时钟中断,否则万一中断系统进入不可知状态) */
TR0 = 1;
AUXR = 0x80; /* 定时器0为1T模式 */
}
到此为止,是我这周所做的工作,但是又遇到很纠结的问题,STC15系列的单片机在下载程序时并不是每次都成功,下一个程序有时需要好几次才能成功下载,因此,拖慢了我的开发进度,我在尝试解决此问题,不过很庆幸的是,我的机器人可以在UCOSII下正常工作了。下一步便是分任务的对传感器控制,并与ARM11上的Linux进行串口通信!