|
清单 L 1.8
建立其它任务的任务。
void TaskStart (void *data)
{
Prevent compiler warning by assigning ‗data‘ to itself;
Display banner identifying this as EXAMPLE #1; (1)
OS_ENTER_CRITICAL();
PC_VectSet(0x08, OSTickISR); (2)
PC_SetTickRate(200); (3)
OS_EXIT_CRITICAL();
Initialize the statistic task by calling ‗OSStatInit()‘; (4)
μ /C OS-II:源码公开的实时嵌入式操作系统
12
Create 10 identical tasks; (5)
for (;;) {
Display the number of tasks created;
Display the % of CPU used;
Display the number of task switches in 1 second;
Display uC/OS-II‘s version number
If (key was pressed) {
if (key pressed was the ESCAPE key) {
PC_DOSReturn();
}
}
Delay for 1 Second;
}
}
在建立其他任务之前,必须调用 OSStatInit()[L1.8(4)]来确定用户的 PC 有多快,如 程序清单 L1.9 所示。在一开始,OSStatInit()就将自身延时了两个时钟节拍,这样它就可 以与时钟节拍中断同步[L1.9(1)]。因此,OSStatInit()必须在时钟节拍启动之后调用;否 则,用户的应用程序就会崩溃。当 μC/OS-II 调用 OSStatInit()时,一个 32 位的计数器 OSIdleCtr 被清为 0 [L1.9(2)],并产生另一个延时,这个延时使 OSStatInit()挂起。此 时,uCOS-II 没有别的任务可以执行,它只能执行空闲任务(μC/OS-II 的内部任务)。空闲 任务是一个无线的循环,它不断的递增 OSIdleCtr[L1.9(3)]。1 秒以后,uCOS-II 重新开始 OSStatInit(),并且将 OSIdleCtr 保存在 OSIdleMax 中[L1.9(4)。所以 OSIdleMax 是 OSIdleCtr 所能达到的最大值。而当用户再增加其他应用代码时,空闲任务就不会占用那样 多的 CPU 时间。OSIdleCtr 不可能达到那样多的记数,(如果拥护程序每秒复位一次 OSIdleCtr)CPU 利用率的计算由 μC/OS-II 中的 OSStatTask()函数来完成,这个任务每秒 执行一次。而当 OSStatRdy 置为 TRUE[L1.9(5)],表示 μC/OS-II 将统计 CPU 的利用率。
程序清单 L 1.9
测试 CPU 速度。
void OSStatInit (void)
{
OSTimeDly(2); (1)
OS_ENTER_CRITICAL();
OSIdleCtr = 0L; (2)
OS_EXIT_CRITICAL();
OSTimeDly(OS_TICKS_PER_SEC); (3)
μ /C OS-II:源码公开的实时嵌入式操作系统
13
OS_ENTER_CRITICAL();
OSIdleCtrMax = OSIdleCtr; (4)
OSStatRdy = TRUE; (5)
OS_EXIT_CRITICAL();
}
1.07.03 TaskN()
OSStatInit()将返回到 TaskStart()。现在,用户可以建立 10 个同样的任务(所有任 务共享同一段代码)。所有任务都由 TaskStart()中建立,由于 TaskStart()的优先级为 0(最 高),新任务建立后不进行任务调度。当所有任务都建立完成后,TaskStart()将进入无限循 环之中,在屏幕上显示统计信息,并检测是否有 ESC 键按下,如果没有按键输入,则延时一 秒开始下一次循环;如果在这期间用户按下了 ESC 键,TaskStart()将调用 PC_DOSReturn() 返回 DOS 系统。 程序清单 L1.10 给出了任务的代码。任务一开始,调用 OSSemPend()获取信号量 RandomSem [程序清单 L1.10(1)](也就是禁止其他任务运行这段代码—译者注),然后调用 Borland C/C++的库函数 random()来获得一个随机数[程序清单 L1.10(2)],此处设 random ()函数是不可重入的,所以 10 个任务将轮流获得信号量,并调用该函数。当计算出 x 和 y 坐标后[程序清单 L1.10(3)],任务释放信号量。随后任务在计算的坐标处显示其任务号 (0-9,任务建立时的标识)[程序清单 L1.10(4)]。最后,任务延时一个时钟节拍[程序清 单 L1.10(5)],等待进入下一次循环。系统中每个任务每秒执行 200 次,10 个任务每秒钟将 切换 2000 次。
程序清单 L 1.10
在屏幕上显示随机位置显示数字的任务。
void Task (void *data)
{
UBYTE x;
UBYTE y;
UBYTE err;
for (;;) {
OSSemPend(RandomSem, 0, &err); (1)
x = random(80); (2)
y = random(16);
μ /C OS-II:源码公开的实时嵌入式操作系统
14
OSSemPost(RandomSem); (3)
PC_DispChar(x, y + 5, *(char *)data, DISP_FGND_LIGHT_GRAY); (4)
OSTimeDly(1); (5)
}
}
1.08 例2
例 2 使用了带扩展功能的任务建立函数 OSTaskCreateExt()和 uCOS-II 的堆栈检查操 作(要使用堆栈检查操作必须用 OSTaskCreateExt()建立任务—译者注)。当用户不知道应 该给任务分配多少堆栈空间时,堆栈检查功能是很有用的。在这个例子里,先分配足够的堆 栈空间给任务,然后用堆栈检查操作看看任务到底需要多少堆栈空间。显然,任务要运行足 够长时间,并要考虑各种情况才能得到正确数据。最后决定的堆栈大小还要考虑系统今后的 扩展,一般多分配 10%,25%或者更多。如果系统对稳定性要求高,则应该多一倍以上。 uCOS-II 的堆栈检查功能要求任务建立时堆栈清零。OSTaskCreateExt()可以执行此项 操作(设置选项 OS_TASK_OPT_STK_CHK 和 OS_TASK_OPT_STK_CLR 打开此项操作)。如果任务 运行过程中要进行建立、删除任务的操作,应该设置好上述的选项,确保任务建立后堆栈是 清空的。同时要意识到 OSTaskCreateExt()进行堆栈清零操作是一项很费时的工作,而且取 决于堆栈的大小。执行堆栈检查操作的时候,uCOS-II 从栈底向栈顶搜索非 0 元素(参看图 F 1.1),同时用一个计数器记录 0 元素的个数。 例 2 的磁盘文件为\SOFTWARE\uCOS-II\EX2_x86L,它包含 9 个任务。加上 uCOS-II 本身 的两个任务:空闲任务(idle task)和统计任务。与例 1 一样 TaskStart()由 main() 函数建立,其功能是建立其他任务并在屏幕上显示如下的统计数据:
|
|