一.UCOS
1.概念
uc/OS-III(Micro C OS Thee),微型C语言编写的操作系统第三版。是一个可升级,可固化,多任务基于优先级的可抢占式实时内核。
ucos的任务个数不限制,实现了操作系统所需求的大部分功能,资源管理,同步,任务之间的通信。除了这些基本的功能以外,还提供一些其他的实时性内核找不到的特色功能,比如完备的运行时间测量,也可以直接发送信号/消息到某个任务,任务也可以同时等待多个内核对象
由于ucos体积微小,功能强悍,可移植性强,在微控制器领域应用广泛
ucos要收费,有时候我们会选择免费的系统,比如freeRTOS....,以及一些其他和物联网结合操作系统(华为liteOS 阿里巴巴.. 腾讯..)
2.ucos移植
(1)源代码结构
EvalBoards ------------ 工程文件
uc-CPU -------------- CPU相关代码
uc-LIB -------------- 和硬件/编译器 无关的库函数(字符串 数学 内存)
uCOS-III ----------- ucos操作系统相关代码
(2)将源码拷贝到工程,修改源码(详情见手册)
(3)特性
3.ucos的任务调度和任务
合作式调度 -------- 多个任务按照指定时间和顺序依次运行,下一个任务等待上一个任务时间用完再开始运行
抢占式调度 -------- 在任务时间片没有用完时,优先级高的任务先运行,ucos使用抢占式调度
(1)创建任务 ------ OSTaskCreate()
void OSTaskCreate (OS_TCB *p_tcb,//任务控制块(TCB) |
(2)任务函数编写注意事项
无返回值,void *参数
通常要写成死循环
任务内部要加延时,让出CPU
延时函数:
delay_us/delay_ms
void OSTimeDlyHMSM (CPU_INT16U hours,//时
|
(3)ucos启动
主函数
初始化时钟----->中断优先级分组----->串口初始化----->其他硬件初始化----->初始化ucos----->创建起始任务(启动实际工作的任务)---->启动ucos
起始任务:
CPU初始化----->创建任务----->删除起始任务
具体工作任务:
根据具体需求完成具体工作
(3)ucos任务抢占
任务执行的时候,高优先级的任务会抢占低优先级任务的CPU(数字越小优先级越高,优先级相同互相抢占)
4.将裸机代码移植到ucos
大部分的代码直接使用即可,只有和延时相关,中断相关的代码需要修改
(1)延时的修改
如果延时时间是os tick的倍数,直接使用系统延时
如果不是,将系统调度关闭来用作延时,延时完成之后再恢复系统调度
(2)中断的修改
主要是要修改中断处理函数
在中断处理函数开始时加上
OSIntEnter();
在中断处理函数结束时加上
OSIntExit();
注;调用了ucos中的函数需要包含includes.h头文件
二.ucos中互斥和同步,任务通信,定时器等的操作
1.临界区
由于ucos支持多任务,某个任务执行有可能被其他任务(中断)打断,但是某些代码如果执行过程中被打断,造成执行失败。
为了避免这种情况,我们可以使用临界区来保护我们不希望被打断的代码。
进入临界区的本质就是关闭系统任务调度和抢占,甚至关闭中断,从而保证临界区的代码执行不会被打断,保证执行成功,当临界区代码(关键代码)执行完毕,
在退出临界区,恢复任务调度和抢占,或者中断,从而恢复系统的正常执行
CPU_SR_ALLOC();//分配变量 OS_CRITICAL_ENTER();//进入临界区 执行关键代码..... OS_CRITICAL_EXIT();//退出临界区 |
注意事项:
在临界区关键代码中禁止使用延时阻塞函数,这些函数会失效,甚至影响任务的运行
可以通过os_cfg.h中宏 OS_CFG_ISR_POST_DEFERRED_EN 的设置来决定临界区代码中是否禁用中断,设置为1,不禁用中断,0禁止中断
2.ucos的时基
ucos提供最小的时间单位由系统tick决定,tick值的设置在os_cfg_app.h中宏 OS_CFG_TICK_RATE_HZ
该宏的取值范围10-1000Hz,周期1ms-100ms
以上取值最小时间单位就是5ms,此时系统延时最小时间是5ms,低于5ms的系统延时会失效
这个宏的值会影响ucos系统的功耗,值越大功耗越高,值越大高优先级的任务执行越及时
在实际应用中,如果是电池供电或者设备有功耗要求,该值尽量调低
如果固定电源供电,不关系功耗,该值可以调高
3.ucos的信号量
ucos中的信号量的原理和Linux中的信号量一样,也是一个计数器,可以进行PV操作,计数值为0就阻塞P操作,直到重新大于0在解除阻塞
创建信号量 -------- OSSemCreate()
void OSSemCreate (OS_SEM
*p_sem,//指向信号量(控制块) |
等待信号量(P操作) ----- OSSemPend()
OS_SEM_CTR OSSemPend (OS_SEM *p_sem,//指向信号量(控制块)
|
发送信号量(V操作) ----- OSSemPost()
OS_SEM_CTR OSSemPost (OS_SEM *p_sem,,//指向信号量(控制块)
|