uCOS-III概览

版权声明:转载注明出处 https://blog.csdn.net/weixin_42108004/article/details/82956243

一、 任务管理

任务控制块OS_TCB中包含了任务栈顶,栈深,下个任务控制块,任务名,任务栈基地址,时间戳,时间片,信号量数目等信息。

1.任务创建:定义任务控制块--定义任务优先级--定义任务栈大小--定义任务栈数组--定义任务函数

OSTaskCreate()函数创建任务。

2. 任务删除:OSTaskDel();

3. 任务调度:OSSched();延时函数中包含任务调度,运行任务调度函数时,自动切换至当前就绪的最高优先级的任务。

3. 任务挂起:OS_TaskSuspend();

4. 任务恢复:OS_TaskResume();

二、临界区

临界区保护的代码不会被中断或任务调度打断,临界区通过关中断或者调度器加锁的方式实现,此处使用调度器加锁。

使用临界区前必须调用        CPU_SR_ALLOC();  

1. 进入临界区 : OS_CRITICAL_ENTER();

2. 退出临界区: OS_CRITICAL_EXIT();

三、时间片轮转调度

同优先级任务可以在创建时设定时间片长度,时间片执行完自动切换至另一任务,任务切换时会自动保护现场。

1. 时间片计算:

    cpu_clk_freq = BSP_CPU_ClkFreq();                           /* 获得HCLK时钟频率, cpu_clk_freq = 72MHz  */
    cnts = cpu_clk_freq / (CPU_INT32U)OSCfg_TickRate_Hz;        /* cnts = 72KHz   */
    OS_CPU_SysTickInit(cnts);                                   /* 重装载寄存器值为72K   */

系统一个时钟周期为:1/72M

重装载寄存器值递至0所用时间:72K * (1/72M) = 1ms

2. 时间片轮转调度配置:OSSchedRoundRobinCfg();

配置为默认值时,一个时间片的长度为:(1000/10) * 1ms = 100ms;

四、钩子函数

1. 主要应用空闲任务钩子函数让系统进入低功耗

OSIdleTaskHook();

五、软件定时器

定时器数据类型:OS_TMR

主要包含定时器名、回调函数名、传递给函数的数据指针、定时器值、剩余量值、开启前是否延时、重复周期等

1. 定时器创建: 

        OSTmrCreate ( (OS_TMR      *)&tmr1 ,
                  (CPU_CHAR    *)"tmr1",
                   (OS_TICK       )20,   //第一个定时器周期,20*100ms
                   (OS_TICK         )10,  //第二个周期开始后的每次定时周期,若参数为0 ,则至定时1次,否则为周期性定时
                   (OS_OPT         )OS_OPT_TMR_PERIODIC,
                   (OS_TMR_CALLBACK_PTR    )tmr1_callback,  //回调函数,每个周期定时结束,都会调用一次回调函数
                   (void      *)0, 
                   (OS_ERR    *)&err);

2. 定时器开启: 

定时器创建完成必须开启,否则不会定时,OSTmrStart();

2. 定时器停止:

OSTmrStop();

六、信号量

信号量定义: OS_SEM

1. 信号量创建

OSSemCreate (OS_SEM      *p_sem,   // 指向定义的信号量
                   CPU_CHAR    *p_name, // 信号量名称
                   OS_SEM_CTR   cnt,  //  信号量初始值,以此定义二值信号量或者计数信号量,当用于任务同步,应初始化为0,为计数信号量,当表示共享资源应该初始化为共享资源数量,共享一个存储区的数组,应该初始化为1
                   OS_ERR      *p_err   //  返回错误值

);

2. 信号量请求

OSSemPend();

(1)当为计数信号量,cnt -1 ,cnt 减到0时,阻塞任务。

(2)当为二值信号量,cnt -1 ,为0表示共享资源正被占用,信号量还未被释放。

3. 信号量释放

OS_SemPost();

(1)当为计数信号量,cnt +1 

(2)当为二值信号量, cnt +1 ,信号量可用,共享资源可用

七、优先级反转

(1) 任务 H 和任务 M 处于挂起状态,等待某一事件的发生,任务 L 正在运行。
(2) 某一时刻任务 L 想要访问共享资源,在此之前它必须先获得对应该资源的信号量。
(3) 任务 L 获得信号量并开始使用该共享资源。
(4) 由于任务 H 优先级高,它等待的事件发生后便剥夺了任务 L 的 CPU 使用权。
(5) 任务 H 开始运行。
(6) 任务 H 运行过程中也要使用任务 L 正在使用着的资源,由于该资源的信号量还被任务
L 占用着,任务 H 只能进入挂起状态,等待任务 L 释放该信号量。
(7) 任务 L 继续运行。
(8) 由于任务 M 的优先级高于任务 L,当任务 M 等待的事件发生后,任务 M 剥夺了任务 L
的 CPU 使用权。
(9) 任务 M 处理该处理的事。
(10) 任务 M 执行完毕后,将 CPU 使用权归还给任务 L。
(11) 任务 L 继续运行。
(12) 最终任务 L 完成所有的工作并释放了信号量,到此为止,由于实时内核知道有个高优
先级的任务在等待这个信号量,故内核做任务切换。
(13) 任务 H 得到该信号量并接着运行。
在这种情况下,任务 H 的优先级实际上降到了任务 L 的优先级水平。因为任务 H 要一直
等待直到任务 L 释放其占用的那个共享资源。由于任务 M 剥夺了任务 L 的 CPU 使用权,使得
任务 H 的情况更加恶化, 这样就相当于任务 M 的优先级高于任务 H,导致优先级反转。

八、互斥信号量

为了避免优先级反转的出现,使用互斥信号量

当低优先级的任务获得信号量,ucosiii会将占用信号量的低优先级任务提高到当前最高优先级,当任务结束,释放信号量可直接被高优先级的任务请求到,以此避免优先级反转为题。

定义:OS_MUTEX

1. 创建互斥信号量

OSMutexCreate();

2. 请求信号量

OSMutexPend();

3. 释放信号量

OSMutexPost();

九、消息队列

消息队列是任务与任务之间交流的媒介

注意点:中断服务程序只能使用 OSQPost()函数

1. 消息队列定义:OS_Q

struct  os_q {                                              /* Message Queue                                          */
                                                            /* ------------------ GENERIC  MEMBERS ------------------ */
    OS_OBJ_TYPE          Type;                              /* Should be set to OS_OBJ_TYPE_Q                         */
    CPU_CHAR            *NamePtr;                           /* Pointer to Message Queue Name (NUL terminated ASCII)   */
    OS_PEND_LIST         PendList;                          /* 正在等待消息队列的任务列表                 */
#if OS_CFG_DBG_EN > 0u
    OS_Q                *DbgPrevPtr;
    OS_Q                *DbgNextPtr;
    CPU_CHAR            *DbgNamePtr;
#endif
                                                            /* ------------------ SPECIFIC MEMBERS ------------------ */
    OS_MSG_Q             MsgQ;                              /* 消息列表                                       */
};

struct  os_msg_q {                                          /* OS_MSG_Q                                               */
    OS_MSG              *InPtr;                             /* 指向下一个将被插人队列的消息控制块 */
    OS_MSG              *OutPtr;                            /* 指向将被从队列中提取的控制块  */
    OS_MSG_QTY           NbrEntriesSize;                    /*队列中最大消息数     */
    OS_MSG_QTY           NbrEntries;                        /* 对列中当前消息数          */
    OS_MSG_QTY           NbrEntriesMax;                     /* 对别中消息数的峰值             */
};

消息控制块OS_MSG :

struct  os_msg {                                            /* MESSAGE CONTROL BLOCK                                  */
    OS_MSG              *NextPtr;                           /* Pointer to next message                                */
    void                *MsgPtr;                            /* Actual message                                         */
    OS_MSG_SIZE          MsgSize;                           /* Size of the message (in # bytes)                       */
    CPU_TS               MsgTS;                             /* Time stamp of when message was sent                    */
};

2. 创建消息队列

OSQCreate (OS_Q        *p_q,  // 指向定义的消息队列
                 CPU_CHAR    *p_name,
                 OS_MSG_QTY   max_qty,   //消息池中的最大消息数
                 OS_ERR      *p_err)

3. 发送消息到消息队列

OSQPost (OS_Q         *p_q,
               void         *p_void,   //指向将要被发送的消息数据(只需要是一个地址,消息内容是多大是什么不用管)
               OS_MSG_SIZE   msg_size,   //消息数据的大小(字节数)
               OS_OPT        opt,  //发送方式,当发送紧急消息时,可用LIFO模式,OS_OPT_POST_LIFO
               OS_ERR       *p_err)

4. 请求消息队列

/***********函数返回值为消息内容**********/

void  *OSQPend (OS_Q         *p_q,
                OS_TICK       timeout,
                OS_OPT        opt,  //请求不到是否阻塞任务
                OS_MSG_SIZE  *p_msg_size,   //返回消息大小
                CPU_TS       *p_ts,  //时间戳
                OS_ERR       *p_err)     

十、事件标志组

事件标志组用于一个任务与多个事件同步,有两种同步模式,多个事件中有一个发生,就进行任务同步,是“或”模式。

多个事件同时发生才进行任务同步,是“与”模式。

事件标志组定义:OS_FLAG_GRP

1. 创建事件标志组

 OSFlagCreate (OS_FLAG_GRP  *p_grp,    //指向定义的事件标志组变量
                    CPU_CHAR     *p_name,  // 事件标志组名字
                    OS_FLAGS      flags, // 事件标志组的初始值  (可以是8/16/32位)
                    OS_ERR       *p_err)  //返回错误值

2. 发送事件标志

/**********返回值为事件标志组的当前值***********/

OS_FLAGS  OSFlagPost (OS_FLAG_GRP  *p_grp,  
                      OS_FLAGS      flags,  // 需要更改的标志位
                      OS_OPT        opt,  //对flags位清0或者置1
                      OS_ERR       *p_err)

3. 请求事件标志

OS_FLAGS  OSFlagPend (OS_FLAG_GRP  *p_grp,
                      OS_FLAGS      flags,   // 需要请求的标志位
                      OS_TICK       timeout,  // 请求等待时间,为0 则一直阻塞任务等待
                      OS_OPT        opt,  

/*

*                                OS_OPT_PEND_FLAG_CLR_ALL   等待所有的标志位被清0 (与)
*                                OS_OPT_PEND_FLAG_CLR_ANY   等待任意一个标志位被清0(或)
*                                OS_OPT_PEND_FLAG_SET_ALL   等待所有的标志位被置1 (与)
*                                OS_OPT_PEND_FLAG_SET_ANY   等待任意一个标志位被置1(或)

*/
                      CPU_TS       *p_ts, //返回时间戳
                      OS_ERR       *p_err)

猜你喜欢

转载自blog.csdn.net/weixin_42108004/article/details/82956243