3.软件定时器使用
软件定时器启动之后是由软件定时器任务 OS_TmrTask() 统一管理。
在创建软件定时器之前必须先使能软件定时器和配置软件定时器的相关参数。
(1)在“os_cfg.h”中使能;
(2)在“os_cpu_app.h”配置相关参数
/* 1.声明TMR对象 */
OS_TMR my_tmr;
/* 2.创建软件定时器 */
OSTmrCreate((OS_TMR *)&my_tmr, // 软件定时器对象
(CPU_CHAR *)"my soft timer", // 命名软件定时器
(OS_TICK )10, // 定时器初始值,依10Hz时基计算,即为1s
(OS_TICK )10, // 定时器周期重载值,依10Hz时基计算,即为1s
(OS_OPT )OS_OPT_TMR_PERIODIC, // 周期性定时
(OS_TMR_CALLBACK_PTR )tmrCallBack, // 回调函数
(void *)"timer over!", // 传递实参给回调函数
(OS_ERR *)err); // 返回错误类
/* 3.启动软件定时器 */
OSTmrStart((OS_TMR *)&my_tmr, // 软件定时器对象
(OS_ERR *)&err); // 返回错误类型
/* 回调函数 */
void tmrCallBack(OS_TMR *p_tmr, void *p_arg)
{
// TODO 定时要执行的任务体
}
多值信号量
多值信号量是 uC/OS 操作系统的一个内核对象,主要用于标志事件的发生和共享资源管理。在“os_cfg.h” 使能多值信号量。
互斥信号量
互斥信号量是 uC/OS 操作系统的一个内核对象,与多值信号量非常相似,但它是二值的,只能是 0 或 1,所以也叫二值信号量,主要用于保护资源,防止优先级反转。
uC/OS为了解决优先级反转问题,在互斥信号量中引入了优先级提升的方法,他的基本思想是:让当前获得互斥信号量的任务的优先级短暂提升到系统可以接受的最大优先级,尽量让该任务快速的完成并释放信号量,释放之后在恢复为任务原来的优先级别。
相关函数:
OSMutexCreate(); // 创建互斥信号量
OSMutexPost(); // 函数用于释放(发布,提交)互斥信号量。
OSMutexPend(); // 函数用于申请(等待,请求)获取一个互斥信号量。
OSMutexPendAbort(); // 函数用于中止任务对一个互斥信号量的等待。
OSMutexDel(); // 函数用于删除一个互斥信号量。
消息队列
给资源赋予内容进行传递
OSQCreate(); // 创建消息队列;
OSQPost(); // 函数用于向消息队列发布一个消息;
OSQPend(); // 函数用于等待获取消息队列的消息;
OSQDel(); // 函数用于删除一个消息队列;
OSQFlush(); // 函数用于清空一个消息队列。
事件标志组
事件标志组是若干二值信号的组合,代表若干个事件是否发生,通常用于集合两个或两个以上事件的状态。
OSFlagCreate(); // 创建事件标志组
OSFlagPost(); // 置位或清0事件标志组中的标志
OSFlagPend(); // 等待事件标志组的标志位
OSFlagPendAbort(); // 中止任务对一个事件标志组的等待。
OSFlagDel(); // 删除事件标志组
等待多个内核对象
等待多个内核对象, 是指任务可以同时等待多个内核对象, 当其中有一个对象被可用时,任务就可以脱离等待。需要注意的是,这里的多个内核对象,是指多值信号量和消息队列的任意组合,一般将该组合声明为一个数组。
OSPendMulti(); // 函数用于等待多个内核对象(多值信号量或消息队列)。
任务信号量
任务信号量和任务消息队列分别与多值信号量和消息队列非常相似,不同之处是,前者仅发布给一个特定任务,而后者可以发布给多个任务。因此,前者的操作相对比较简单,而且省时。如果任务信号量和任务消息队列可以满足设计需求,那么尽量不要使用普通多值信号量和消息队列。
任务消息队列
任务消息队列跟任务信号量一样,均隶属于某一个特定任务,不需单独创建,任务在则在,只有该任务才可以接收这个任务消息队列的消息,其他任务只能给这个任务消息队列发送消息,却不能接收。任务消息队列与前面讲解的(普通)消息队列极其相似,只是任务消息队列已隶属于一个特定任务,所以它不具有等待列表,省去了等待任务插入和移除列表的动作,原理更简单,效率更高。
内存管理
要使用 uC/OS 的内存管理必须先声明和创建内存管理对象,调用 OSMemCreate () 函数可以创建一个内存管理对象。注意,内存分区一经创建便不能删除。
OSMemCreate(); // 函数用于创建内存管理对象;
OSMemGet(); // 函数用于向内存管理对象获取一个空闲内存块;
OSMemPut(); // 函数用于把内存块退还回内存管理对象(内存分区)。
/* 创建内存分区memTest */
OSMemCreate((OS_MEM *)&memTest, // 指向内存管理对象
(CPU_CHAR *)"mem test", // 命名内存管理对象
(void *)testArray, // 内存分区首地址
(OS_MEM_QTY )2, // 内存分区块数目--要求不小于2
(OS_MEM_SIZE )4, // 内存分区块大小(in bytes)--不少于一个指针的字节数(STM32是的指针的字节数是4,且为其整数倍)
(OS_ERR *)&err); // 返回错误类型
/* 获取一个内存块 */
pMemBlk = OSMemGet((OS_MEM *)&memTest,
(OS_ERR *)&err);
/* 退还一个内存块 */
OSMemPut((OS_MEM *)&memTest, // 指向内存管理对象
(void *)msgPtr, // 内存块的首地址
(OS_ERR *)&err); // 返回错误类型
任务管理
OSTaskCreate(); // 函数用于创建一个任务;
OSTaskSuspend(); // 函数用于挂起一个任务,令任务暂停运行;
OSTaskResume(); // 解除任务的挂起,如果解嵌后任务挂起前套数为 0,才可以恢复被挂起前的任务状态;
OSTaskChangePrio(); // 改变任务的优先级;
OSTaskDel(); // 删除任务;
OSSchedRoundRobinCfg(); // 函数使能时间片轮转调度和配置相关参数;
OSSchedRoundRobinYield(); // 放弃CPU;
OSTaskTimeQuantaSet(); // 调整任务的时间片;
OSTaskRegSet(); // 函数可以设置一个任务的任务寄存器的值;
OSTaskRegGet (); // 函数可以获取一个任务的任务寄存器的值。
中断管理
在 uC/OS 系统中,中断相当于一个优先级最高的任务。中断一般用于处理比较紧急的事件,而且只做简单处理,例如标记该事件,带退出中断后再做详细处理。在使用 uC/OS系统时,一般建议使用信号量、消息或事件标志组等标志中断的发生,将这些内核对象发布给处理任务,处理任务再做详细处理。
OSIntEnter(); // 标记任务进入中断,方便中断嵌套管理;
OSIntExit(); // 标记函数退出中断,方便中断嵌套管理;
CPU_IntDisMeasMaxGet(); // 获取整个程序目前的最大关中断时间;
CPU_IntDisMeasMaxCurReset(); // 复位当前最大关中断时间;
CPU_IntDisMeasMaxCurGet(); // 获取当前最大关中断时间;
Q Note:
- 原来一直不明白为啥总是要先创建一个起始任务,在起始任务中创建其他任务,然后再删掉起始任务。现在在μC/OS-III User’s Manual看到这样一句话“uC/OS-III允许用户在调用OSStart()之前创建任意个任务。然而,当用到统计任务统计CPU的使用率时,调用OSStart()之前只能创建一个任务”