临界区的处理
临界区就是访问共享资源的那段代码。ucos内核为了避免在处理临界区的同时有其他任务或中断抢占,所以需要在处理前先关中断,处理完毕后再开中断。关中断的时间是实时内核最重要的指标之一,他影响系统的实时响应特性。关中断的时间在很大程度上取决于微处理器的架构以及编译所生成的代码质量。
ucos定义了两个宏来关中断和开中断
OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()
ucos提供了三种关中断宏定义的实现方法,具体使用哪一种取决于所用的cpu及c编译器。文件OS_CPU.H中定义了常数OS_CRITICAL_METHOD来选择具体使用哪种方法。
1、置OS_CRITICAL_METHOD=1
#define OS_ENTER_CRITICAL() EA=O
#define OS_EXIT_CRITICAL() EA=1
方法简单直接通用。瑕疵就是:比如处理临界区之前中断本来就是关闭的,在处理完毕后由于调用了中断宏,系统返回的就不是原本中断关闭的状态了。在这种情况下,这种实现方法显然不妥,但对于某些特定的微处理器或编译器,这是唯一的选择
2、置OS_CRITICAL_METHOD=2
#define OS_ENTER_CRITICAL
asm("PUSH PSW")
asm("DI")
#define OS_EXIT_CRITICAL()
asm("POP PSW")
优点就是:保护了中断的原始状态;缺点就是必须使用汇编代码,如果某些编译器对嵌入汇编代码优化的 不好,将导致严重的错误。
3、置OS_CRITICAL_METHOD=3
OS_CPU_SR cpu_sr
#define OS_ENTER_CRITICAL()
cpu_sr=get+processor_psw();
Disbale_interrupt();
#define OS_EXIT_CRITICAL() set_processor_psw(cpu_sr);
ge_processor_psw()是一个示意性功能函数,能取得程序状态字psw,将psw保存在局部变量cpu_sr中,其类型在应用程序中定义。Disbale_interrupt()表示禁止中断;set_processor_psw(cp_sr)表示将程序中断开关返回给psw。
任务的形式:
特征:1、具有一个返回类型和一个参数。
2、任务的返回类型必须定义成void
3、任务的 结构必须是两种之一:第一种是无限循环结构
二:只执行一次就被删除的程序。(任务删除后,其代码依然驻留在ram中,至少ucos将任务转入休眠状态,不再管理该段代码,而不是将代码真正的删除,除非重新启动,否则永远都不会再运行。)
例子:
void MYtask(void *pdata)
{
pdata=pdata;//使用一次形式参量,以避免出现编译错误
for(;;)
{
OSMboxPend();
OSQPend();
OSSemPend();
OSTaskDel(OS_PRIO_SELF);
OSTimeDly();
OSTimeDlyHMSM();
用户代码;
}
}
void mytsak(void *pdata)
{
*pdata=*pdata;
用户代码:
OSTaskDel(OS_PRIO_SELF);
}
4、任务永不返回。
任务的状态
包含:休眠、就绪、挂起、被中断和运行五个状态。
任务控制块
OS_TCB是用来保存任务各种状态信息的数据结构,它实现以下功能:
一旦任务建立,任务控制块就被赋值;
当任务的cpu使用权被剥夺时,任务控制块用来保存该任务的状态;
当任务重新得到cpu使用权时,任务控制块能确保任务从当时被中断的哪一点丝毫不差的继续执行。
就绪表
就绪表就是用于存放任务准备就绪标志的列表,它是为了保证每次切换时间的可确定性、一致性和高速性而设置的,整个算法由两个变量、两个表格和三个程序组成的。
两个变量:OSRdyGrp和OSRdyTbl;两个表格分别是位掩码表OSMapTbl和优先级判定表OSUnMapTbl;
三个程序分别是使任务进入就绪、使任务脱离就绪、寻找准备就绪的最高优先级任务的程序。
任务的调度
任务的调度机制是内核的核心。ucos的调度器主要有两个功能:一是确定进入就绪态的任务中哪个优先级最高;
二是进行任务的切换。
调度有两种方式:
任务级的调度是由OSSched()函数完成的;中断级的调度是由OSIntExt()函数完成的。
void OSSched(void){
#if OS_CRITICAL_METHOD==3
OS_CPU_SR cpu_sr;
#end if
INT8U y;
OS_ENTER_CRITICAL()
if((OSLockNesting==0)&&(OSIntNesting==0)){
y=OSUnMapTbl;
OSPrioHighRdy=(INT8U)(Y<<3)+OSUnMapTbl];
if(OSPrioHighRdy!=OSPrioCur){
OSTCBHighRdy=OSTCBPrioTbl];
OSCtxSwCtr++;
OS_TASK_SW();
}
}
OS_EXIT_CRITICAL();
}
任务级的任务的切换
有两种模式:
一是任务级的任务切换,它是通过调用任务切换函数OS_TASK_SW()实现的;
二是中断级的任务切换,它是通过中中断服务程序中调用OSIntSw()函数来实现的;
就是在切换前:当前运行任务的任务控制块指针OSTCBcur之心昂即将被挂起且正在运行的低优先级的任务控制块。堆栈指针sp指向低优先级任务的任务栈的栈顶。当进行切换时,正在运行的低优先级任务的cpu寄存器全部内容就将被推入到它的任务栈中,而保存在准备就绪的高优先级任务栈中的cpu寄存器内容将会被重新装入到cpu寄存器中,高优先级任务更可以在被中断的那一点接着运行。
临界区的处理
临界区就是访问共享资源的那段代码。ucos内核为了避免在处理临界区的同时有其他任务或中断抢占,所以需要在处理前先关中断,处理完毕后再开中断。关中断的时间是实时内核最重要的指标之一,他影响系统的实时响应特性。关中断的时间在很大程度上取决于微处理器的架构以及编译所生成的代码质量。
ucos定义了两个宏来关中断和开中断
OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()
ucos提供了三种关中断宏定义的实现方法,具体使用哪一种取决于所用的cpu及c编译器。文件OS_CPU.H中定义了常数OS_CRITICAL_METHOD来选择具体使用哪种方法。
1、置OS_CRITICAL_METHOD=1
#define OS_ENTER_CRITICAL() EA=O
#define OS_EXIT_CRITICAL() EA=1
方法简单直接通用。瑕疵就是:比如处理临界区之前中断本来就是关闭的,在处理完毕后由于调用了中断宏,系统返回的就不是原本中断关闭的状态了。在这种情况下,这种实现方法显然不妥,但对于某些特定的微处理器或编译器,这是唯一的选择
2、置OS_CRITICAL_METHOD=2
#define OS_ENTER_CRITICAL
asm("PUSH PSW")
asm("DI")
#define OS_EXIT_CRITICAL()
asm("POP PSW")
优点就是:保护了中断的原始状态;缺点就是必须使用汇编代码,如果某些编译器对嵌入汇编代码优化的 不好,将导致严重的错误。
3、置OS_CRITICAL_METHOD=3
OS_CPU_SR cpu_sr
#define OS_ENTER_CRITICAL()
cpu_sr=get+processor_psw();
Disbale_interrupt();
#define OS_EXIT_CRITICAL() set_processor_psw(cpu_sr);
ge_processor_psw()是一个示意性功能函数,能取得程序状态字psw,将psw保存在局部变量cpu_sr中,其类型在应用程序中定义。Disbale_interrupt()表示禁止中断;set_processor_psw(cp_sr)表示将程序中断开关返回给psw。
任务的形式:
特征:1、具有一个返回类型和一个参数。
2、任务的返回类型必须定义成void
3、任务的 结构必须是两种之一:第一种是无限循环结构
二:只执行一次就被删除的程序。(任务删除后,其代码依然驻留在ram中,至少ucos将任务转入休眠状态,不再管理该段代码,而不是将代码真正的删除,除非重新启动,否则永远都不会再运行。)
例子:
void MYtask(void *pdata)
{
pdata=pdata;//使用一次形式参量,以避免出现编译错误
for(;;)
{
OSMboxPend();
OSQPend();
OSSemPend();
OSTaskDel(OS_PRIO_SELF);
OSTimeDly();
OSTimeDlyHMSM();
用户代码;
}
}
void mytsak(void *pdata)
{
*pdata=*pdata;
用户代码:
OSTaskDel(OS_PRIO_SELF);
}
4、任务永不返回。
任务的状态
包含:休眠、就绪、挂起、被中断和运行五个状态。
任务控制块
OS_TCB是用来保存任务各种状态信息的数据结构,它实现以下功能:
一旦任务建立,任务控制块就被赋值;
当任务的cpu使用权被剥夺时,任务控制块用来保存该任务的状态;
当任务重新得到cpu使用权时,任务控制块能确保任务从当时被中断的哪一点丝毫不差的继续执行。
就绪表
就绪表就是用于存放任务准备就绪标志的列表,它是为了保证每次切换时间的可确定性、一致性和高速性而设置的,整个算法由两个变量、两个表格和三个程序组成的。
两个变量:OSRdyGrp和OSRdyTbl;两个表格分别是位掩码表OSMapTbl和优先级判定表OSUnMapTbl;
三个程序分别是使任务进入就绪、使任务脱离就绪、寻找准备就绪的最高优先级任务的程序。
任务的调度
任务的调度机制是内核的核心。ucos的调度器主要有两个功能:一是确定进入就绪态的任务中哪个优先级最高;
二是进行任务的切换。
调度有两种方式:
任务级的调度是由OSSched()函数完成的;中断级的调度是由OSIntExt()函数完成的。
void OSSched(void){
#if OS_CRITICAL_METHOD==3
OS_CPU_SR cpu_sr;
#end if
INT8U y;
OS_ENTER_CRITICAL()
if((OSLockNesting==0)&&(OSIntNesting==0)){
y=OSUnMapTbl;
OSPrioHighRdy=(INT8U)(Y<<3)+OSUnMapTbl];
if(OSPrioHighRdy!=OSPrioCur){
OSTCBHighRdy=OSTCBPrioTbl];
OSCtxSwCtr++;
OS_TASK_SW();
}
}
OS_EXIT_CRITICAL();
}
任务级的任务的切换
有两种模式:
一是任务级的任务切换,它是通过调用任务切换函数OS_TASK_SW()实现的;
二是中断级的任务切换,它是通过中中断服务程序中调用OSIntSw()函数来实现的;
就是在切换前:当前运行任务的任务控制块指针OSTCBcur之心昂即将被挂起且正在运行的低优先级的任务控制块。堆栈指针sp指向低优先级任务的任务栈的栈顶。当进行切换时,正在运行的低优先级任务的cpu寄存器全部内容就将被推入到它的任务栈中,而保存在准备就绪的高优先级任务栈中的cpu寄存器内容将会被重新装入到cpu寄存器中,高优先级任务更可以在被中断的那一点接着运行。