2. 移植uCOS III到i.MX RT

本章开始,先新建一个基于野火i.MX RT全系列(包含M7)开发板的的uCOS III的工程模板,让uCOS III先跑起来。以后所有的uCOS III相关的例程我们都在此模板上修改和添加代码,不用再反反复复地新建。在本书配套的例程中,每一章的例程对野火I.MX RT的每一个板子都会有一个对应的例程,但是区别都很小,如果有区别的地方我会在教程里面详细指出,如果没有特别备注那么都是一样的。

2.1. 获取i.MX RT的裸机工程模板

I.MX RT的裸机工程模板我们直接使用野火i.MX RT开发板配套的固件库例程即可。这里我们选取比较简单的例程—“GPIO输出—使用固件库点亮LED”作为裸机工程模板。 该裸机工程模板均可以在对应板子的书籍配套例程的目录下获取到,下面以野火RT1052PRO板子的光盘目录为例,具体见 图16-1

图片没有找到

2.2. 下载uCOS III源码

在移植之前,我们首先要获取到uCOS III的官方的源码包,首先,打开Micrium 公司官方网站(http://micrium.com/),打开网站链接之后,我们点击“Downloads”选项卡进入下载页面,在“Brouse by MCU Manufacturer”栏目展开“STMicroelectronics”,单击“Viewall STMicroelectronics”,具体见 图16-2图16-3

图片没有找到 图片没有找到

uCOS-III是一个操作系统,其实也可以理解成一个软件库,它可以移植到多种硬件平台,如M3、M4还有M7内核的i.MX RT,或者ARM9等等其他芯片。核心代码肯定是一致的,但是针对不同的处理器肯定要不同的实现部分。这里选择与我们开发板最为接近的版本(NXPi.MX RT series),因为我们的野火i.MX RT系列开发板属于是i.MX RT series系列的,而uCOS-III的这个官方代码就满足我们的需求,目的也在于少花费工夫,要知道,若要从0开始移植uCOS-III到目标硬件平台,需要极大的精力和软件水平。

在“ Projects”栏目中只有一个基于 IAR(EWARM)V8.x 平台在 cortex-M7 内核 MCU 评估板上测试的 uC/OS-III 源码,单击即可。我们选择“MIMXRT150-EVK”这个项目的代码,点击后进入下载即可,不过uCOS官网下载这些源码是需要注册账号的, 而我们野火已经将这些源码下载了,在配套源码中,这样子就免去下载这一步了,直接拿来使用即可具体见 图16-4图16-5图16-6

图片没有找到 图片没有找到 图片没有找到

2.3. uCOS III源码文件介绍

我们从uCOS III源码下面的文件夹夹中看到,里面的文件夹不多,只有4个,分别是EvalBoards、uC-CPU、uC-LIB、uCOS-III,下面我们就来介绍一下这几个文件夹的作用。

2.3.1. MIMXRT1050-EV

MIMXRT1050-EV文件夹里面包含评估板相关文件,在移植时我们添加部分文件,将图16-7的源码复制添加到我们的工程目的新建cfg目录下,具体见 图16-7_,具体见 图16-8。 .. image:: media/section14/sectio007.png

align

center

name

图16-7

alt

图片没有找到

图片没有找到

将“\MIMXRT1050-EVKNXPBSPInterrupts”和“MIMXRT1050-EVKNXPBSP\ MIMXRT1050-EVK”路径下的文件添加到我们工程中的新建目录BSP文件夹下,具体见 图16-9图16-10

图片没有找到 图片没有找到

2.3.2. uC-CPU

这是和CPU紧密相关的文件,里面的一些文件很重要,都是我们需要使用的。在ARM-Cortex-M4文件夹下,存在cpu_c.c 一些对不同编译器移植相关的文件,目前只有IAR,里面有一些很重要的文件,但是目前我们使用的开发环境是MDK(keil),IAR与keil这部分文件是不同的,但是相同的文件可以复制同为M7内核的文件即可。下面具体来介绍一下里面的文件,具体见 图16-11

图片没有找到

2.3.2.1. cpu_c.h文件

包含了一些数据类型的定义,让uCOSIII与CPU架构和编译器的字宽无关。同时还指定了CPU使用的是大端模式还是小端模式,还包括一些与CPU架构相关的函数的声明。

这两个文件主要是CPU 底层相关的一些CPU 函数,cpu_c.c 文件中放的是C 函数,包含了一些CPU架构相关的代码,为什么要用C语言实现呢?uCOS是为了移植方便而采用C语言编写;而 cpu_a.asm 存放的是汇编代码,有一些代码只能用汇编实现,包含一些用来开关中断,前导零指令等。

2.3.2.2. cpu_core.c

cpu_core.c文件包含了适用于所有的CPU架构的C代码,也就是常说的通用代码。是一个很重要的文件。主要包含的函数是CPU 名字的命名,时间戳的计算等等,跟CPU底层的移植没有太大的关系,主要保留的是 CPU 前导零的 C 语言计算函数以及一些其他的函数,因为前导零指令是依靠硬件实现的,这里采用C语言方式实现,以防止某些CPU不支持前导零指令

2.3.2.3. cpu_core.h

主要是对 cpu_core.c 文件里面一些函数的说明,以及一些时间戳相关等待定义。

2.3.2.4. cpu_def.h

包含CPU相关的一些宏定义,常量,利用#define进行定义的相关信息。

2.3.3. uC-LIB

Micrium公司提供的官方库,诸如字符串操作、内存操作等接口,可用可不用。一般能用于代替标准库中的一些函数,使得在嵌入式中应用更加方便安全。

2.3.4. uCOS-III

这是关键目录,我们下来着重分析的文件位于此目录下。

首先先看看uCOS-IIIPortsARM-Cortex-MARMv7-MIAR目录下的文件,具体见 图16-12

图片没有找到

uCOS是软件,我们的开发版是硬件,软硬件必须有桥梁来连接,这些与处理器架构相关的代码,可以称之为RTOS硬件接口层,它们位于uCOS-IIIPorts文件夹下,这些文件不需要我们去修改,也不需要我们去理会,都是官方给我们写好的,直接使用即可。

2.3.4.1. os_cpu.h

定义数据类型、处理器相关代码、声明函数原型。

2.3.4.2. oc_cpu_a.asm

与处理器相关的汇编代码,主要是与任务切换相关。

2.3.4.3. os_cpu_c.c

定义用户钩子函数,提供扩充软件功能的的接口。

打开Source文件,这个是uCOS的源码文件,我们可以看到这些就是uCOS核心文件,是非常重要的,我们在移植的时候必须将这里面的文件添加到我们的工程中去,具体见 图16-13

图片没有找到

下面介绍一下每个文件的功能作用,具体见

../_images/biao1.png

至此,关于uCOS III源码的文件就简单介绍完成,下面我们需要将其拷贝到我们的工程中,将图16-14中的几个文件夹拷贝到工程中的User文件夹下,然后进行移植,具体见 图16-14

图片没有找到

2.4. 移植到i.MX RT工程

在前一章节中,我们看到了uCOS III源码中那么多文件,一开始学我们根本看不过来那么多文件,我们需要提取源码中的最简洁的部分代码,方便同学们学习,更何况我们学习的只是uCOS III的实时内核中的知识,因为这才是uCOS III的核心,那些demo都是基于此移植而来的,上一章节我们只是将uCOS III的源码放到了本地工程目录下,还没有添加到开发环境里面的组文件夹里面,所以uCOS III也就没有移植到我们的工程中去,现在开始讲uCOS III的源码添加到工程中。

2.4.1. 在工程中添加文件分组

我们需要先在工程中创建一些分组,方便我们分模块管理uCOS III中的文件,就按照uCOS III官方的命名方式创建我们的文件分组即可,具体见 图16-15

图片没有找到

2.4.2. 添加文件到对应分组

向“user”分组添加“uCOS-IIIcfg”目录下的所有文件,具体见 图16-16

图片没有找到

向“ BSP”分组添加“ \uCOS-IIIBSP”文件夹下的所有文件,使用工程自带的即可具体见 图16-17

图片没有找到

向“ uC/CPU”分组添加“uCOS-IIIuC-CPU”文件夹下的所有文件和“ \uCOS-IIIuC-CPUARM-Cortex-M4IAR”文件夹下的所有文件,具体见 图16-18

图片没有找到

向“uC/LIB”分组添加“uCOS-IIIuC-LIB”文件夹下的所有文件和“uCOS-IIIuC-LIBPortsARM-Cortex-M4IAR”文件夹下的所有文件,具体见 图16-19

图片没有找到

向“ uC/OS-III Source”分组添加“ \uCOS-IIIuCOS-IIISource”文件夹下的所有文件,具体见 图16-20

图片没有找到

向“uC/OS-III Port”分组添加“uCOS-IIIuCOS-IIIPortsARM-Cortex-MARMv7-MIAR”文件夹下的所有文件,具体见 图16-21

图片没有找到

至此,我们的源码文件就添加到工程中了,当然此时仅仅是添加而已,并不是移植成功了,如果你编译一下工程就会发现一大堆错误,所以还需努力移植工程才行。

2.4.3. 添加头文件路径到工程中

Ucos III的源码已经添加到开发环境的组文件夹下面,编译的时候需要为这些源文件指定头文件的路径,不然编译会报错,此时我们先将头文件添加到我们的工程中,具体见 图16-22

图片没有找到

至此,UCOS的整体工程基本移植完毕,我们需要修改UCOS配置文件,按照我们的需求来进行修改。

2.4.4. 具体的工程文件修改

添加完头文件路径后,我们可以编译一下整个工程,但肯定会有错误的, uC/OS-III 的移植尚未完毕,接下来需要对工程文件进行修改。首先修改工程的启动文件“startup_MIMXRT1052.s”。其中将图中的PendSV_Handler 和 SysTick_Handler 分别改为 OS_CPU_PendSVHandler 和OS_CPU_SysTickHandler,只有一处需要修改,因为uCOS官方已经给我们处理好对应的中断函数,就无需我们自己处理与系统相关的中断了,同时我们还需要在启动文件中添加EXTERN OS_CPU_PendSVHandler和EXTERN OS_CPU_SysTickHandler,具体见 图16-23图16-24图16-25

图片没有找到 图片没有找到

如果使用的是M7内核带有FPU(浮点运算单元)的处理器,不需要增加其他代码,在SystemInit()函数中就已经写好。具体见 代码清单16-1图16-26

代码清单‑1使能FPU位置(system_MIMXRT1052.c)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
    void SystemInit (void)
    {
    #if ((__FPU_PRESENT == 1) && (__FPU_USED == 1))
    SCB->CPACR |= ((3UL << 10*2) | (3UL << 11*2));    /* set CP10, CP11 Full Access */
    #endif/* ((__FPU_PRESENT == 1) && (__FPU_USED == 1)) */

    #if defined(__MCUXPRESSO)
    externuint32_t g_pfnVectors[];  // Vector table defined in startup code
            SCB->VTOR = (uint32_t)g_pfnVectors;
    #endif

    /* Watchdog disable */

    /*省略与FPU无关内容*/
    }

同时将对应芯片头文件中启用FPU的宏定义__FPU_PRESENT配置为1(默认是使能的),然后在Option->Target->Floating Point Hardware中选择启用浮点运算,具体见 图16-25

图片没有找到

修改完启动文件后,还需要修改cpu.h文件中的两处位置,分别是增加头文件“cmsis_compiler.h”和修改CPU_INT_DIS()的宏定义,由于工程是从IAR版本移植过来的,所以在cpu.h文件中缺少了写底层的宏定义文件。具体看 图16-26图16-27

图片没有找到 图片没有找到

2.4.5. 添加bsp.c与bsp.h文件

我们知道bsp就是板级相关的文件,也就是对应开发板的驱动文件,而在i.MX RT的uCOS III源码中需要添加一个这样的文件,主要是对系统的板级驱动初始化和板级驱动的头文件包含。

代码清单‑2bsp.c文件
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
    /*
    *********************************************************************
    * @file    bsp.c
    * @author  fire
    * @version V1.0
    * @date    2019-xx-xx
    * @brief   板级驱动
    ********************************************************************
    * @attention
    *
    * 实验平台:野火  i.MXRT1052开发板
    * 论坛    :http://www.firebbs.cn
    * 淘宝    :http://firestm32.taobao.com
    *
    ****************************************************************
    */


    /*
    ******************************************************************
    *                             包含的文件
    ******************************************************************
    */

    //板级驱动
    #include"fsl_debug_console.h"
    #include"board.h"
    #include"pin_mux.h"
    #include"clock_config.h"
    #include"./led/bsp_led.h"
    #include"bsp.h"

    /*
    ***************************************************************
    * 函数名 : BSP_Init
    * 描述   : 所有的硬件设备都应该放在这个函数里边初始化
    * 形参   : 无
    * 返回值 : 无
    ****************************************************************
    */
    void  BSP_Init (void)
    {
    /* 初始化内存保护单元 */
            BOARD_ConfigMPU();
    /* 初始化开发板引脚 */
            BOARD_InitPins();
    /* 初始化开发板时钟 */
    //BOARD_BootClockRUN();
    /* 初始化调试串口 */
            BOARD_InitDebugConsole();

    /* 打印系统时钟 */
            PRINTF("\r\n");
            PRINTF("*****欢迎使用野火i.MX RT1052 开发板*****\r\n");
            PRINTF("CPU:             %d Hz\r\n", CLOCK_GetFreq(kCLOCK_CpuClk));
            PRINTF("AHB:             %d Hz\r\n", CLOCK_GetFreq(kCLOCK_AhbClk));
            PRINTF("SEMC:            %d Hz\r\n", CLOCK_GetFreq(kCLOCK_SemcClk));
            PRINTF("SYSPLL:          %d Hz\r\n", CLOCK_GetFreq(kCLOCK_SysPllClk));
            PRINTF("SYSPLLPFD0:      %d Hz\r\n", CLOCK_GetFreq(kCLOCK_SysPllPfd0Clk));
            PRINTF("SYSPLLPFD1:      %d Hz\r\n", CLOCK_GetFreq(kCLOCK_SysPllPfd1Clk));
            PRINTF("SYSPLLPFD2:      %d Hz\r\n", CLOCK_GetFreq(kCLOCK_SysPllPfd2Clk));
            PRINTF("SYSPLLPFD3:      %d Hz\r\n", CLOCK_GetFreq(kCLOCK_SysPllPfd3Clk));
            PRINTF("这是一个[野火]-全系列开发板-uCOS-III  任务管理实验!\n\n");
    /* 硬件BSP初始化统统放在这里,比如LED,串口,LCD等 */
            LED_GPIO_Config();    //初始化LED

    }

bsp.h文件中需要添加我们自己的板级驱动头文件,头文件代码具体见 代码清单16-3

代码清单‑3bsp.h文件添加我们自己的板级头文件
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
    #ifndef  BSP_H_
    #define  BSP_H_


    /*********************************************************************
    *                                     EXTERNAL C LANGUAGE LINKAGE
    *
    * Note(s) : (1) C++ compilers MUST 'extern'ally declare ALL C function prototypes &
    riable/object
    *               declarations for correct C language linkage.
    ************************************************************************
    */

    #ifdef __cplusplus
    extern"C" {        /* See Note #1.  */
    #endif


    /*
    ************************************************************************
    *                             包含的文件
    ***********************************************************************
    */
    #include"./led/bsp_led.h"
    /*
    *************************************************************************
    *                             函数原型
    *************************************************************************
    */

    void  BSP_Init(void);

    /*
    *************************************************************************
    *                              MODULE END
    *************************************************************************
    */

    #endif

2.5. 按需配置最适的工程

虽然前面的编译是没有错误的,并且工程模板也是可用的,但是此时还不是我们最适合使用的工程模板,最适合的工程往往是根据需要进行配置的,而uCOS提供裁剪的功能,我们可以按需对系统进行裁剪。

2.5.1. os_cfg.h

os_cfg.h文件是系统的配置文件,主要是让用户自己配置一些系统默认的功能,用户可以选择某些或者全部的功能,比如消息队列、信号量、互斥量、事件标志位等,系统默认全部使用的,如果如果用户不需要的话,则可以直接关闭,在对应的宏定义中设置为0即可,这样子就不会占用系统的SRAM,以节省系统资源,os_c fg.h文件的配置说明具体见 代码清单16-4

代码清单‑4os_cfg.h
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
    #ifndef OS_CFG_H
    #define OS_CFG_H

    /* -------------- 其他配置 --------------- */
    #define OS_CFG_APP_HOOKS_EN             DEF_ENABLED/* 是否使用子函数*/
    #define OS_CFG_ARG_CHK_EN               DEF_ENABLED/* 是否使用参数检查*/
    #define OS_CFG_CALLED_FROM_ISR_CHK_EN   DEF_ENABLED/* 是否使用中断调用检查*/
    #define OS_CFG_DBG_EN                   DEF_ENABLED/* 是否使用debug*/
    #define OS_CFG_DYN_TICK_EN              DEF_DISABLED/* 是否使用动态勾选*/
    #define OS_CFG_INVALID_OS_CALLS_CHK_EN  DEF_ENABLED/* 是否使用检查无效的内核调用 */
    #define OS_CFG_OBJ_TYPE_CHK_EN          DEF_ENABLED/* 是否使用对象类型检查*/
    #define OS_CFG_TS_EN                    DEF_ENABLED/* 是否使用时间戳 */

    #define OS_CFG_PRIO_MAX                 64u/* 定义任务优先级的最大数量(请参阅OS_PRIO数据类型*/

    #define OS_CFG_SCHED_LOCK_TIME_MEAS_EN  DEF_DISABLED/* 是否包含DEF_ENABLED)代码以测量调度程
    锁定时间*/
    #define OS_CFG_SCHED_ROUND_ROBIN_EN     DEF_ENABLED/* 是否包含DEF_ENABLED)循环调度的代码*/

    #define OS_CFG_STK_SIZE_MIN             64u/*最小允许任务堆栈大小*/


    /* -------------- 事件标志位------------- */
    #define OS_CFG_FLAG_EN                  DEF_ENABLED/*是否使用事件标志位*/
    #define OS_CFG_FLAG_DEL_EN              DEF_ENABLED/*是否包含OSFlagDel()的代码 */
    #define OS_CFG_FLAG_MODE_CLR_EN    DEF_ENABLED/*是否包含清除事件标志位的代码 */
    #define OS_CFG_FLAG_PEND_ABORT_EN       DEF_ENABLED/*是否包含OSFlagPendAbort()的代码


    /* --------------- 内存管理 ----------- */
    #define OS_CFG_MEM_EN                   DEF_ENABLED/* 是否使用内存管理 */


    /* --------------- 互斥量 ------------- */
    #define OS_CFG_MUTEX_EN                 DEF_ENABLED/*是否使用互斥量 */
    #define OS_CFG_MUTEX_DEL_EN             DEF_ENABLED/*是否包含OSMutexDel()的代码*/
    #define OS_CFG_MUTEX_PEND_ABORT_EN      DEF_ENABLED/*是否包含OSMutexPendAbort()的代



    /* ---------- 消息队列---------------- */
    #define OS_CFG_Q_EN                     DEF_ENABLED/*是否使用消息队列       */
    #define OS_CFG_Q_DEL_EN                 DEF_ENABLED/*是否包含OSQDel()的代码 */
    #define OS_CFG_Q_FLUSH_EN               DEF_ENABLED/*是否包含OSQFlush()的代码 */
    #define OS_CFG_Q_PEND_ABORT_EN          DEF_ENABLED/*是否包含OSQPendAbort()的代码 */


    /* --------------- 信号量 ------------ */
    #define OS_CFG_SEM_EN                   DEF_ENABLED/*是否使用信号量  */
    #define OS_CFG_SEM_DEL_EN               DEF_ENABLED/*是否包含OSSemDel()的代码 */
    #define OS_CFG_SEM_PEND_ABORT_EN        DEF_ENABLED/*是否包含OSSemPendAbort()的代码*
    #define OS_CFG_SEM_SET_EN               DEF_ENABLED/*是否包含OSSemSet()的代码  */


    /* ----------- 任务管理 -------------- */
    #define OS_CFG_STAT_TASK_EN             DEF_ENABLED/*是否使用任务统计功能 */
    #define OS_CFG_STAT_TASK_STK_CHK_EN     DEF_ENABLED/*从统计任务中检查任务堆栈 */

    #define OS_CFG_TASK_CHANGE_PRIO_EN      DEF_ENABLED/*是否包含OSTaskChangePrio()代码*
    #define OS_CFG_TASK_DEL_EN              DEF_ENABLED/*是否包含OSTaskDel()代码*/
    #define OS_CFG_TASK_IDLE_EN             DEF_ENABLED/*是否使用空闲任务*/
    #define OS_CFG_TASK_PROFILE_EN          DEF_ENABLED/*是否使用OS_TCB中的变量用来分析*/
    #define OS_CFG_TASK_Q_EN                DEF_ENABLED/*是否包含OSTaskQXXXX()代码*/
    #define OS_CFG_TASK_Q_PEND_ABORT_EN     DEF_ENABLED/*是否包含OSTaskQPendAbort()代码*
    #define OS_CFG_TASK_REG_TBL_SIZE        1u/*任务特定寄存器的数量*/
    #define OS_CFG_TASK_STK_REDZONE_EN      DEF_DISABLED/*是否使用堆栈 redzone */
    #define OS_CFG_TASK_STK_REDZONE_DEPTH   8u/*堆栈redzone的深度*/
    #define OS_CFG_TASK_SEM_PEND_ABORT_EN   DEF_ENABLED/*是否包含OSTaskSemPendAbort()代

    #define OS_CFG_TASK_SUSPEND_EN          DEF_ENABLED/*是否包含OSTaskSuspend()和
    askResume()代码 */
    #define OS_CFG_TASK_TICK_EN             DEF_ENABLED/*是否包含(DEF_ENABLED)内核tick
    */


    /* ------- 任务本地存储管理 ------- */
    #define OS_CFG_TLS_TBL_SIZE             0u/* 是否包含任务本地存储(TLS)寄存器的代码
    F_ENABLED)*/


    /* -------- 时间管理 ------------- */
    #define OS_CFG_TIME_DLY_HMSM_EN         DEF_ENABLED/*是否包含OSTimeDlyHMSM()的代码*/
    #define OS_CFG_TIME_DLY_RESUME_EN       DEF_ENABLED/*是否包含OSTimeDlyResume()的代码



    /* ---------- 定时器管理 -------- */
    #define OS_CFG_TMR_EN                   DEF_ENABLED/*是否使用定时器 */
    #define OS_CFG_TMR_DEL_EN               DEF_ENABLED/*是否支持OSTmrDel()*/
    /*-----------跟踪录音机-----------*/
    #define OS_CFG_TRACE_EN                 DEF_DISABLED/*是否使用 uC/OS-III 跟踪仪器*/
    #define OS_CFG_TRACE_API_ENTER_EN       DEF_DISABLED/*是否使用 uC/OS-III Trace API进
    测*/
    #define OS_CFG_TRACE_API_EXIT_EN        DEF_DISABLED/*是否使用 uC/OS-III Trace API退
    测*/


    #endif

2.5.2. cpu_cfg.h

cpu_cfg.h文件主要是配置CPU相关的一些宏定义,我们可以选择对不同的CPU进行配置,当然,如果我们没有对CPU很熟悉的话,就直接忽略这个文件即可,在这里我们只需要注意关于时间戳与前导零指令相关的内容,我们使用的CPU是i.MX RT,是32位的CPU,那么时间戳我们使用32位的变量即可,而且i.MX RT支持前导零指令,可以使用它让系统进行寻找最高优先级的任务更加快捷,具体见 代码清单16-5

UCOS支持两种方法选择下一个要执行的任务:一个采用C语言实现前导零指令,这种方法我们通常称为通用方法,CPU_CFG_LEAD_ZEROS_ASM_PRESENT没有被定义的时候使用才使用通用方法获取下一个即将运行的任务,通用方法可以用于所有uCOS支持的硬件平台,因为这种方法是完全用C语言实现, 所以效率略低于特殊方法,但不强制要求限制最大可用优先级数目;另一个是硬件方式查找下一个要运行的任务,必须定义CPU_CFG_LEAD_ZEROS_ASM_PRESENT这个宏,因为这种方法是必须依赖一个或多个特定架构的汇编指令(一般是类似计算前导零[CLZ]指令,在M3、M4、M7内核中都有,这个指 令是用来计算一个变量从最高位开始的连续零的个数),所以效率略高于通用方法,但受限于硬件平台。

代码清单‑5cpu_cfg.h
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
    #ifndef  CPU_CFG_MODULE_PRESENT
    #define  CPU_CFG_MODULE_PRESENT
    /*   是否使用CPU名字:DEF_ENABLED或者DEF_DISABLED*/
    #define  CPU_CFG_NAME_EN                        DEF_DISABLED
    /* CPU名字大小(ASCII字符串形式)*/
    #define  CPU_CFG_NAME_SIZE                                16
    /* CPU时间戳功能配置(只能选择其中一个)*/
    /*  是否使用32位的时间戳变量:DEF_ENABLED或者DEF_DISABLED*/
    #define  CPU_CFG_TS_32_EN                       DEF_ENABLED
    /*  是否使用64位的时间戳变量:DEF_ENABLED或者DEF_DISABLED*/
    #define  CPU_CFG_TS_64_EN                       DEF_DISABLED
    /* *配置CPU时间戳计时器字大小 */
    #define  CPU_CFG_TS_TMR_SIZE                    CPU_WORD_SIZE_32

    /* 是否使用测量CPU禁用中断的时间  */
    #if 0
    #define  CPU_CFG_INT_DIS_MEAS_EN
    #endif
    /* 配置测量的次数*/
    #define  CPU_CFG_INT_DIS_MEAS_OVRHD_NBR                    1u
    /* 是否使用CPU前导零指令(需要硬件支持)  */
    #if 1
    #define  CPU_CFG_LEAD_ZEROS_ASM_PRESENT
    #endif
    /* 是否配置CPU计数尾随零位 */
    #if 0
    #define  CPU_CFG_TRAIL_ZEROS_ASM_PRESENT
    #endif
    /*是否定义CPU数据字存储顺序参见注释#2*/
    #if 0
    #define  CPU_CFG_ENDIAN_TYPE            CPU_ENDIAN_TYPE_BIG
    #endif
    /*是否定义定义CPU数据字存储顺序(参见注1)*/
    #define  CPU_CFG_CACHE_MGMT_EN            DEF_DISABLED

    #endif

2.5.3. os_cfg_app.h

os_cfg_app.h是系统应用配置的头文件,简单来说就是系统默认的任务配置,如任务的优先级、堆栈大小等基本信息,但是有两个任务是必须开启的,一个就是空闲任务, 另一个就是时钟节拍任务,这两个是让系统正常运行的最基本任务,而其他任务我们自己按需配置即可。

代码清单‑6os_cfg_app.h
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
    #ifndef OS_CFG_APP_H
    #define OS_CFG_APP_H

    /* ------------------ 其他配置 ------------------- */
    #define  OS_CFG_ISR_STK_SIZE                         256u/*ISR堆栈的大小*/

    #define  OS_CFG_MSG_POOL_SIZE                         32u/* 支持的最大消息数量*/

    #define  OS_CFG_TASK_STK_LIMIT_PCT_EMPTY              10u/*检查堆栈的剩余大小(百分百形
    此处是10%*/

    /* -------------------- 空闲任务 --------------------- */
    #define  OS_CFG_IDLE_TASK_STK_SIZE                    64u/* 空闲任务堆栈大小*/


    /* ------------------ 统计任务 ------------------ */
    #define  OS_CFG_STAT_TASK_PRIO  ((OS_PRIO)(OS_CFG_PRIO_MAX-2u))/* 优先级*/
    #define  OS_CFG_STAT_TASK_RATE_HZ                     10u/* 执行率(1至10 Hz)*/
    #define  OS_CFG_STAT_TASK_STK_SIZE                   128u/* 堆栈大小(CPU_STK元素的数
    )*/


    /* ---------------------- 时钟节拍任务 ----------------------- */
    #define  OS_CFG_TICK_RATE_HZ                        1000u/*系统的时钟节拍(一般为10 到
    00 Hz)*/
    #define  OS_CFG_TICK_TASK_PRIO                         1u/*时钟节拍任务的优先级    */
    #define  OS_CFG_TICK_TASK_STK_SIZE                   128u/*时钟节拍任务的堆栈大小 */


    /* --------------------- 定时器任务 ----------------------- */
    #define  OS_CFG_TMR_TASK_PRIO   ((OS_PRIO)(OS_CFG_PRIO_MAX-3u))/*“计时器任务”的优先级

    #define  OS_CFG_TMR_TASK_RATE_HZ                       1u/*定时器的频率*/
    #define  OS_CFG_TMR_TASK_STK_SIZE                    128u/*定时器任务的堆栈大小*/

    #endif

此处要注意时钟节拍任务,uCOS的时钟节拍任务是用于管理时钟节拍的,建议将其优先级设置更高一些,这样子在调度的时候,时钟节拍任务能抢占其他任务执行,从而能够更新任务,相对于其他操作系统,寻找处于最高优先级的就绪任务都是在中断中,uCOS将其放于任务中能更好解决关中断时间过长的问题。

2.6. 修改main.c

我们将原来裸机工程里面main.c的文件内容全部删除,新增如下内容,具体见 代码清单16-7

代码清单‑7app.c文件内容
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
    /*
    *****************************************************************
    * @file    main.c
    * @author  fire
    * @version V1.0
    * @date    2019-xx-xx
    * @brief   uCOS-III 系统移植
    ****************************************************************
    * @attention
    *
    * 实验平台:野火  i.MXRT1052开发板
    * 论坛    :http://www.firebbs.cn
    * 淘宝    :http://firestm32.taobao.com
    *
    *****************************************************************
    */
    /*
    ******************************************************************
    *                         包含的文件
    ********************************************************************
    */
    //ucosiii系统相关
    #include  <cpu.h>
    #include  <lib_mem.h>
    #include  <os.h>
    #include  <bsp_os.h>
    #include  <bsp_clk.h>
    #include  <bsp_int.h>
    #include"os_app_hooks.h"
    #include"app_cfg.h"
    //板级驱动


    /*
    ********************************************************************
    * 函数名 : main
    * 描述   : 标准的C函数入口
    * 形参   : 无
    * 返回值 : 无
    ********************************************************************
    */
    int main(void)
    {

    }

2.7. 下载验证

将程序编译好,用DAP仿真器把程序下载到野火i.MX RT系列开发板(具体型号根据你买的板子而定,每个型号的板子都配套有对应的程序),一看,啥现象都没有,一脸懵逼,我说,你急个肾,目前我们还没有在main函数里面创建任务,系统也没有跑起来,main函数中什么都没有,那当然是没有现象。如果要想看现象, 得自己在main创建里面应用任务,并且让uCOS跑起来,关于如何使用uCOS创建任务,请看下一章“创建任务”。