本文是《嵌入式实时操作系统ucosii原理及应用(任哲)》一书第三章的阅读笔记,知识点多为摘录,若希望深入了解,请购买该书认真研读。由于一些知识比较零散,记起来不大方便,又习惯画图辅助记忆,刚好想起一款比较好用的思维导图,就顺手拿来用一用了(绝非打广告),导图中包含部分备注。
脑图链接及密码:http://naotu.baidu.com/file/c550d674fa54bd29588c31c5bd682f4f?token=8e71f5732699f4b6 密码: v6um
可以看出:A)任务必须先从睡眠状态进入就绪状态,才能在合适的时机被运行;B)只能从运行状态进入中断服务状态;C)只能从运行状态进入等待状态。
前面一章我们已经讲过:大多数任务(尤其是用户任务)是一个无限循环结构,在这个循环中,系统响应中断请求,进入中断服务函数进行其他操作。但是,有时任务中的一些操作是不允许被中断打断的,为此,我们可以在任务函数程序代码中添加关中断函数和开中断函数,则在这两个函数之间的代码,执行过程不会被打断,该段代码称为临界段。ucosii中用两个宏:OS_ENTER_CRITICAL( )、OS_EXIT_CRATICAL( )分别实现关中断和开中段。从程序设计角度看,一个ucosii任务的代码就是一个C语言函数,为了可以传递各种不同类型的数据甚至是函数,ucosii把任务参数定义成了一个void类型的指针。
用户应用程序的一般结构:
在ucosii中,main函数与任务函数的地位是平等的,虽然任务是在main函数中初始化的,但是任务和main的运行与中断是由操作系统调度的,也就是说,作为程序运行的入口函数,main函数必须完成操作系统的初始化、任务的创建、操作系统的启动,最后把系统的调度权交回给操作系统。
void MyTask1(void *pdata)
{
for( ; ; )
{
//这上面的代码执行时可以被打断
OS_ENTER_CRITICAL( );
//临界段
//这中间执行的代码不可以被打断
OS_ENTER_CRITICAL( );
}
}
void MyTask2(void *pdata)
{
for( ; ; )
{
//这上面的代码执行时可以被打断
OS_ENTER_CRITICAL( );
//临界段
//这中间执行的代码不可以被打断
OS_ENTER_CRITICAL( );
}
}
void main(void)
{
OS_Init( );
OSTaskCreate(MyTask1,...);
OSTaskCreate(MyTask2,...);
OS_Start( );
}
操作系统运行时,一定有某段时间处于空闲状态,但是CPU是不可以停下来的,除非断电。为此,ucosii定义了两个系统任务:空闲任务和统计任务。空闲任务是用户应用程序必须使用的,统计任务是用户程序可选择使用的。
//操作系统定义的空闲任务
void OS_TaskIdle(void *pdata)
{
#if(OS_CRITICAL_METHOD == 3)
OS_CPU_SR cpu_sr;
#endif
//部分C编译器会对定义了却没有使用的变量报错
pdata = pdata;
for( ; ; )
{
OS_ENTER_CRITICAL( );
OSIdleCtr++; //记录空闲任务运行次数
OS_EXIT_CRITICAL( );
//一般还会加上下面这个函数,用户可以在该函数中写用户希望执行的代码
//一般函数内写的是让CPU进入低功耗模式的指令
//该函数总是处于就绪状态的
OSTaskIdleHook( );
}
}
至于统计任务,该任务每秒计算一次CPU在单位时间内被使用的时间,并把计算结果以百分比的形式存放在变量OSCPUsage中,从而使得应用程序可以了解CPU的利用率。
当不同任务同时需要运行时,系统利用优先级判断哪个先执行,由于大多数情况下任务数少于64个,用户可以通过修改OS_CFG.h文件的OS_LOWEST_PRIO来确定最低优先级(优先级为:0~OS_LOWEST_PRIO)。OS_LOWEST_PRIO赋给空闲任务,如果用户使用了统计任务,系统还会把(OS_LOWEST_PRIO-1)赋给统计任务,用户可以使用的优先级范围为:0~OS_LOWEST_PRIO-2,在创建任务时,用户必须指定任务的优先级(指定OSTaskCreate( )第四个参数)。
任务堆栈:任务的运行环境,在程序设计上体现为一数组,出栈入栈遵循LIFO后进先出的原则。任务堆栈的定义:宏定义设置堆栈存储单位(可理解为数据类型)type、宏定义设置堆栈大小size、用type定义大小为size的数组用作任务堆栈。
任务的定义:使用系统函数OSTaskCreate(指向任务代码的指针,传递给任务的参数,任务堆栈的栈顶指针,任务优先级),需要提醒的是,处理器不同,栈的生长方向不同,stm32f103的栈生长方向是从高地址到低地址,所以栈顶指针是堆栈数组的最后一个成员的地址。
int 16位;unsigned int 位数与操作系统相关。
任务堆栈的初始化:由于任务的运行前,CPU的各个寄存器需要预置一些原始数据,包括指向任务的指针、程序状态字PSW等,因为它们因任务不同而有差异,所以存储在任务堆栈中,创建任务时将这些值放入堆栈中称为堆栈的初始化。堆栈的初始化由OSTaskCreat( )函数调用OSTaskStkInit( )实现,用户除了在移植操作系统时修改它,基本不会接触到这个函数。
附上一篇的脑图链接及密码:http://naotu.baidu.com/file/8910fc6778b390b730a755e610790477?token=86bdf5ad5bee75c3 密码: SC2h