自己很早都开始学习ucosii这个嵌入式操作系统,这个是非常小型的操作系统,相比linux来说真是没有办法比较。
并且这个操作系统在Cortex-M3上跑起来真是不错,感觉就是为它设计的一样。对于LM3S811也是Cortex-M3的芯片
所以用起来很是方便。对于ucosii也在不断地成长,现在ucos-iii也出来了,我看了看里面给增加了=很多的东西,
比ucos-ii有强大了很多。
在本次收到21IC的LM3S811板子后,自己用它做了个四足的机器人,这个是自己很长时间的想法了。所以在本次设计的
四足机器人上将用这操作系统。我见论坛上也有坛友发有关ucosii的帖子,但是自己看了看,讲的都非常的简单,
就是粘贴一些源码,使用的价值很少并且对于ucosii只是一个浅浅的了解。所以趁着本次机器人的需要,我来说说ucosii
的学习,并且结合本次设计运用ucosii的需求,希望对刚接触这个操作系统的人有一点作用。增加咱21ic论坛的人气
和大家分享的精神。
对于ucosii我个人认为应该知道的是:时间管理,ucosii的初始化,任务控制块,时间控制块,任务调度方法,中断的控制
和嵌套,移植的汇编编写。
1、时间管理
在ucosii的时间管理上,都有一个定时器来给ucosii产生定时的中断,让它运行起来。这都需要硬件一个定时器来产生
系统时钟
static void tickInit (void)
{
SysTickPeriodSet((INT32U)(SysCtlClockGet() / OS_TICKS_PER_SEC) -1 );
SysTickEnable();
SysTickIntEnable();
}
中断服务程序
void tickISRHandler (void)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr;
#endif
OS_ENTER_CRITICAL();
OSIntNesting++;
OS_EXIT_CRITICAL();
OSTimeTick(); /* Call uC/OS-II's OSTimeTick()*/
OSIntExit();
}
里面的 OSTimeTick();来给ucosii产生系统时钟,这个大家需要看一下源码,太多了我就在说了
2、ucosii的初始化
在ucosii的初始化中有时间,就绪表,任务就绪表,事件等待表,事件组、内存、消息队列、定时器、
钩子函数的初始化等的初始化操作
void OSInit (void)
{
OSInitHookBegin(); /* Call port specific initialization code */
OS_InitMisc(); /* Initialize miscellaneous variables */
OS_InitRdyList(); /* Initialize the Ready List */
OS_InitTCBList(); /* Initialize the free list of OS_TCBs */
OS_InitEventList(); /* Initialize the free list of OS_EVENTs */
#if (OS_FLAG_EN > 0u) && (OS_MAX_FLAGS > 0u)
OS_FlagInit(); /* Initialize the event flag structures */
#endif
#if (OS_MEM_EN > 0u) && (OS_MAX_MEM_PART > 0u)
OS_MemInit(); /* Initialize the memory manager */
#endif
#if (OS_Q_EN > 0u) && (OS_MAX_QS > 0u)
OS_QInit(); /* Initialize the message queue structures */
#endif
OS_InitTaskIdle(); /* Create the Idle Task */
#if OS_TASK_STAT_EN > 0u
OS_InitTaskStat(); /* Create the Statistic Task */
#endif
#if OS_TMR_EN > 0u
OSTmr_Init(); /* Initialize the Timer Manager */
#endif
OSInitHookEnd(); /* Call port specific init. code */
#if OS_DEBUG_EN > 0u
OSDebugInit();
#endif
}
3、任务控制块
任务控制块是个链表结构,在任务申请的时候来创建。用它来管理每一个创建的任务,
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;
里面包括了任务的优先级,任务的状态,任务的堆摘的大小,其实位置和结束位置。
特别是任务切换的时候优先级的切换
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 */
这四个变量,要多关注一下。
4、事件控制块
是自己所申请的事件:信号量,队列,邮箱,事件组,互斥锁等所具有控制信息,任务等待的时间没有发生而在
时间控制块进行注册。
5、任务调度的方法
一个操作系统核心,任务的调度方法。很显然ucosii是一优先级进行调度的
INT8U const OSUnMapTbl[256] = {
0u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, /* 0x00 to 0x0F */
4u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, /* 0x10 to 0x1F */
5u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, /* 0x20 to 0x2F */
4u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, /* 0x30 to 0x3F */
6u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, /* 0x40 to 0x4F */
4u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, /* 0x50 to 0x5F */
5u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, /* 0x60 to 0x6F */
4u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, /* 0x70 to 0x7F */
7u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, /* 0x80 to 0x8F */
4u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, /* 0x90 to 0x9F */
5u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, /* 0xA0 to 0xAF */
4u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, /* 0xB0 to 0xBF */
6u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, /* 0xC0 to 0xCF */
4u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, /* 0xD0 to 0xDF */
5u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, /* 0xE0 to 0xEF */
4u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u /* 0xF0 to 0xFF */
};这个数组能看懂,基本上就懂了它的任务是如何切换的。并且在就需态下选择优先级最高的任务运行。
主要用到OSRdyGrp和OSRdyTbl两个数组来完成就绪态任务选取。
还有中断的控制和移植的汇编程序,以后在跟大家补充。
发个信号量用的例子
#include<include.h>
static OS_STK Task_StartStk[TASK_START_STK_SIZE]; /* The stack of start task */
/* 启动任务的堆栈 */
static OS_STK Task_AStk[TASK_A_STK_SIZE];
static OS_STK Task_BStk[TASK_B_STK_SIZE];
//static OS_STK Task_CStk[TASK_C_STK_SIZE];
//INT16U box[]="我是中国人,和必须额外问";
OS_EVENT *DispSem;
OS_EVENT *ReMbox;
/*********************************************************************************************************
FUNCTION PROTOTYPES 函数声明
*********************************************************************************************************/
static void taskStart (void *parg); /* The start task 启动任务 */
static void taskA (void *parg);
static void taskB (void *parg);
//static void taskc (void *parg);
static void taskCreate (void);
int main (void)
{
SysCtlLDOSet(SYS_LDO); /* 设置LDO的输出为2.50v */
intDisAll(); /* Disable all the interrupts */
/* 关闭所有中断 */
OSInit(); /* Initialize the kernel of uC */
/* OS-II 初始化uC/OS-II的内核 */
OSTaskCreate ( taskStart,
(void *)0,
&Task_StartStk[TASK_START_STK_SIZE - 1],
TASK_START_PRIO ); /* Initialize the start task */
/* 初始化启动任务 */
OSStart(); /* Start uC/OS-II 启动uC/OS-II */
return(0) ;
}
static void taskStart (void *parg)
{
(void)parg;
targetInit(); /* Initialize the target's MCU */
// SSIInit();
// usart_init();
#if OS_TASK_STAT_EN > 0
OSStatInit(); /* Enable statistics */
/* 使能统计功能 */
#endif
/*
* Create the other tasks here. 在这里创建其他任务
*/
taskCreate();
while (1) {
OSTaskSuspend(OS_PRIO_SELF); /* The start task can be pended*/
/* here. 启动任务可在这里挂起 */
}
}
static void taskCreate (void)
{
DispSem = OSSemCreate(1);
// ReMbox=OSMboxCreate(NULL);
OSTaskCreate (taskA, (void *)0,
&Task_AStk[TASK_A_STK_SIZE-1], TASK_A_PRIO);
OSTaskCreate (taskB, (void *)0,
&Task_BStk[TASK_B_STK_SIZE-1], TASK_B_PRIO);
// OSTaskCreate (taskc, (void *)0,
// &Task_CStk[TASK_C_STK_SIZE-1], TASK_C_PRIO);
}
static void taskA(void *parg)
{
INT8U err;
// INT8U box[100];
(void)parg;
while (1) {
OSSemPend(DispSem, 0, &err); /* 等待信号量 */
ledToggle(1);
OSTimeDly(20);
// box[]=OSMboxPend(ReMbox,0,&err);
// UARTSend(box[],sizeof(box[]));
}
}
static void taskB(void *parg)
{
INT8U uckey;
(void)parg;
while (1) {
uckey = keyRead( );
switch (uckey) {
case 0xFE: /* KEY1按下 */
while (keyRead( ) == 0xFE) { /* 等待按键释放,消除按键抖动 */
;
}
OSSemPost(DispSem); /* 发送信号量 */
break;
default:
break;
}
ledToggle(3);
OSTimeDly(2);
}
}
/*void taskc(void *parg)
{
INT8U err;
parg=parg;
// OSSemPend(DispSem,0,&err);
// UARTSend(box[],sizeof(box[]));
OSTimeDly(20);
}*/ |