【精彩推荐】RT-Thread操作系统μC/OS-III兼容层

RT-Thread社区作者:满鉴霆

1 概述

这是一个针对RT-Thread操作系统的μCOS-III操作系统兼容层,可以让基于美国Micriμm公司的μCOS-III操作系统的项目快速迁移到RT-Thread操作系统上。

1.1 本兼容层适合于:

  1. 老项目需要从μCOS-III操作系统向RT-Thread操作系统迁移

  2. 之前学习过μCOS-III操作系统,意图转向学习RT-Thread国产操作系统。本兼容层可以帮您用已有的μCOS-III编程经验和习惯快速将项目跑起来,日后再慢慢深入熟悉RT-Thread的API函数,逐步向RT-Thread过度。降低您的学习门槛和时间成本。有了本兼容层,对RT-Thread API以及编程风格的不熟悉再也不是您学习RT-Thread的阻力!

1.2 版本详细信息

组件名称版本号
RT-Thread nano3.1.3
μC/OS-III3.03.00
μC/CPU1.30.00
μC/LIB1.37.02

1.3 官网

RT-Thread:
https://www.rt-thread.org/
文档中心:

https://www.rt-thread.org/document/site/tutorial/nano/an0038-nano-introduction/

μCOS-III:https://www.micrium.com/
文档中心:

https://doc.micrium.com/display/kernel304/uC-OS-III+Documentation+Home

2 使用

2.1 Keil-MDK仿真工程

本仿真工程是基于STM32F103RB平台。

Keil工程路径:RT-Thread-wrapper-of-uCOS-III\rt_thread_3.1.3-ucosiii_3.03-wrapper\rt-thread-3.1.3\bsp\stm32f103-msh-628\Project.uvprojx

需要提前安装好RT-Thread Nano-3.1.3 Keil支持包:

https://www.rt-thread.org/download/mdk/RealThread.RT-Thread.3.1.3.pack

注意:调试串口使用的是USART2,不是USART1

2.2 迁移步骤

  1. uCOS-III_Wrapper文件夹内的所有文件都加入到你的工程中,最好保持原有文件夹的结构。相较于原版μCOS-III增加了os_rtwrap.c文件,负责对RT-Thread和μCOS-III的转换提供支持。

  2. 浏览一下μC-CPU/cpu.h文件,看一下头文件中的定义是否符合你的CPU,一般不需要改这个文件

  3. 浏览一下μCOS-III/os.h文件,看一下错误代码,这个错误代码和原版μCOS-III是有一定区别的。

    注意: 请勿随意打开注释掉的错误码枚举体成员, 如果用户使用到了这些注释掉的成员,则会在迁移时编译报错,用以提醒用户这些错误代码在兼容层已经不可用。

  4. 软件定时器:μCOS-III原版的软件定时器回调函数是两个参数,本兼容层由于RT-Thread的回调函数仅为一个参数,因此改为一个参数(详见μCOS-III/os.h)。

    μCOS-III原版软件定时器回调函数定义:

    1typedef  void  (*OS_TMR_CALLBACK_PTR)(void *p_tmr, void *p_arg);
    

    本兼容层软件定时器回调函数定义:

    1typedef  void (*OS_TMR_CALLBACK_PTR)(void *parameter);
    
  5. 配置os_cfg.h和os_cfg_app.h
    每个选项的配置说明和原版μCOS-III一致,若有不同,我已经在注释中有所解释。

    原版μCOS-III配置说明可参见:

    a)《嵌入式实时操作系统μC/OS-III》北京航空航天大学出版社 宫辉等译 邵贝贝审校

    b) Micriμm公司μCOS-III在线文档: https://doc.micrium.com/display/kernel304/uC-OS-III+Features+os_cfg.h

2.3 os_cfg.h配置文件

1#define  OS_CFG_DBG_EN  1     /* Enable (1) debug code/variables  */  

该宏定义定义是否启用兼容层调试,建议在第一次迁移时打开,因为在兼容层内部,一部分uCOS-III原版功能没有实现,如果用户用到了这部分没有实现的功能,将会通过调试的方式输出,予以提示。用户务必对业务逻辑予以修改。

1#define  OS_CFG_TMR_TASK_RATE_HZ 100u /* Rate for timers (100 Hz Typ.) */

在原版μCOS-III中,该宏定义定义了软件定时器的时基信号,这与RT-Thread的软件定时器有本质的不同,在RT-Thread中,软件定时器的时基信号就等于OS ticks。因此为了能够将μCOS-III软件定时器时间参数转为RT-Thread软件定时器的时间参数,需要用到该宏定义。请使该宏定义与原工程使用μCOS-III时的该宏定义参数一致。

2.4 os_cfg_app.h配置文件

该文件仅保留了OS tick频率的配置、定时器任务以及统计任务的配置。其他配置项本兼容层用不到(例如中断任务),予以删除。

2.5 运行

 1#include <os.h> /*头文件保持和原版μCOS-III相同*/
 2
 3int main(void) /*RT-Thread main线程*/
 4{
 5    OS_ERR err;
 6
 7    OSInit(&err);                                   /*uCOS-III操作系统初始化*/
 8
 9    OSStart(&err);                                  /*开始运行uCOS-III操作系统*/
10
11#if OS_CFG_APP_HOOKS_EN > 0u
12    App_OS_SetAllHooks();                           /*设置钩子函数*/
13#endif  
14
15#if OS_CFG_STAT_TASK_EN > 0u
16    OSStatTaskCPUUsageInit(&err);                   /*统计任务*/    
17    OSStatReset(&err);                              /*复位统计数据*/    
18#endif      
19
20}

2.6 注意

  1. 由于μCOS-III支持8、16、32位CPU,而RT-Thread支持32、64位CPU,因此本兼容层仅能对基于32位CPU的已有工程进行兼容

  2. μCOS-III的任务堆栈大小单位是sizeof(CPU_STK),而RT-Thread的线程堆栈大小单位是Byte,虽然在兼容层已经做了转换,但是在填写时一定要注意,所有涉及到μCOS-III的API、宏定义全部是按照μCOS-III的标准,即堆栈大小为sizeof(CPU_STK),切勿混搭!这种错误极其隐晦,一定要注意!下面是混搭的错误示例

     1ALIGN(RT_ALIGN_SIZE)
     2static rt_uint8_t thread2_stack[1024];//错误:混搭RT-Thread的数据类型定义线程堆栈
     3
     4OSTaskCreate(&thread2,
     5             (CPU_CHAR*)"thread2",
     6             thread2_entry,    
     7             RT_NULL,
     8             THREAD_PRIORITY,
     9             thread2_stack,
    10             sizeof(thread2_stack)/10,//任务堆栈深度限位(错误:这个参数的单位是sizeof(CPU_STK))
    11             sizeof(thread2_stack),//任务堆栈大小(错误:这个参数的单位是sizeof(CPU_STK))
    12             0,
    13             THREAD_TIMESLICE,
    14             0,
    15             OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
    16             &err);
    

    下面是正确写法

     1#define THREAD_STACK_SIZE       256 //正确,要通过宏定义单独定义堆栈大小,单位为sizeof(CPU_STK)
     2ALIGN(RT_ALIGN_SIZE)
     3    static CPU_STK thread2_stack[THREAD_STACK_SIZE];//正确,使用uCOS-III自己的数据类型定义任务堆栈
     4
     5OSTaskCreate(&thread2,
     6             (CPU_CHAR*)"thread2",
     7             thread2_entry,
     8             RT_NULL,
     9             THREAD_PRIORITY,
    10             thread2_stack,
    11             THREAD_STACK_SIZE/10,//任务堆栈深度限位(正确)
    12             THREAD_STACK_SIZE,//任务堆栈大小(正确)
    13             0,
    14             THREAD_TIMESLICE,
    15             0,
    16             OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
    17             &err);
    
  3. 切勿将RT-Thread和μCOS-III的API混搭使用。

    例如RTT中的rt_thread_suspend / rt_thread_resume仅支持一次挂起/解挂;而μCOS-III的OSTaskSuspend / OSTaskResume是支持嵌套挂起/解挂的,为此需要继承struct rt_thread结构体并在其基础上增加成员.SuspendCtr变量实现该功能。若采用rt_thread_init初始化线程,该函数并不会管理μCOS-III兼容层的成员变量,.SuspendCtr也不会创建和初始化,若此时调用OSTaskSuspend / OSTaskResume函数试图指向.SuspendCtr成员变量,将会访问非法内存地址(因为rt_thread_init初始化的线程.SuspendCtr成员变量根本不存在)!

  4. 兼容层取消了原版μCOS-III中的时间戳功能

    在μCOS-III中,时间戳主要用于测量中断关闭时间,以及任务单次执行时间以及最大时间等涉及到精度较高的时长测量。该特性在μCOS-II以及RT-Thread中均没有,因此不予实现。

  5. μCOS-III原版定时器回调函数是在定时器线程中调用的,而非在中断中调用,因此要使用μCOS-III兼容层的软件定时器,需要将rtconfig.h中的宏定义RT_USING_TIMER_SOFT置1。

3 接口

3.1 没有实现兼容的API(仅2个)

虽然RT-Thread没有任务内建消息队列、任务内建信号量、任务内建寄存器机制,但是本兼容层均已实现,可以正常兼容。但由于RT-Thread没有提供相关接口,以下μCOS-III API无法兼容

1void  OSTaskChangePrio (OS_TCB *p_tcb, OS_PRIO prio_new, OS_ERR *p_err);
2void  OSTaskTimeQuantaSet (OS_TCB *p_tcb, OS_TICK time_quanta, OS_ERR *p_err);

3.2 钩子函数

μCOS-III的钩子函数仅对μCOS-III兼容层负责。 即如果你注册了OSTaskDelHook函数,他仅会在调用OSTaskDel函数时被调用,不会在调用rt_thread_detach函数时被调用(这个由RTT的钩子函数负责)。这样做是为了层次分明,防止μCOS-III兼容层插手RT-Thread内部事务。

μCOS-III的钩子函数在两个文件中实现:os_cpu_c.c和os_app_hooks.c。按照μCOS-III的思想,os_cpu_c.c提供原始的钩子函数(即这些钩子函数被相应的函数直接调用),该文件以及其内部的钩子函数是移植工程师编写的内容,应用工程师不应该操作这个文件的内容,os_cpu_c.c文件的钩子函数提供相应的函数指针供os_app_hooks.c文件内的钩子函数注册和使用,这个文件内的钩子函数应用工程师是可以操作的。换句话说,我们有什么需要在钩子函数中调用的函数,应该放在os_app_hooks.c文件中。

以下原版μCOS-III钩子函数将予以取消,由RT-Thread接管相关钩子函数接管:

1void          OSTaskReturnHook          (OS_TCB *p_tcb);
2void          OSTaskSwHook              (void);
3void          OSTimeTickHook            (void);

同时,上述钩子函数对应的应用级钩子函数也被取消:

1void  App_OS_TaskReturnHook (OS_TCB  *p_tcb);
2void  App_OS_InitHook (void);/*按照手册要求OS初始化的钩子函数不应该出现在应用层,在3.03版本中出现应该是失误,在3.08版本中已经将该应用级钩子函数取消*/
3void  App_OS_TaskSwHook (void);
4void  App_OS_TimeTickHook (void);

3.3 统计任务(OS_StatTask()、os_stat.c)

在μCOS-III中,统计任务是一个系统任务,通过OS_CFG_STAT_TASK_EN宏决定是否开启,可以在系统运行时做一些统计工作。例如统计总的CPU使用率(0.00% - 100.00%)、各任务的CPU使用率(0.00% - 100.00%)以及各任务的堆栈使用量。从内核版本V3.03.00起,CPU的利用率用一个0-10000之间的整数表示(对应0.00% - 100.00%)。

但是RT-Thread并没有统计任务,因此需要创建一个任务来兼容原版μCOS-III的统计任务,完成上述功能。该统计任务会在兼容层初始化时自动创建,用户无需干预。用户仅需调用OSStatTaskCPUUsage全局变量即可获取当前的CPU使用率,CPU使用率的计算策略和原版μCOS-III完全一致。

目前统计任务实现的功能:

  1. 计算全局CPU使用率

  2. 计算每个任务的任务堆栈使用情况(当 OS_CFG_DBG_EN 和 OS_CFG_STAT_TASK_STK_CHK_EN 为1)

注意:一旦开启统计任务,则该优先级强烈建议不要被其他任务使用,统计任务的优先级总是为OS_CFG_PRIO_MAX-2u

特别感谢:感谢armink大神在2018年7月14日在idle.c文件中增加了hook list功能,使RT-Thread空闲任务回调函数可以注册最多RT_IDEL_HOOK_LIST_SIZE个,而非只能注册一个。若没有该功能,本兼容层的空闲任务将无法实现。

3.4 全局变量

目前,本兼容层可以使用以下μCOS-III原版全局变量(位于os.h)。这些全局变量的具体含义请参见2.2节中所列举出的参考资料。

 1#define          OSSchedLockNestingCtr      rt_critical_level()         /* Lock nesting level                         */
 2#define          OSIntNestingCtr            rt_interrupt_get_nest()     /* Interrupt nesting level                    */
 3#define          OSTCBCurPtr                ((OS_TCB*)rt_thread_self()) /* Pointer to currently running TCB           */
 4                                                                        /* PRIORITIES ------------------------------- */
 5#define          OSPrioCur                  rt_current_priority         /* Priority of current task                   */
 6#define          OSPrioTbl                  rt_thread_priority_table
 7
 8#if OS_CFG_APP_HOOKS_EN > 0u
 9OS_EXT           OS_APP_HOOK_TCB            OS_AppTaskCreateHookPtr;    /* Application hooks                          */
10OS_EXT           OS_APP_HOOK_TCB            OS_AppTaskDelHookPtr;
11OS_EXT           OS_APP_HOOK_VOID           OS_AppIdleTaskHookPtr;
12OS_EXT           OS_APP_HOOK_VOID           OS_AppStatTaskHookPtr;
13#endif
14
15OS_EXT            OS_STATE                  OSRunning;                  /* Flag indicating that kernel is running     */
16
17#ifdef OS_SAFETY_CRITICAL_IEC61508
18OS_EXT            CPU_BOOLEAN               OSSafetyCriticalStartFlag;  /* Flag indicating that all init. done        */
19#endif
20
21#if OS_CFG_MEM_EN > 0u
22#if OS_CFG_DBG_EN > 0u
23OS_EXT            OS_MEM                   *OSMemDbgListPtr;
24#endif
25OS_EXT            OS_OBJ_QTY                OSMemQty;                   /* Number of memory partitions created        */
26#endif
27                                                                        /* TASKS ------------------------------------ */
28#if OS_CFG_DBG_EN > 0u
29OS_EXT            OS_TCB                   *OSTaskDbgListPtr;
30#endif
31OS_EXT            OS_OBJ_QTY                OSTaskQty;                  /* Number of tasks created                    */
32#if OS_CFG_TASK_REG_TBL_SIZE > 0u
33OS_EXT            OS_REG_ID                 OSTaskRegNextAvailID;       /* Next available Task Register ID            */
34#endif
35#if OS_CFG_SCHED_ROUND_ROBIN_EN > 0u
36OS_EXT            OS_TICK                   OSSchedRoundRobinDfltTimeQuanta;
37OS_EXT            CPU_BOOLEAN               OSSchedRoundRobinEn;        /* Enable/Disable round-robin scheduling      */
38#endif
39                                                                        /* IDLE TASK -------------------------------- */
40OS_EXT            OS_IDLE_CTR               OSIdleTaskCtr;              
41
42#if OS_CFG_STAT_TASK_EN > 0u                                            /* STATISTICS ------------------------------- */
43OS_EXT            CPU_BOOLEAN               OSStatResetFlag;            /* Force the reset of the computed statistics */
44OS_EXT            OS_CPU_USAGE              OSStatTaskCPUUsage;         /* CPU Usage in %                             */
45OS_EXT            OS_CPU_USAGE              OSStatTaskCPUUsageMax;      /* CPU Usage in % (Peak)                      */
46OS_EXT            OS_TICK                   OSStatTaskCtr;
47OS_EXT            OS_TICK                   OSStatTaskCtrMax;
48OS_EXT            OS_TICK                   OSStatTaskCtrRun;
49OS_EXT            CPU_BOOLEAN               OSStatTaskRdy;
50OS_EXT            OS_TCB                    OSStatTaskTCB;
51#endif

4 联系方式&致谢

感谢RT-Thread工程师Willian Chan的技术支持:

https://github.com/willianchanlovegithub

感谢RT-Thread工程师yangjie的技术支持:

https://github.com/yangjie11

维护:Meco Man

联系方式:jiantingman@foxmail.com

主页:https://github.com/mysterywolf/RT-Thread-wrapper-of-uCOS-III

【DIY活动】一起来做一个基于RT-Thread Nano的Mini示波器吧!

你可以添加微信17775982065为好友,注明:公司+姓名,拉进 RT-Thread 官方微信交流群!

RT-Thread


让物联网终端的开发变得简单、快速,芯片的价值得到最大化发挥。Apache2.0协议,可免费在商业产品中使用,不需要公布源码,无潜在商业风险。

长按二维码,关注我们

转一转

赞一赞

看一看

???? 点击阅读原文进入RT-Thread新版社区

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值