μC/OS - III

系列文章目录


文章目录

  • 系列文章目录
  • 前言
  • 1. 概述
    • 前后台系统
    • 实时内核
    • RTOS(实施操作系统)
  • 3. μC/OS - III
    • 单任务应用程序
    • 有内核对象(信号量、消息队列等)参与的多任务应用程序
  • 4. 临界段代码
    • 关中断
    • 给调度器上锁
    • μC/OS - III的某些功能会导致临界段代码长度增加
    • 小结
  • 5. 任务管理
    • 任务优先级的分配
    • 栈空间大小确认
    • 任务栈溢出检测
    • 任务管理函数
    • 任务管理的内部原理
    • 系统内部任务


前言

μC/OS - III是什么?

它是一个可裁减、可固化、可剥夺型的实时内核,管理任务的数目不受限。可提供现代实时内核所能提供的所有服务,如资源管理、任务间同步、任务间通讯等,在如,在系统运行时做性能测试,向任务直接发信号量或消息,以及同时等待多个内核对象等。


1. 概述

实时系统:硬实时和软实时。

前后台系统

包括一个死循环和若干中断服务程序:应用程序是一个无限循环,循环中调用相应的函数完成相应的操作(后台),中断服务程序用于处理系统的异步事件(前台)。前台也成中断级,后台是任务级。

实时内核

实时内核用于管理微处理器、微控制器或数字信号处理器的时间及硬件资源的软件代码。
μC/OS - III_第1张图片

RTOS(实施操作系统)

包含多任务内核,协议栈、文件系统、GUI等。大多数组件可独立运行。
μC/OS - III可裁减、可固化、可剥夺型多任务内核,没有任务数目限制。

3. μ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 */
    }
}

4. 临界段代码

临界段代码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的某些功能会导致临界段代码长度增加

μC/OS - III_第2张图片

小结

   μ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。

应用程序不可以调用以下函数:

  • OS_CRITICAL_ENTER();
  • OS_CRITICAL_EXIT();
  • OS_CRITICAL_EXIT_NO_SCHED();

   当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能测得最长的调度器锁定时间。


每个任务相当于一个线程。

5. 任务管理

一个任务(也称作一个线程)就是一个简单的程序。多任务管理就是在多个任务间电镀和切换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和堆栈初始化。
μC/OS - III_第3张图片

OSTaskCreate()函数对任务TCB和堆栈的初始化

μC/OS - III_第4张图片

任务相关资源

静态栈空间声明:

在程序运行之前静态的分配栈空间:在函数体外
static CPU_STK MyTaskStk[???];
or
CPU_STK MyTaskStk[???];

任务优先级的分配

栈空间大小确认

任务栈溢出检测

  1. 使用存储管理单元或存储保护单元
  2. 使用具有堆栈溢出检测功能的CPU
    μC/OS - III_第5张图片
  3. 基于软件的堆栈溢出检测
  4. 计算空闲堆栈空间的数量

任务管理函数

函数组 函数
通用 OSTaskCreate()
通用 OSTaskDel()
通用 OSTaskChangePrio()
通用 OSTaskRegSet()
给任务发信号量
给任务发信息

任务管理的内部原理

μC/OS - III_第6张图片

从用户的角度看,任务的5种基本状态

μC/OS - III_第7张图片

μC/OS - III的内部状态机

每个任务可以处于8种状态中的任意一种,此状态保存在TCB的一个变量中。


任务控制块TCB
是内核使用的一种数据结构,用来维护任务相关的信息。

系统内部任务

  • OS_IdleTask() 必须
      μC/OS - III必须创建的第一个任务。空闲任务优先级为 OS_CFG_PRIO_MAX-1

  • OS_TickTask() 必须
      时钟节拍任务。RTOS需要一个周期性的时钟源,称为时钟节拍或系统节拍,用以跟踪任务延时和任务等待超时。 优先级比最高任务优先级略底即可。
    μC/OS - III_第8张图片

任务与时钟节拍列表
  • OS_StatTask()
     统计任务

  • OS_TmrTask()

  • OS_IntQTask()

你可能感兴趣的:(其它,单片机,RTOS)