UCOS

序章

延时函数

1
2
3
4
5
6
7
8
9
void  OSTimeDlyHMSM (CPU_INT16U   hours,
CPU_INT16U minutes,
CPU_INT16U seconds,
CPU_INT32U milli,
OS_OPT opt,
OS_ERR *p_err)

OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_HMSM_STRICT,&err); //延时1s
//strick adj. 严格的;绝对的;精确的;详细的

任务管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//创建开始任务
OSTaskCreate((OS_TCB * )&StartTaskTCB, //任务控制块
(CPU_CHAR * )"start task", //任务名字
(OS_TASK_PTR )start_task, //任务函数
(void * )0, //传递给任务函数的参数
(OS_PRIO )START_TASK_PRIO, //任务优先级
(CPU_STK * )&START_TASK_STK[0], //任务堆栈基地址
(CPU_STK_SIZE)START_STK_SIZE/10, //任务堆栈深度限位
(CPU_STK_SIZE)START_STK_SIZE, //任务堆栈大小
(OS_MSG_QTY )0, //任务内部消息队列能够接收的最大消息数目,为0时禁止接收消息
(OS_TICK )0, //当使能时间片轮转时的时间片长度,为0时为默认长度,
(void * )0, //用户补充的存储区
(OS_OPT )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, //任务选项
(OS_ERR * )&err); //存放该函数错误时的返回值


  1. (CPU_STK_SIZE)START_STK_SIZE/10, //任务堆栈深度限位 一般设定小于10%即可

  2. (OS_TCB * )&StartTaskTCB, //任务控制块 不要访问和更改其中的成员变量

优先级

  • 数值越小优先级越高

  • os_cfg.h line48 OS_CFG_PRIO_MAX 最大优先级数

就绪表

  • 优先级位映射表**OSPrioTbl[]**:用来记录哪个优先级下有任务就绪
  • 就绪任务列表**OSRdyList[]**:用来记录每一个优先级下所有就绪的任务

前导零

  • 硬件计算 能计算一个值前面有多少零

任务调度

任务调度

  • 任务调度器 进入中断 OSIntEnter();
  • 任务调度器 退出中断 OSIntExit();

发生任务调度的调度点

  • 延时函数OSTimeDly()(按时间延时)或者OSTimeDlyHMSM()(按节拍延时)
  • 创建、删除任务
  • 改变优先级
  • 通过调用OSTaskSuspend()将自身挂起、或解除某个挂起的任务
  • OSSched() 用户自行请求调度

调度器上锁解锁

  • OSSchedLock()加锁
  • OSSchedUnlock()解锁

时间片轮转调度

  • 待补充

UCOS系统初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
int main(void)
{
OS_ERR err;
……
//其他函数,一般为外设初始化函数
……
OSInit(&err);
……
//其他函数,一般为创建任务函数
……
OSStart(&err);
}

  • OSInit()必须先于其他的UCOS函数调用包括OSStart()

任务创建与管理

任务的创建

1
2
3
4
5
6
7
8
9
10
11
12
13
OSTaskCreate((OS_TCB 	* )&StartTaskTCB,		//任务控制块
(CPU_CHAR * )"start task", //任务名字
(OS_TASK_PTR )start_task, //任务函数
(void * )0, //传递给任务函数的参数
(OS_PRIO )START_TASK_PRIO, //任务优先级
(CPU_STK * )&START_TASK_STK[0], //任务堆栈基地址
(CPU_STK_SIZE)START_STK_SIZE/10, //任务堆栈深度限位
(CPU_STK_SIZE)START_STK_SIZE, //任务堆栈大小
(OS_MSG_QTY )0, //任务内部消息队列能够接收的最大消息数目,为0时禁止接收消息
(OS_TICK )0, //当使能时间片轮转时的时间片长度,为0时为默认长度,
(void * )0, //用户补充的存储区
(OS_OPT )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, //任务选项
(OS_ERR * )&err); //存放该函数错误时的返回值

OS_ERR 错误代码

任务的删除

1
2
3
4
void  OSTaskDel (OS_TCB  *p_tcb,
OS_ERR *p_err);

OSTaskDel((OS_TCB*)&Task2_TaskTCB,&err);

不建议在系统运行时删除任务

尽管UCOSIII允许在系统运行中删除任务,但是应该尽量避免这种操作,如果这个任务可能占有与其他任务共享的资源,在删除此任务之前这个被占有的资源没有被释放就有可能导致奇怪的结果。

任务的挂起与恢复

挂起

1
2
3
4
void   OSTaskSuspend (OS_TCB  *p_tcb,
OS_ERR *p_err);

OSTaskSuspend((OS_TCB*)&Task2_TaskTCB,&err);//挂起任务2

挂起错误

  • 任务被加锁
  • 任务空闲

恢复

1
2
3
4
void  OSTaskResume (OS_TCB  *p_tcb,
OS_ERR *p_err)

OSTaskResume((OS_TCB*)&Task2_TaskTCB,&err); //恢复任务2

恢复错误

  • 任务状态无效(错误的状态)、任务不是已经挂起的
  • 不能恢复自己

时间片轮转调度

1
2
3
4
5
6
7
8
9
void  OSSchedRoundRobinCfg (CPU_BOOLEAN   en,
OS_TICK dflt_time_quanta,
OS_ERR *p_err)

#if OS_CFG_SCHED_ROUND_ROBIN_EN //当使用时间片轮转的时候
//使能时间片轮转调度功能,时间片长度为1个系统时钟节拍,既1*5=5ms
OSSchedRoundRobinCfg(DEF_ENABLED,1,&err);
#endif

初始化

  • 设置宏 OS_CFG_SCHED_ROUND_ROBIN_EN 为1
  • 调用函数 OSSchedRoundRobinCfg() 开启时间片轮转调度功能

时间片的放弃

OSSchedRoundRobinYield(&err);

注:

时间片如果不够执行可能会产生奇怪的效果请注意

系统内部任务

  1. 中断服务管理任务

  2. 时钟节拍任务

  3. 定时任务(可选)

  4. 统计任务(可选)

  5. 空闲任务

中断服务管理任务

  • 默认优先级最高,第一,不可更改。

时钟节拍任务

  • 优先级较高,第二。

定时任务(可选)

  • 默认优先级,第三。

  • 提供软件定时功能

  • 将宏OS_CFG_TMR_EN设置为1就会使能定时任务,在OSInit()中将会调用函数OS_TmrInit()来创建定时任务。

统计任务(可选)

  • 一般优先级,倒数第二。
  • 统计CPU使用率,堆栈使用率
  • 可选创建(将宏OS_CFG_STAT_TASK_EN置1)
  • 必须在main函数创建的以一个任务也是唯一的一个应用任务里面调用函数**OSStatTaskCPUUsageInit()**查询使用情况

空闲任务

  • 优先级最低,倒数第一。
  • 不能调用会使空闲任务进入等待态的函数。
  • 可统计CPU使用率(用处)

钩子函数

共有8个

  1. OSIdleTaskHook(), 空闲任务 调用这个函数,可以用来让CPU进入低功耗模式
  2. OSInitHook(), 系统初始化 函数OSInit()调用此函数
  3. OSStatTaskHook(), 统计任务每秒 中都会调用这个函数,此函数允许你向统计任务中添加自己的应用函数。
  4. OSTaskCreateHook(), 任务创建 的钩子函数。
  5. OSTaskDelHook(), 任务删除 的钩子函数。
  6. OSTaskReturnHook(), 任务意外返回 时调用的钩子函数,比如删除某个任务
  7. OSTaskSwHook(), 任务切换 时候调用的钩子函数。
  8. OSTimeTickHook(), 滴答定时器 调用的钩子函数。

中断时间管理

1
2
3
4
5
6
7
8
9
void USART1_IRQHandler(void)
{
OSIntEnter();
//中断服务程序
OSIntExit();
}



  • 最大250级中断嵌套

临界区代码保护

临界区:不可被打断的代码段

OS_CFG_ISR_POST_DEFERRED_EN 的值与临界段代码保护方式

0关中断
1调度器上锁(可能会被其它中断打断)
  1. 进入临界段

    • 一个进入函数
  2. 退出临界段

    • 退出后产生调度——-OS_CRITICAL_EXIT()

    • 退出后不产生调度—-OS_CRITICAL_EXIT_NO_SCHED()

CPU_SR_ALLOC()

  1. 函数CPU_SR_ALLOC()是为CPU_CRITICAL_ENTER()和CPU_CRITICAL_EXIT()申请一个变量:

#define CPU_SR_ALLOC() CPU_SR cpu_sr = (CPU_SR)0

这个是临界代码段,在下面一个小节有详细讲解。

  1. 这样做是为了防止编译器警告。

任务延时

  • 开始延时
OSTimeDly()相对延时基于时钟节拍
绝对延时
周期延时
OSTimeDlyHMSM()相对延时基于时间
  • 取消延时

    延时任务任务可通过在其他任务中调用函数OSTimeDlyResume()取消延时而进入就绪状态,此函数最后会引发一次任务调度。

获取系统时间

​ UCOSIII定义了一个 CPU_INT32U 类型的全局变量 OSTickCtr 来记录系统时钟节拍数,在调用 OSInit() 时被初始化为 0,以后每发生1个时钟节拍,OSTickCtr加1。

  • OSTimeSet()允许用户改变当前时钟节拍计数器的值
  • OSTimeGet()用来获取动迁时钟节拍计数器的值

软件定时器

​ 定时器本质是递减计数器,当计数器减到零时可以执行回调函数。应用程序可以有任意数量的定时器,UCOSIII中定时器的时间分辨率由一个宏 OS_CFG_TMR_TASK_RATE_HZ 确定,单位为HZ,默认为100Hz。

  • 避免在回调函数使用 阻塞删除 定时器任务的函数。

软件定时器的API

OSTmrCreate()创建定时器并制定运行模式
OSTmrDel()删除定时器
OSTmrRemainGet()获取定时器的剩余时间
OSTmrStart()启动定时器计数
OSTmrStateGet()获取当前定时器状态
OSTmrStop()停止计数器倒计时

OSTmrCreate()有三种模式

  • 单次模式(通过OSTmrStart()触发)
  • 周期无延迟模式
  • 周期有延迟模式

信号量、互斥信号量、内嵌信号量

信号量

信号量像是一种上锁机制,代码必须获得对应的钥匙才能继续执行,一旦获得了钥匙,也就意味着该任务具有进入被锁部分代码的权限。一旦执行至被锁代码段,则任务一直等待,直到对应被锁部分代码的钥匙被再次释放才能继续执行。

  • 信号量用于控制对共享资源的保护,但是现在基本用来做任务同步用。

信号量API

OSSemCreate()建立一个信号量
OSSemDel()删除一个信号量
OSSemPend()等待一个信号量
OSSemPendAbrot()取消等待
OSSemPost()释放或者发出一个信号量
OSSemSet()强制设置一个信号量的值
1
2
3
4
5
6
7
8
9
void  OSSemCreate (OS_SEM      *p_sem,		//OS_SEM	MY_SEM;	定义一个信号量,用于访问共享资源
CPU_CHAR *p_name, //"MY_SEM" 名称
OS_SEM_CTR cnt, //如果设置成计数型信号量 此处设置成对应数字即可 如果设置成二进制信号量 此处设置成0即可
OS_ERR *p_err) //

OSSemCreate ((OS_SEM* )&MY_SEM,
(CPU_CHAR* )"MY_SEM",
(OS_SEM_CTR)1,
(OS_ERR* )&err);
  • OS_SEM_CTR cnt,
    • 如果设置成计数型信号量 此处设置成对应数字即可
    • 如果设置成二进制信号量 此处设置成0,指示事件的发生(同步)
1
2
3
4
5
6
7
OS_SEM_CTR  OSSemPend (OS_SEM   *p_sem,
OS_TICK timeout,
OS_OPT opt,
CPU_TS *p_ts,
OS_ERR *p_err)

OSSemPend(&MY_SEM,0,OS_OPT_PEND_BLOCKING,0,&err); //请求信号量
  • OS_OPT opt,
    • OS_OPT_PEND_BLOCKING —————-> 阻塞式
    • OS_OPT_PEND_NON_BLOCKING ——-> 非阻塞式
1
2
3
4
5
OS_SEM_CTR  OSSemPost (OS_SEM  *p_sem,
OS_OPT opt,
OS_ERR *p_err)

OSSemPost (&MY_SEM,OS_OPT_POST_1,&err); //发送 释放 信号量
  • OS_OPT opt,
    • OS_OPT_POST_1 —–>只使能等待信号量的最高优先级任务 (如果任务正在等待)。
    • OS_OPT_POST_ALL ——>发送到所有等待信号量的任务
    • OS_OPT_POST_NO_SCHED ———>不调用调度程序 可以与其他选项之一一起添加。

互斥信号量

互斥信号量API

OSMutexCreate()建立一个互斥信号量
OSMutexDel()删除一个互斥信号量
OSMutexPend()等待一个互斥信号量
OSMutexPendAbrot()取消等待
OSMutexPost()释放或者发布一个互斥信号量

内嵌信号量

OSTaskSemPend()等待一个任务信号量
OSTaskSemPendAbort()取消等待任务信号量
OSTaskSemPost()发布任务信号量
OSTaskSemSet()强行设置任务信号量计数

消息队列

消息队列

函数名作用
OSQCreate()创建一个消息 队列
OSQDel()删除一个消息队列
OSQFlush()清空消息队列
OSQPend()等待消息
OSQPendAbort()取消等待消息
OSQPost()向消息队列发布一则消息
1
2
3
4
5
6
7
8
9
void  OSQCreate (OS_Q        *p_q,
CPU_CHAR *p_name,
OS_MSG_QTY max_qty,
OS_ERR *p_err)

OSQCreate ((OS_Q* )&KEY_Msg, //消息队列
(CPU_CHAR* )"KEY Msg", //消息队列名称
(OS_MSG_QTY )KEYMSG_Q_NUM, //消息队列长度,这里设置为1
(OS_ERR* )&err); //错误码
1
2
3
4
5
6
7
//发送消息
OSQPost((OS_Q* )&DATA_Msg,
(void* )pbuf,
(OS_MSG_SIZE)10,
(OS_OPT )OS_OPT_POST_FIFO,
(OS_ERR* )&err);

1
2
3
4
5
6
7
//请求消息
p=OSQPend((OS_Q* )&DATA_Msg,
(OS_TICK )0,
(OS_OPT )OS_OPT_PEND_BLOCKING,
(OS_MSG_SIZE* )&size,
(CPU_TS* )0,
(OS_ERR* )&err);

任务内建消息队列

函数名作用
OSTaskQPend()等待消息
OSTaskQPendAbort()取消等待消息
OSTaskQPost()向任务发布一则消息
OSTaskQFlush()清空任务的消息队列
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//创建MSGDIS任务
OSTaskCreate((OS_TCB * )&Msgdis_TaskTCB,
(CPU_CHAR * )"Msgdis task",
(OS_TASK_PTR )msgdis_task,
(void * )0,
(OS_PRIO )MSGDIS_TASK_PRIO,
(CPU_STK * )&MSGDIS_TASK_STK[0],
(CPU_STK_SIZE)MSGDIS_STK_SIZE/10,
(CPU_STK_SIZE)MSGDIS_STK_SIZE,
(OS_MSG_QTY )TASK_Q_NUM, //任务Msgdis_task需要使用内建消息队列,消息队列长度为4
(OS_TICK )0,
(void * )0,
(OS_OPT )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
(OS_ERR * )&err);

  • 注意看 OS_MSG_QTY 正常时其设置为0 使用内建消息队列将之设置成对应的数量即可

事件标志组

​ 在UCOSIII中事件标志组为OS_FLAG_GRP,如果需要使用事件标志组的时候需要将宏OS_CFG_FLAG_EN置1,

函数名作用
OSFlagCreate()创建事件标志组
OSFlagDel()删除事件标志组
OSFlagPend()等待事件标志组
OSFlagPendAbort()取消等待事件标志
OSFlagPendGetFlagsRdy()获取使任务就绪的事件标志
OSFlagPost()向事件标志组发布标志

同时等待多个内核对象

​ 在UCOSIII中允许任务同时等待多个信号量和多个消息队列,也就是说,UCOSIII不支持同时等待多个事件标志组或互斥信号量。

​ 一个任务可以等待任意数量的信号量和消息队列,第一个信号量或消息队列的发布会导致该任务进入就绪态。

1
2
3
4
5
OS_OBJ_QTY  OSPendMulti (OS_PEND_DATA  *p_pend_data_tbl,
OS_OBJ_QTY tbl_size,
OS_TICK timeout,
OS_OPT opt,
OS_ERR *p_err)
1
2
3
4
5
6
7
8
9
OS_SEM	Test_Sem1;			//信号量1		
OS_SEM Test_Sem2; //信号量2
OS_Q Test_Q; //消息队列

OS_PEND_DATA pend_multi_tbl[CORE_OBJ_NUM];

pend_multi_tbl[0].PendObjPtr=(OS_PEND_OBJ*)&Test_Sem1;
pend_multi_tbl[1].PendObjPtr=(OS_PEND_OBJ*)&Test_Sem2;
pend_multi_tbl[2].PendObjPtr=(OS_PEND_OBJ*)&Test_Q;

内存管理


UCOS
https://www.oikiou.top/2020/2ac84091/
作者
Oikiou
发布于
2020年8月21日
许可协议