μC/OS - III是什么?
它是一个可裁减、可固化、可剥夺型的实时内核,管理任务的数目不受限。可提供现代实时内核所能提供的所有服务,如资源管理、任务间同步、任务间通讯等,在如,在系统运行时做性能测试,向任务直接发信号量或消息,以及同时等待多个内核对象等。
实时系统:硬实时和软实时。
包括一个死循环和若干中断服务程序:应用程序是一个无限循环,循环中调用相应的函数完成相应的操作(后台),中断服务程序用于处理系统的异步事件(前台)。前台也成中断级,后台是任务级。
实时内核用于管理微处理器、微控制器或数字信号处理器的时间及硬件资源的软件代码。
包含多任务内核,协议栈、文件系统、GUI等。大多数组件可独立运行。
μC/OS - III可裁减、可固化、可剥夺型多任务内核,没有任务数目限制。
μC/OS - III提供的服务函数可以管理信号量、消息队列、互斥型信号量等。
#include
#include // 板级支持包,提供宏定义 BSP_Init()
#include
static OS_TCB AppTaskStartTCB; // 任务控制块 OS_TCB
static CPU_STK AppTaskStartStk[APP_TASK_START_STK_SIZE]; // 任务栈,任务不会退出,所以栈也需要一直存在
static void AppTaskStart(void * p_arg); // 拟创建任务的函数原型声明
eg:
void main(void)
{
OS_ERR err;
BSP_IntDisALL(); // 系统启动期间关闭所有中断
OSInit(&err); // 初始化μC/OS - III的内部变量和数据结构,并创建系统任务
// 空闲任务(OS_IdelTask(),在其他任务都不就绪时运行)和
// 时钟节拍任务(负责时间管理)
// 可能,统计任务OS_StatTask(), 定时任务OS_TmrTask(),
// 中断处理队列管理任务OS_IntQTask()
// 调用该函数以创建一个任务
OSTaskCreate((OS_TCB*) &AppTaskStartTCB, // 任务控制块
(CPU_CHAE*) "App Task Name", // 任务名
(OS_TASK_PTR) AppTaskStart, // 任务的函数
(void *) 0, // 要传入 “任务的函数”的参数
(OS_PRIO) 任务优先级 高[1, OS_CFG_PRIO_MAX-2]底,
(CPU_STK *) &AppTaskStartStk[0], // 该任务的栈空间基地址
(CPU_STK_SIZE)APP_TASK_START_STK_SIZE/10, //当栈的剩馀空间小于10%,警报
(CPU_STK_SIZE)APP_TASK_START_STK_SIZE, //该任务的栈大小,该数值 乘 sizeof(CPU_STK) 得到栈的字节数
(OS_MSG_QTY)0,
(OS_TICK)0,
(void 8)0,
(OS_OPT)(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
(OS_ERR*) &err );
OSStart(&err); // 这一步是干啥的?
}
#include
#include
#include
static OS_TCB AppTaskStartTCB; //每个任务一个TCB
static OS_TCB AppTask1_TCB;
static OS_TCB AppTask2_TCB;
static OS_MUTEX AppMutex; // mutex是一个内核对象(一种数据结构)
static OS_Q AppQ; // 消息队列,InterruptServerR或任务通过消息队列给其他任务发送消息
static CPU_STK AppTaskStartStk[APP_TASK_START_STK_SIZE];
static CPU_STK AppTask1_Stk[128]; // 每个任务一个栈空间
static CPU_STK AppTask2_Stk[128];
// 任务的原型函数
static void AppTaskStart(void* p_arg);
static void AppTask1 (void* p_arg);
static void AppTask2 (void* p_arg);
int main()
{
OS_ERR err;
BSP_IntDisALL();
OSInit(&err);
// check err
OSMutexCreate(...);
// check err
OSQCreate(...);
...
OSTaskCreate(. &AppTaskStart ..);
OSStart(&err);
}
static void AppTaskStart(void* p_arg)
{
p_arg = p_arg;
BSP_Init();
CPU_Init();
BSP_CfgTick();
OSTaskCreate( ... &AppTask1 ... ); // 若task1的优先级比AppTaskStart高,则会立即执行它
OSTaskCreate( ... &AppTask2 ... );
while(1){
BSP_LET_Toggle(0);
OSTimeDlyHMSM(...);
}
}
static void AppTask1 (void* p_arg)
{
OS_ERR err;
CPU_TS ts;
p_arg = p_arg;
while(1) {
OSTimeDly(...); // 等待一个时钟节拍
OSQPost(..&AppQ.); //通过消息队列AppQ发送一条消息给另一个任务
OSMutexPend(..&AppMutex.); //获取
/* Access shared resource */
OSMutexPost(..&AppMutex.); //释放
}
}
static void AppTask2 (void* p_arg)
{
OS_ERR err;
void * p_msg;
OS_MSG_SIZE msg_size;
CPU_TS ts;
CPU_TS ts_delta;
p_arg = p_arg;
while(1){
p_msg = OSQPend(...&AppQ..,ts在这里更新.); // 获取消息队列的消息
ts_delta = OS_TS_GET() - ts;
/* Process message received */
}
}
临界段代码critical sections,也叫临界区critical region,是指那些必须完整连续运行,不可被打断的代码段。中断处理程序和任务都会访问的临界段代码,需要用关中断的方法加以保护;仅由任务访问的临界段代码,可以通过给调度器上锁的方法来保护。
当μC/OS - III内部定义的宏OS_CFG_ISR_POST_DEFERRED_EN为0时,进入临界段代码前关中断,退出后中重新打开中断。
新时代的代码中因尽量避免使用宏
#define OS_CRITICAL_ENTER() { CPU_CRITICAL_ENTER(); }
#define OS_CRITICAL_EXIT() { CPU_CRITICAL_EXIT(); }
#define OS_CRITICAL_EXIT_NO_SCHED() { CPU_CRITICAL_EXIT(); }
以下是?内敛函数的原型???
#define OS_CRITICAL_ENTER() { \
CPU_CRITICAL_ENTER(); \
OSSchedLockNestingCtr++; \
CPU_CRITIAL_EXIT(); \
}
μC/OS - III通过关中断(在os_cfg.h中将OS_CFG_ISR_POST_DEFERRED_EN设置为0)或给调度器上锁(在os_cfg.h中将OS_CFG_ISR_POST_DEFERRED_EN设置为1)的方法来保护critical sections。
应用程序不可以调用以下函数:
当cpu_cfg.h中的CPU_CFG_INT_DIS_MEAS_EN设置为1时,μC/OS - III能测量最长关中断时间,包括总的关中断时间和每个任务的关中断时间。
当os_cfg.h中的OS_CFG_SCHED_LOCK_TIME_MEAS_EN设为1时,μC/OS - III能测得最长的调度器锁定时间。
每个任务相当于一个线程。
一个任务(也称作一个线程)就是一个简单的程序。多任务管理就是在多个任务间电镀和切换CPU使用权的过程。多任务管理实现并发。
任务与C函数很像。
// 任务(线程)的创建和销毁会有一定的开销
void MyTask(void* p_arg)
{
....
OSTaskDel( (OS_TCB*)0, &err );
}
在无限循环类型的任务中必须调用某个μC/OS - III服务函数,使该任务进入等待某个事件的状态。确保灭个任务都需要等待某个事件的出现是非常重要的,否则该任务就成为一个真正的无限循环,从而导致其他优先级更低的任务无法得到执行。
任务所等待的事件可能是一段延时的结束(当调用OSTimeDly()或OSTimeDlyHMSMs()时)。如,每过100ms扫描一次键盘,然后缓存下都有哪些键按下了。接收网络数据包,OS???Pend()函数(pend与wait同义)。
void MyTask(void *p_arg)
{
/* local var
* Do something with "p_arg"
* Task initialization
* while(DEF_ON){
* must call one of the following services
* OSFlagPend()
* OSMutexPend()
* OSPendMulti()
* OSQPend()
* OSSemPend()
* OSTimeDly()
* OSTimeDlyHMSM()
* OSTaskQPend()
* OSTaskSemPend()
* OSTaskSumpend()
* OSTaskDel()
*
* task body ... do work!
* }
*/
}
每个任务都有TCB,stack,优先级,和其他一些参数。OSTaskCreate()函数对任务TCB和堆栈初始化。
静态栈空间声明:
在程序运行之前静态的分配栈空间:在函数体外
static CPU_STK MyTaskStk[???];
or
CPU_STK MyTaskStk[???];
函数组 | 函数 |
---|---|
通用 | OSTaskCreate() |
通用 | OSTaskDel() |
通用 | OSTaskChangePrio() |
通用 | OSTaskRegSet() |
给任务发信号量 | |
给任务发信息 |
每个任务可以处于8种状态中的任意一种,此状态保存在TCB的一个变量中。
任务控制块TCB
是内核使用的一种数据结构,用来维护任务相关的信息。
OS_IdleTask() 必须
μC/OS - III必须创建的第一个任务。空闲任务优先级为 OS_CFG_PRIO_MAX-1
OS_TickTask() 必须
时钟节拍任务。RTOS需要一个周期性的时钟源,称为时钟节拍或系统节拍,用以跟踪任务延时和任务等待超时。 优先级比最高任务优先级略底即可。
OS_StatTask()
统计任务
OS_TmrTask()
OS_IntQTask()