第1章
新建RT-Thread工程——软件仿真
在开始编写RT-Thread内核之前,我们先新建一个RT-Thread工程,Device选择Cortex-M3(Cortex-M4或Cortex-M7)内核的处理器,调试方式选择软件仿真,然后我们开始一步一步地教大家把RT-Thread内核写出来,让大家彻底明白RT-Thread的内部实现和设计思想,最后把RT-Thread移植到野火STM32开发板上。最后的移植其实已经非常简单,只需要换一下启动文件并添加bsp驱动即可。
1.1 新建本地工程文件夹
在开始新建工程之前,我们先在本地计算机中新建一个文件夹用于存放工程。可将文件夹命名为“新建RT-Thread工程——软件仿真”(名字可以随意设置),然后在该文件夹下新建各个文件夹和文件,有关这些文件夹的包含关系和作用如表1-1所示。
表1-1 工程文件夹根目录下的文件夹及作用
1.2 使用KEIL新建工程
开发环境我们使用KEIL5,版本为5.23,高于或者低于5.23均可,但应为版本5系列。
1.2.1 New Project
首先打开KEIL5软件,新建一个工程,工程文件放在目录Project下面,命名为Fire_RT-Thread,其中Fire表示“野火”,当然也可以为其他名称,但是应注意必须用英文,不能用中文。
1.2.2 Select Device for Target
设置好工程名称,确定之后会弹出相应Select Device for Target对话框,选择处理器,这里选择ARMCM3,也可根据Device型号选择ARMCM4或ARMCM7,如图1-1~图1-3所示。
图1-1 选择ARMCM3
图1-2 选择ARMCM4
图1-3 选择ARMCM7
1.2.3 Manage Run-Time Environment
选择好处理器后,单击OK按钮将弹出Manage Run-Time Environment对话框。这里在CMSIS栏中选中CORE,在Device栏中选中Startup文件即可,如图1-4所示。
图1-4 Manage Run-Time Environment对话框
单击OK按钮,关闭Manage Run-Time Environment对话框之后,刚刚选择的CORE和Startup这两个文件就会添加到工程组中,如图1-5所示。
图1-5 CORE(即system)和Startup文件
这两个文件刚开始都是存放在KEIL的安装目录下,当配置Manage Run-Time Environment对话框之后,软件就会把选中的文件从KEIL的安装目录复制到我们的工程目录Project\RTE\Device\ARMCM3(ARMCM4或ARMCM7)下面。其中startup_ARMCM3.s(startup_ARMCM4.s或startup_ARMCM7.s)是用汇编语言编写的启动文件,system_ARMCM3.c(system_ARMCM4.c或system_ARMCM7.c)是用C语言编写的与时钟相关的文件。若想了解更加具体的内容,可直接阅读这两个文件的源码。只要是Cortex-M3(Cortex-M4或Cortex-M7)内核的单片机,这两个文件都适用。
1.3 在KEIL工程中新建文件组
在KEIL工程中添加user、rtt/ports、rtt/source和doc这4个文件组,用于管理文件,如图1-6所示。
图1-6 新添加的文件组
对于初学者,有一个问题就是如何添加文件组。具体的方法为右击Target 1,在弹出的快捷菜单中选择Add Group...命令即可,如图1-7所示。需要多少个组,就按此步骤操作多少次。
图1-7 添加组
1.4 在KEIL工程中添加文件
图1-8 向组中添加文件
在工程中添加好组之后,需要把本地工程中创建好的文件添加到工程里面。具体操作为把readm. txt文件添加到doc组,把main.c文件添加到user组,至于RT-Thread相关的文件目前还没有编写,那么RT-Thread相关的组暂时为空,如图1-8所示。
对于初学者,有一个问题是如何将本地工程中的文件添加到工程组中。具体的方法为双击相应的组,在弹出的文件对话框中找到要添加的文件,默认的文件类型是C文件。如果要添加的是文本或者汇编文件,那么此时将看不到这类文件,这时就需要将“文件类型”设置为All files,最后单击Add按钮即可,如图1-9所示。
图1-9 向组中添加文件的方法
下面编写main()函数。
一个工程中如果没有main()函数是无法编译成功的,因为系统在开始执行时先执行启动文件里面的复位程序,复位程序中会调用C库函数__main, __main的作用是初始化系统变量,如全局变量,以及只读的、可读可写的变量等。__main最后会调用__rtentry,再由__rtentry调用main()函数,从而由汇编跳入C的世界,这里的main()函数就需要我们手动编写,如果没有编写main()函数,就会出现main()函数未定义的错误,如图1-10所示。
图1-10 未定义main()函数的错误
main()函数写在main.c文件中,因为是刚刚新建的工程,所以main()函数暂时为空,具体参见代码清单1-1。
代码清单1-1 main()函数
1 /* 2 ************************************************************************ 3 * main()函数 4 ************************************************************************ 5 */ 6 int main(void) 7 { 8 for (; ; ) 9 { 10 /* 无操作 */ 11 } 12 }
1.5 调试配置
1.5.1 设置软件仿真
完成上述操作后,再配置一下调试相关的参数即可。为了方便,本书全部代码都用软件仿真,既不需要开发板,也不需要仿真器,只需要一个KEIL软件即可。有关软件仿真的具体配置如图1-11所示。
图1-11 软件仿真的配置
1.5.2 修改时钟大小
在时钟相关文件system_ARMCM3.c(system_ARMCM4.c或system_ARMCM7.c)的开头,有一段代码定义了系统时钟的频率为25MHz,具体参见代码清单1-2。在软件仿真时,要确保时间的准确性,代码中系统时钟与软件仿真的时钟必须一致,所以Options for Target对话框中Target选项卡中的时钟频率应该由默认的12改成25,如图1-12所示。
图1-12 软件仿真时钟配置
代码清单1-2 时钟相关宏定义
1 #define __HSI ( 8000000UL) 2 #define __XTAL ( 5000000UL) 3 4 #define __SYSTEM_CLOCK (5*__XTAL) /* 5*5000000=25M*/
1.5.3 添加头文件路径
应在C/C++选项卡中指定工程头文件的路径,否则编译会出错。头文件路径的具体指定方法如图1-13所示。
图1-13 指定头文件的路径
至此,一个完整的基于Cortex-M3(Cortex-M4或Cortex-M7)内核的RT-Thread软件仿真工程建立完毕。