uC/OS-II(miu 扣丝兔)
MicroC/OS-II The-Time Kernel
微控制器操作系统版本 2
是一个多任务的实时内核,允许建立多达 63 个用户任务。
uC/OS-II
终于在 STM32 上跑起
一切函数都要从 main()说起
一进来,挡在前面的是函数 OSIinit():
其实吧,拉伯罗斯先生给函数起名字都是很讲究的,让我们理解下这个函数函数名字,OS
=操作系统,Iinit=初始化,意思就是进行操作系统初始化。到底初始化了什么东东呢?
正如你要盖一座大厦之前,你要设置好一砖一瓦,一水泥一钢筋。所以在使用 ucosII 提供的
任何功能之前,必须调用 OSIinit 函数。
它调用了各种初始化,各种清空,各种裸~~
它最重要的是它建立了两个任务:
空闲任务――没有任务时候运行的空任务。
统计任务――计算 CPU 的利用率,呵呵,想起了 XP 的任务管理器
(*task)(void *p_arg),
下面这个函数可以吓得人蛋都碎掉 OSTaskCreateExt(……………….):
你翻遍谭浩强大哥的那本 C 程序设计,也找不出这么变态的函数,里面参数都写了快三行
了,所以我只能无耻且无奈的以点点点代替之。
函数原型奉上~~
INT8U OSTaskCreateExt (void
void
*p_arg,
OS_STK *ptos,
prio,
INT8U
INT16U
id,
OS_STK *pbos,
INT32U
void
INT16U
stk_size,
*pext,
opt)
{
}
函数的功能是创建一个任务,
可以看到这里有 9 个参数,让我们一个个分析
task 是指向该任务运行的函数代码的指针(任务的代码函数)
p_arg 是指向任务初始化数据的指针(任务传递的参数)
ptos 是任务的堆栈栈顶 TOS,因为每个任务都有各自的堆栈空间,每个每个堆栈容量可以
单独指定(任务的堆栈)
prio 是指定建立任务的优先级,值越小,优先级越高,说过 ucos2 可以建立多达 63 个用户
任务。必须给这些任务分配一个独一无二的(0~62)的优先级(任务的优先级别)
id 是这个任务的 ID 即它的身份证号码(ID 号)
pbos 是任务的栈底指针(堆栈的底部)
stk_size 堆栈的容量(堆栈的容量)
pext 需要一个指向用户定义的 TCB 扩展数据结构的指针。如 cpu 是浮点计数器的时候
opt 其他选项有(选其他项)
OS_TASK_OPT_STK_CHK 允许堆栈检查
OS_TASK_OPT_STK_CLR 清空任务创建时的栈
OS_TASK_OPT_SAVE_FP 如果 cpu 是浮点计数器的时候,上下文切换的时候保存
返回情况
OS_ERR_NONE 成功
OS_PRIO_EXIT 优先级存在了
OS_ERR_PRIO_INVALID 优先级超过设定的最大值
OS_ERR_TASK_CREATE_ISR 从中断中创建任务了
呼呼,终于把这该死的程序分析完了,正所谓万事俱备,只欠东风
接下来,开始任务调度了 OSStart()
这个函数将判断所有建立的任务中哪个任务是最重要的(优先级最高),并开始运行这个任
务;
实际应用:
OSTaskCreateExt(
App_TaskStart, (void *) 0,
(OS_STK
APP_TASK_START_PRIO,
*)
&App_TaskStartStk[APP_TASK_START_STK_SIZE
-
1],
APP_TASK_START_PRIO,
(OS_STK *) &App_TaskStartStk[0],
APP_TASK_START_STK_SIZE ,
(void *) 0,
OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR
);
我们创建了一个叫 App_TaskStart,系统的第一个任务,负责开 OS 时钟,建立其他任务。没
有 初始 化数 据 ,分 配 堆栈 ,指 定 栈顶 , 任务 优先 级 ,ID 和 任务 优先 级 别是 相 同的 值
(APP_TASK_FLICKER_PRIO 5),确定栈底指针,这是任务堆栈检查的时候要用到的,
栈的大小,没有拓展 TCB,选项是允许堆栈检查,并清空任务创建时的栈。
当运行完 OSStart();main 函数就这样没了~~,正如一些东西,你还没感受它存在,就
消失了。那往哪运行了?我们既然创建了 App_TaskStart 的任务,就有这个函数~
static
{
void App_TaskStart(void* p_arg)
p_arg = p_arg;
/* 初始化 OS 时钟 */
OS_CPU_SysTickInit();
/* 统计任务 */
#if (OS_TASK_STAT_EN > 0)
OSStatInit();
#endif
OSTaskCreateExt(
App_TaskFLICKER,
(void *) 0,
(OS_STK
APP_TASK_FLICKER_PRIO,
*)
&App_TaskFLICKERStk[APP_TASK_FLICKER_STK_SIZE
-
1],
APP_TASK_FLICKER_PRIO,
(OS_STK *) &App_TaskFLICKERStk[0],
APP_TASK_FLICKER_STK_SIZE ,
(void *) 0,
OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR
); // 建立闪灯线程
/* 初始化外设 */
BSP_Init(); // 开启 CPU 外设
while (1) {
OSTaskSuspend(OS_PRIO_SELF);
// 挂起任务
}
}
环中环,套中套,第一个任务,初始化了该初始化的,然后又依葫芦画瓢,又创建一个线程,
最后突然出现了一个莫名奇妙的函数,挂起任务?OSTaskSuspend(OS_PRIO_SELF);
其实,这里是挂起了 SELF,就是自身,App_TaskStart。任务挂起后,系统会重新进行任务
调度,运行下一个优先级最高的就绪任务。
得,这就相当于儿子在荡秋千,需要爸爸给于启动的条件。App_TaskStart 就是爸爸,挂起
就是秋千启动后,你的手不能老不松开啊,这明显影响儿子荡秋千的心情,且能不能荡的起
来还是一回事呢~
好了,下面来看看儿子~~App_TaskFLICKER 函数
OSTaskCreateExt(
App_TaskFLICKER,
(void *) 0,
(OS_STK
APP_TASK_FLICKER_PRIO,
APP_TASK_FLICKER_PRIO,
(OS_STK *) &App_TaskFLICKERStk[0], APP_TASK_FLICKER_STK_SIZE ,
(void *) 0,
OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR
); // 建立闪灯线程
我们又创建了一个叫 App_TaskFLICKER,没有初始化数据,分配堆栈,指定栈顶,任务优
先级,ID 和任务优先级别是相同的值(APP_TASK_FLICKER_PRIO 6),确定栈底指针,
栈的大小,没有拓展 TCB,选项是允许堆栈检查,并清空任务创建时的栈。
&App_TaskFLICKERStk[APP_TASK_FLICKER_STK_SIZE
1],
*)
-
void App_TaskFLICKER(void* p_arg)
static
{
INT8U i;
p_arg = p_arg;
while (1) {
for(i = 0 ; i < 2; i++){
LED1_ON_OFF(i);
OSTimeDlyHMSM(0,0,1,0);
// 延时一秒
}
}
}
任务函数就比较让人惬意了,可以看到传递的参数是 p_arg
其实我们这里并没有用到它,所以,为了避免编译器报错,说我们花了国家的土地,盖了一
个茅房,却不进去如厕,会被严惩的;所以只能有事没事的进去蹲蹲~~p_arg = p_arg;(没
有实际意义的一句话,仅仅为了避免编译器报警)
任务就是一个无限死循环,它的生命周期是要交给内核来定夺的
这里是 LED 灯每隔 1 秒闪烁一次的程序。烧到板上,看到那灯很嚣张的一亮一灭的时候,
心情不免小小激动了~~