摘要
本文章主要从以下几点去解析ucosii系统,熟悉基本原理,不涉及实践。
1.所包含的相关文件,以及文件的大概作用
2.从运行状态的角度去理解此系统
一、寄存器说明
寄存器分为内核寄存器(CPU内部寄存器)和外设寄存器(IO、TIMER、DMA等)
1.1 M0、M3、M4内核寄存器
例如Cortex-M3处理器的寄存器有16个寄存器,其中13个为32Bit通用寄存器,3个特殊寄存器。
R13,栈指针(Stack Pointer)
- R13寄存器中存放的是栈顶指针,M3/M4 的栈是向下生长的,入栈的时候地址是往下减少的。
- 裸机程序不会用到PSP,只用到MSP,需要运行RTOS的时候才会用到PSP。
- 堆栈主要是通过POP,PUSH指令来进行操作。在执行 PUSH 和 POP 操作时, SP 的地址寄存器,会自动调整。
R14,链接寄存器(Link Register)
- LR 用于在调用子程序时存储返回地址。 例如,在使用 BL(分支并连接, Branch and Link)指令时,就自动填充 LR 的值(执行函数调用的下一指令),进而在函数退出时,正确返回并执行下一指令。 如果函数中又调用了其他函数,那么LR将会被覆盖,所以需要先将LR寄存器入栈。
- 保存子程序返回地址。使用BL或BLX时,跳转指令自动把返回地址放入r14中;子程序通过把r14复制到PC来实现返回
- 当异常发生时,异常模式的r14用来保存异常返回地址,将r14如栈可以处理嵌套中断
R15,程序计数器(Program Count)
- 在Cortex-M3中指令是3级流水线,出于对Thumb代码的兼容的考虑,读取pc时,会返回当前指令地址+4的值。
- 读 PC 时返回的值是当前指令的地址+4,关于M3、M4 和 A7的 PC值的问题需要单独来解释一下
xPSR,程序状态寄存器
二、软件架构说明
2.1 任务状态
2.2 结构体任务控制块
/*****************************************************************************************************
* TASK CONTROL BLOCK
******************************************************************************************************/
typedef struct os_tcb {
OS_STK *OSTCBStkPtr; /* Pointer to current top of stack */
#if OS_TASK_CREATE_EXT_EN > 0u
void *OSTCBExtPtr; /* Pointer to user definable data for TCB extension */
OS_STK *OSTCBStkBottom; /* Pointer to bottom of stack */
INT32U OSTCBStkSize; /* Size of task stack (in number of stack elements) */
INT16U OSTCBOpt; /* Task options as passed by OSTaskCreateExt() */
INT16U OSTCBId; /* Task ID (0..65535) */
#endif
struct os_tcb *OSTCBNext; /* Pointer to next TCB in the TCB list */
struct os_tcb *OSTCBPrev; /* Pointer to previous TCB in the TCB list */
#if (OS_EVENT_EN)
OS_EVENT *OSTCBEventPtr; /* Pointer to event control block */
#endif
#if (OS_EVENT_EN) && (OS_EVENT_MULTI_EN > 0u)
OS_EVENT **OSTCBEventMultiPtr; /* Pointer to multiple event control blocks */
#endif
#if ((OS_Q_EN > 0u) && (OS_MAX_QS > 0u)) || (OS_MBOX_EN > 0u)
void *OSTCBMsg; /* Message received from OSMboxPost() or OSQPost() */
#endif
#if (OS_FLAG_EN > 0u) && (OS_MAX_FLAGS > 0u)
#if OS_TASK_DEL_EN > 0u
OS_FLAG_NODE *OSTCBFlagNode; /* Pointer to event flag node */
#endif
OS_FLAGS OSTCBFlagsRdy; /* Event flags that made task ready to run */
#endif
INT32U OSTCBDly; /* Nbr ticks to delay task or, timeout waiting for event */
INT8U OSTCBStat; /* Task status */
INT8U OSTCBStatPend; /* Task PEND status */
INT8U OSTCBPrio; /* Task priority (0 == highest) */
INT8U OSTCBX; /* Bit position in group corresponding to task priority */
INT8U OSTCBY; /* Index into ready table corresponding to task priority */
OS_PRIO OSTCBBitX; /* Bit mask to access bit position in ready table */
OS_PRIO OSTCBBitY; /* Bit mask to access bit position in ready group */
#if OS_TASK_DEL_EN > 0u
INT8U OSTCBDelReq; /* Indicates whether a task needs to delete itself */
#endif
#if OS_TASK_PROFILE_EN > 0u
INT32U OSTCBCtxSwCtr; /* Number of time the task was switched in */
INT32U OSTCBCyclesTot; /* Total number of clock cycles the task has been running */
INT32U OSTCBCyclesStart; /* Snapshot of cycle counter at start of task resumption */
OS_STK *OSTCBStkBase; /* Pointer to the beginning of the task stack */
INT32U OSTCBStkUsed; /* Number of bytes used from the stack */
#endif
#if OS_TASK_NAME_EN > 0u
INT8U *OSTCBTaskName;
#endif
#if OS_TASK_REG_TBL_SIZE > 0u
INT32U OSTCBRegTbl[OS_TASK_REG_TBL_SIZE];
#endif
} OS_TCB;
- OSTCBStkPtr,指向当前任务堆栈的栈顶。UcosII允许用户自定义每个任务的堆栈大小,这样可以使用户根据每个任务实际的需要合理分配堆栈大小,便于节省RAM的空间(因为堆栈都是占用RAM空间的)。
- OSTCBExtPtr:指向用户定义的扩展内容的指针。
- OSTCBStkBottom:任务栈的栈底指针。
- OSTCBStkSize:可以容纳指针单位的数目,注意不是BYTE为单位。
- OSTCBOpt:主要在使用创建任务扩展功能中使用,将选项值传递给创建任务接口。
- OSTCBId:任务识别码,暂未使用
为TCB双向链表的前后向指针。该链表主要应用于系统时钟节拍函数
- OSTCBNext:TCB双向链表的后向指针
- OSTCBPrev:TCB双向链表的前向指针
用于存储任务信息
- OSTCBDly:任务对应的挂起等待时间单位长度。
- OSTCBStat:任务的状态存储变量,对应任务的5个装填。
- OSTCBPrio:任务的优先级。
- OSTCBX,OSTCBY,OSTCBBitX,OSTCBBitY:与任务的优先级存在对应关系,用于加速调度过程中优先级的比较。
2.3 任务调度
2.2.1 任务级别调度
OS_Sched();
2.2.2 中断级别调度
OSIntExit();
2.2.3 保证低优先级任务抢占CPU资源
void OSTimeDly (INT32U ticks)
2.4 实践指导
任务组成:
任务控制块(底层,不需要掌握)、任务优先级,任务栈,任务函数。
- 任务控制块:当创建一个任务的时候,ucos会分配一段内存空间给这个任务,这段内存空间就称为任务控制块。任务控制块记录了任务的相关信息:任务函数地址、任务的优先级、任务状态、任务栈地址。
- 任务优先级:每个任务都有一个唯一的优先级,优先级也只我们这个任务在ucos中的唯一标识,任务的优先级是ucos做任务调度的依据。
- 任务栈:当任务切换的时候保存该任务的状态(切换之前执行到哪里了,局部变量)。
2.4.1 创建任务
OSTaskCreate(Task_Led,(void *)0,&Task_4_stk[TASK_4_STK_SIZE-1],TASK_4_PRIO);
- Task_Led 具体任务函数
extern void Task_Led(void *p_arg);
void Task_Led(void *p_arg)
{
//uint8_t x;
IWDG_Init(4,625);
while(1)
{
IWDG_Feed();
OSTimeDlyHMSM(0,0,0,100);
}
}
2.4.2 中断
void SysTick_Handler(void)
{
/* 从运行状态进入中断状态必须要调用的函数,
该函数的功能是用来告诉操作系统当前程序进入中断 */
OSIntEnter();
/*心跳节拍函数*/
OSTimeTick();
/*从中断状态退出后进入运行状态之前必须调用函数
该函数的功能是用来告诉操作系统当前程序退出中断
*/
OSIntExit();
}