函数API
函数 | 功能 |
---|---|
OSTaskCreate | 创建任务 |
OSTaskDel | 删除任务 |
OSTaskSuspend | 挂起任务 |
OSTaskResume | 恢复任务 |
OS_CFG_SCHED_ROUND_ROBIN_EN变量置1 | 使能时间片轮转调度 |
OSSchedRoundRobinCfg | 放弃时间片轮转调度 |
OSTimeDlyHMSM | 延时函数(前四个参数对应 时/分/秒/毫秒) |
OSTimeGet | 换区系统节拍计数器的值 |
钩子函数(不经常用?):在UCOSIII_CONFIG/os_app_hooks.c中编写
软件定时器:UCOSIII_CORE/os_tmr.c
细碎知识点
- uCOS内核特点
- 可剥夺型
- 总是运行着就绪任务中优先级最高的那个任务
- micrium是ucos源码
- 心跳频率【1s跳200次】
#define OS_TICKS_PER_SEC 200u /* Set the number of ticks in one second */
- ucos-III的delay_us不发生任务调度,delay_ms发生任务调度
- 使用UCOS-III之前先调用OSInit(&err)初始化函数
- 任务开启用OSStart
- 只有开启了时间片轮转,才能多个任务设置同样的优先级哦
- 当任务中要使用临界区的时候,需要声明CPU_SR_ALLOC()。
- 一般任务开头需要写上一句:p_arg = p_arg;是为了防止编译器报错~
- 创建任务理论不需要加临界区保护,因为创建函数内部已经进行了临界区保护。但是加上也无妨。
- 注意:因为ucos-III的任务是while(1)死循环的形式,我们在得在合适的位置上进行调度器的任务切换,比如:延时函数…
整体知识点
-
UCOS-II体系结构
-
uCOS-III
-
任务管理
- 任务就是程序实体【操作系统管理和调度的最小单位,称之为任务】
- 任务组成:任务堆栈(上下文切换的寄存器值)、任务控制块(各个任务的属性值)、任务函数(用户编写的)
-
系统任务
- 空闲任务:必选
- 时钟节拍任务:必选
- 统计任务:可选【OS_CFG_STAT_TASK_EN】
- 定时任务:可选【OS_CFG_EN】
- 中断服务管理任务:可选【OS_CFG_ISR_POST_DEFERRED_EN】
-
任务状态
- 休眠态:存在于CPU的FLASH中,但不受RTOS管理。
- 就绪态:具备任务运行条件
- 运行态:正在运行
- 等待态:正在运行的任务需要等待一段时间或事件
- 中断服务态:因发生中断,当前任务被挂起
- 就绪表
- 优先级位映射表:OSPrioTb1[] - 记录哪个优先级下有任务就绪
- 就绪任务列表:OSRdyList[] - 记录每一个优先级下所有就绪的任务
-
任务调度
- 任务级调度器:OSSched()
- 中断级调度器:OSInitExit() 【写在外部中断中的,退出中断用】
-
任务调度点(任务调度的时间点)
-
重点关注:延时、创建/删除任务、挂起/解挂任务、调度器调度
-
任务切换
- 任务调度包括任务切换
-
任务切换种类
- 任务级切换函数:OSCtxSw()
- 中端级切换函数:OSIntCtxSw()
-
UCOS-III下的中断服务函数编写范例【参考串口中断】
OSIntEnter(); //进入中断
...
OSIntExit(); //退出中断
- 临界区保护(OS_CFG_SCHED_ROUND_ROBIN_EN)
- 关中断【全部中断都要关闭,滴答定时器也不会走了】标志位为0
- 调度器上锁【滴答定时器还会走,但是有些中断仍会打断】标志位为1
- 临界区代码
- 临界区退出方式有两种,其中OS_CRITICAL_EXIT会进行调度器任务切换
CPU_SR_ALLOC();
OS_CRITICAL_ENTER(); //进入临界区
OS_CRITICAL_EXIT(); //进入临界区
- 软件定时器
- 递减计数器,到0触发回调函数
- 使用软件定时器前还需要将:OS_CFG_TMR_EN置为1
- 时间分辨率由:OS_TMR_TASK_RATE_HZ,默认100Hz,即10ms,所以软件定时器周期必须为10ms的整数倍
- 定时器的回调函数中不能使用阻塞调用(延时、删除定时器)
- 定时器先Create、再Start
- 软件定时器模式有:单次模式、周期模式
- 停止软件定时器的时候:可以直接停止、也可以停止时最后调用一下回调函数(即使没有递减到0)
- 软件定时器的几个API函数
函数 | 功能 |
---|---|
OSTmrCreate | 创建定时器并制定运行模式 |
OSTmrDel | 删除定时器 |
OSTmrRemainGet | 获取定时器的剩余时间 |
OSTmrStart | 启动定时器 |
OSTmrStateGet | 获取当前定时器的状态 |
OSTmrStop | 停止计数器倒计时 |
- 信号量【理解成一个变量,不等于0可用】
- 上锁机制
- 一次钥匙只能给一个人用
- 信号量用于对共享资源的保护,但是现象在基本用来做任务同步
- 对共享资源的保护有三种手段:开关中断、调度器锁、信号量
- 任务同步案例:LED和KEY是两个任务,当我按下按键的时候,进行任务同步,让LED亮。
- 等待(请求)信号量:Pend
- 发送(释放)信号量:POST
- 信号量可以为
- 二进制
- 一次只能一个任务使用的资源
- 计数型(OS_SEM_CTR决定计数型的位数)
- 某些资源可同时被几个任务使用
- 二进制
- 信号量的API函数【可在UCOSIII_CORE/os_sem.c中具体查看】
函数 | 功能 |
---|---|
OSSemCreate | 建立一个信号量 |
OSSemDel | 删除一个信号量 |
OSSemPend | 请求或等待一个信号量(-1) |
OSSemPendAbrot | 取消等待 |
OSSemPost | 释放或发出一个信号量(+1) |
OSSemSet | 强制设置一个信号量的值 |
-
优先级反转【参考正点原子uCOS第16讲】
-
- 解决优先级反转问题,引入了互斥信号量
-
-
互斥信号量 API
- 互斥信号量创建不需要指定初始值
函数 | 功能 |
---|---|
OSMutexCreate | 建立一个互斥信号量 |
OSMutexDel | 删除一个互斥信号量 |
OSMutexPend | 等待一个互斥信号量 |
OSMutexPendAbrot | 取消等待 |
OSMutexPost | 释放或者发布一个互斥信号量 |
- 内嵌信号量
- 不仅能简化代码,还可以比使用独立的信号量更有效
- 相关代码在os_task.c
- 内嵌信号量的API
- 内嵌信号量,默认创建好的!
- 内嵌信号量,不需要指定信号量初始值,默认为0
- 如果想初始化,可以在创建任务的后面调用OSTaskSemSet 函数,设置初始值。
函数 | 功能 |
---|---|
OSTaskSemPend | 等待一个任务信号量 |
OSTaskSemPendAbort | 取消等待任务信号量 |
OSTaskSemPost | 发布任务信号量 |
OSTaskSemSet | 强行设置任务信号量计数 |
-
任务间通信
- 方式有两种:全局变量和发布消息。
- 但是要注意,通过全局变量进行任务间通信的时候,要注意对这个全局变量的保护。防止同时被多个任务操作
- 消息的组成部分:指向数据的指针、数据的长度、记录消息发布时刻的时间戳
- 可以使用动态内存分配的方式来分配一个内存块
- 传递一个指向全局变量、全局数据结构、全局数组或函数的指针
-
消息队列的API函数
- 消息邮箱是特殊的消息队列,大小为1的消息队列
- 1个任务请求1个消息队列,适合用任务内建消息队列
- 多个任务请求1个消息队列,适合用独立消息队列
函数 | 功能 |
---|---|
OSQCreate | 创建一个消息队列 |
OSQDel | 删除一个消息队列 |
OSQFlush | 情况消息队列 |
OSQPend | 等待消息 |
OSQPendAbort | 取消等待消息 |
OSQPost | 向消息队列发布一则消息 |
- 任务内建消息队列
-
多个任务等待同一个消息队列的应用很少见
-
每个任务都有其内建消息队列,这样用户可以不用通过外部的消息队列而直接向任务发布消息
-
使用内建消息队列需要将宏OS_CFG_TASK_Q_EN置为1
-
内建消息队列的API函数
-
函数 | 功能 |
---|---|
OSTaskPend | 等待消息 |
OSTaskPendAbort | 取消瞪大消息 |
OSTaskPost | 向任务发布一则消息 |
OSTaskFlush | 清空任务的消息队列 |