(1)裸机系统
裸机系统通常分成轮询系统和前后台系统 1.轮询系统 轮询系统即是在裸机编程的时候,先初始化好相关的硬件,然后让主程序在一个死循环里面不断循环,顺序地做各种事情.轮询系统是一种非常简单的软件结构,通常只适用于那些只需要顺序执行代码且不需要外部事件来驱动的就能完成的事情.只适合顺序执行的功能代码,当有外部事件驱动时,实时性就会降低
2.前后台系统 前后台系统是在轮询系统的基础上加入了中断。外部事件的响应在中断里面完成,事件的处理还是回到轮询系统中完成,后台程序是一个死循环,也称为“任务级”,前台程序则是中断服务程序,也称为“中断级”;一般的低成本应用多采用这种程序结构。在顺序执行后台程序的时候,如果有中断来临,那么中断会打断后台程序的正常执行流,转而去执行中断服务程序
(2)实时内核系统 它把系统功能划分为多个任务,每个任务只完成特定的一个功能,通常都为死循环,在多任务系统中,任务跟中断一样,也具有优先级,优先级高的任务会被优先执行。;CPU在任意时刻只能执行一个任务,但每个任务都认为自己在独自使用整个CPU,由于处理器速度非常快,任务切换的速度也非常快,所以看起来几乎多个任务同时被执行;对多任务的管理就是实时内核所要做的工作,实现CPU资源的最大化利用。
uC/OS-III是一个可剥夺型内核(抢占式内核,Preemptive Kernel),它总是执行当前就绪任务中优先级最高的那个;uC/OS-III被设计用于32位处理器;uC/OS-III至少需要4KB RAM资源的微控制器上运行
比较:
使用顺序: (1)调用OSInit()初始化UCOSIII
(2)创建任务,在main()只创建一个start_task任务,其他任务都在start_task
任务中创建,但是在调用OSTaskCreate()创建任务的时候,必须先调用
OS_CRITICAL_ENTER()进入临界区,任务创建完毕调用
OS_CRITICAL_EXIT()退出临界区。
(3)调用OSStart()开启UCOSIII
注:在调用OSStart()开启UCOS之前一定要至少创建一个任务,在调用OSInit()初始化ucos时已经创建了一个空闲任务。
任务:在多任务系统中,我们根据功能的不同,把整个系统分割成一个个独立的且无法返回,无限循环的函数,这个函数我们称为任务。
(1)任务状态
UCOSIII是单核CPU,在某一时刻只有一个任务会获得CPU使用权进入 运行态,其他任务进入其他状态,
(2)任务控制块
在裸机系统中,程序的主体是 CPU 按照顺序执行的。而在多任务系统中,任务的执行是由系统调度的。系统为了顺利的调度任务,为每个任务都额外定义了一个任务控制块 TCB(Task ControlBlock),这个**任务控制块就相当于任务的身份证,里面存有任务的所有信息,比如任务的栈,任务名称,任务的形参等。**有了这个任务控制块之后,以后系统对任务的全部操作都可以通过这个 TCB 来实现。 TCB 是一个新的数据类型(结构体)
OS_TCB用来保存任务的信息,使用OSTaskCreate()来创建任务的时候就会给任务分配一个任务控制块(结构体)
(3)任务堆栈
任务堆栈用来在切换任务和调用其他函数的时候保留现场,每个任务都有自己的任务堆栈
创建任务堆栈:
// CPU_STK 是4个字节的数据类型,栈的大小为64*4字节
CPU_STK TASK_STK[64] //创建一个任务堆栈
标准:
#define TASK_STK_SIZE 64 //任务堆栈大小
CPU_STK TASK_STK[TASK_STK_SIZE] //任务堆栈
在调用OSTaskCreate()创建任务的时候可以把创建的堆栈传递给任务, 将堆栈的基地址传递给OSTaskCreate()参数p_stk_base,将堆栈的深度传递给stk_limit,堆栈的深度通常为堆栈大小的十分之一,用来检测堆栈是否为空,将堆栈的大小传递给stk_size.
(4)任务就绪表 (任务的优先级)
UCOSIII将已经就绪的任务放在就绪表里,任务就绪表有两部分 优先级位映射表OSPrioTal[] 和 就绪任务列表OSRdyList[]
优先级位映射表一般用来标记那些任务就绪了的 就绪任务列表记录每一个优先级下所有就绪的任务
注: 一下优先级在原子的开发板中不能使用,已分配给相应任务 优先级0:中断服务服务管理任务 OS_IntQTask() 优先级1:时钟节拍任务 OS_TickTask() 优先级2:定时任务 OS_TmrTask() 优先级OS_CFG_PRIO_MAX-2:统计任务 OS_StatTask() 优先级OS_CFG_PRIO_MAX-1:空闲任务 OS_IdleTask()
1.优先级位映射表OSPrioTal[] 当某个任务就绪后就会将优先级位映射表中相应位置1, 从左到右优先级降低,但是每个OSPrioTal[]数组的元素最低位在右,最高位在左。这样的目的为了支持一条特殊的指令"计算前导零(CLZ)",该指令可以快速找到最高优先级任务
有关优先级任务操作函数
OS_PrioGetHighest() //获取就绪表中最高优先级任务
OS_PrioInset() //将某个任务在就绪表中相应位置置1
OS_PrioRemove() //将某个任务在就绪表中清零
2.就绪任务列表 OSRdyList[]数组元素的类型为OS_RDY_LIST(结构体) OSRdyList[]数组中每一个元素对于一个优先级,OSRdyList[0]用来管理优先级0下的所有任务,这些任务通过链表来管理 HeadPtr和TailPtr分别指向链表的头和尾,
在优先级4下右3个任务通过链表来管理: 同一个优先级支持多个任务的时候才需要使用头尾指针来将 TCB 串成一个双向链表
就绪列表操作函数
(5)任务调度和切换
1.可剥夺型调度 任务调度和切换就是让就绪表中优先级最高的任务获得CPU的使用权, 任务的调度是由一个叫做任务调度器的东西来完成,任务调度器有两种: 任务级调度器和中断级调度器
2.时间片轮转调度 概念:允许一个任务运行一段时间(时间片)后让出CPU的使用权,让拥有同优先级的下一个任务运行。 在优先级N下有3个任务,时间片划分为4个时间节拍
4.任务相关API
(1)创建任务 OSTaskCreate()函数 一个任务应该包含 任务优先级,任务控制块,任务堆栈,任务函数
任务优先级,任务堆栈,任务的函数实体,任务的 TCB ***最终需要联系起来才能由系统进行统一调度。***那么这个联系的工作就由任务创建函数 OSTaskCreate 来实现,
void OSTaskCreate (OS_TCB *p_tcb,
CPU_CHAR *p_name,
OS_TASK_PTR p_task,
void *p_arg,
OS_PRIO prio,
CPU_STK *p_stk_base,
CPU_STK_SIZE stk_limit,
CPU_STK_SIZE stk_size,
OS_MSG_QTY q_size,
OS_TICK time_quanta,
void *p_ext,
OS_OPT opt,
OS_ERR *p_err)
(2)任务删除函数 OSTaskDel()
void OSTaskDel (OS_TCB *p_tcb,
OS_ERR *p_err)
(3)任务挂起 OSTaskSuspend()
void OSTaskSuspend (OS_TCB *p_tcb,
OS_ERR *p_err)
(4)任务恢复 OS_TaskResume()
void OS_TaskResume (OS_TCB *p_tcb,
OS_ERR *p_err)
(5) OSSchedRoundRobinCfg() 使能或者失能UCOSIII的时间片轮转调度功能
void OSSchedRoundRobinCfg (CPU_BOOLEAN en,
OS_TICK dflt_time_quanta,
OS_ERR *p_err)
(6) OSSchedRoundRobinYield() 当一个任务放弃本次时间片,把CPU的使用权让给同级下的另一个任务:
void OSSchedRoundRobinYield (OS_ERR *p_err)