2.4 RT-Thread快速上手
嵌入式操作系统因为它的特殊性,往往和硬件平台密切相关,特定的嵌入式操作系统往往只能在特定的硬件上运行。刚接触RT-Thread操作系统的读者并不容易获得一个和RT-Thread操作系统相配套的硬件平台,因此我们使用了软件的方式去模拟一个能够运行RT-Thread操作系统的硬件平台,如ARM公司的MDK-ARM仿真模拟环境;在软件模拟环境中也能达到和硬件环境几乎相同的效果。
MDK-ARM(MDK-ARM Microcontroller Development Kit)软件是一套完整的集成开发环境(IDE),它出自ARM公司,包括针对ARM芯片(ARM7、ARM9、Cortex-M系列、Cortex-R系列等)的高效C/C++编译器;针对各类ARM设备、评估板的工程向导和工程管理;用于软件模拟运行硬件平台的模拟器;与市面上常见的(如ST-Link、JLink等)在线仿真器相连接,以配合调试目标板的调试器。MDK-ARM软件中的软件仿真模拟器,采用完全软件模拟方式解释和执行ARM的机器指令,并实现外围的一些外设逻辑,从而构成一套完整的虚拟硬件环境,使得用户能够不借助真实的硬件平台就能够在电脑上执行相应的目标程序。
MDK-ARM集成开发环境因为其完全的STM32F103软件仿真环境,也让我们有机会在不使用真实硬件环境的情况下直接在电脑上运行目标代码。这套软件仿真模拟器能够完整地虚拟出ARM Cortex-M3的各种运行模式、外设,如中断异常、时钟定时器、串口等,这几乎和真实的硬件环境完全一致。实践也证明,本章使用的这份RT-Thread入门例程,在编译成二进制代码后,不仅能够在模拟器上模拟运行,也能够无须修改地在真实的硬件平台上正常运行。
下面我们将选择MDK-ARM集成开发环境模拟目标硬件平台来观察RT-Thread操作系统是如何运行的。
2.4.1 准备环境
在运行RT-Thread操作系统前,我们需要安装MDK-ARM 5.24(正式版或评估版,5.14版本及以上版本均可),这个版本也是当前比较新的版本,它能够提供相对完善的调试功能。这里采用了16K编译代码限制的评估版5.24版本,如果要解除16K编译代码限制,请购买MDK-ARM正式版。先从www.keil.com官方网站下载MDK-ARM评估版:http://www.keil.com/download/。
在下载时,需要填写一些个人基本信息,请填写相应的完整信息,然后开始下载。
步骤1 下载完成后,鼠标双击运行,会出现如图2-3所示的软件安装界面,这是MDK-ARM的安装说明,单击“Next”按钮进入下一步骤。
图2-3 MDK安装图1
步骤2 出现如图2-4所示的界面,选中“I agree to all the terms of the preceding License Agreement”复选框,并单击“Next”按钮进入下一步。
图2-4 MDK安装图2
步骤3 出现如图2-5所示的界面,单击“Browse”按钮选择MDK-ARM的安装目录或者直接在“Destination Folder”下的文本框中输入安装路径,这里我们默认“C:\Keil_v5”即可,然后单击“Next”进入下一步。
图2-5 MDK安装图3
步骤4 出现如图2-6所示的界面,在“First Name”文本框中输入你的名字,“Last Name”文本框中输入你的姓,“Company Name”文本框中输入你的公司名称,“E-mail”文本框中输入你的邮箱地址,然后单击“Next”按钮进行安装。
图2-6 MDK安装图4
步骤5 出现如图2-7所示的界面,等待一段时间后,安装结束。
图2-7 MDK安装图5
步骤6 出现如图2-8所示的界面,图中的默认选择不需改动,在这里可以单击“Finish”按钮完成整个MDK-ARM软件的安装。
图2-8 MDK安装图6
有了MDK-ARM这个利器,就可以轻松开始RT-Thread操作系统之旅,探索实时操作系统的奥秘了。
注意:MDK-ARM正式版是收费的,如果希望能够编译出更大体积的二进制文件,请购买MDK-ARM正式版。RT-Thread操作系统也支持自由软件基金会的GNU GCC编译器,这是一款开源的编译器,想要了解如何使用GNU的相关工具,请参考RT-Thread网站上的相关文档。
2.4.2 初识RT-Thread
本节开始接触RT-Thread的例程源码,为了方便上手,从一份精简的内核代码开始,代码位于配套资料的chapter1-9目录下,源自RT-Thread 3.1.0发布版,并在3.1.0版的基础上进行了裁剪,可以帮助读者快速上手使用RT-Thread。
本书所用的内核例程源码的目录结构如图2-9所示。
图2-9 工程目录
各个目录所包含的文件类型的描述如表2-1所示。
表2-1 RT-Thread例程文件夹目录
在目录下,有一个project.uvprojx文件,它是这里所引述的例程中的一个MDK5工程文件,双击project.uvprojx图标,打开此工程文件,如图2-10所示。
图2-10 MDK工程图
在工程主窗口左侧的Project栏里可以看到该工程的文件列表,这些文件被分别存放到如表2-2中所示的几个组内。
表2-2 RT-Thread例程工程目录
现在我们单击窗口上方工具栏中的按钮,对该工程进行编译,如图2-11所示。
图2-11 MDK工程编译图
编译的结果显示在窗口下方的Build Output栏中,若无特殊情况,最后一行会显示“0 Error(s), 0 Warning(s). ”,即无任何错误和警告。
在编译完RT-Thread/STM32后,我们可以通过MDK-ARM的模拟器来仿真运行RT-Thread。单击窗口右上方的 按钮或直接按Ctrl+F5组合键进入仿真环境,单击 按钮或直接按F5开始仿真。
然后单击该图工具栏中的按钮或者依次选择菜单栏中的“View → Serial Windows→ UART#1”命令,打开串口1窗口,可以看到串口输出了RT-Thread的Logo,其模拟运行的结果如图2-12所示。
图2-12 MDK模拟仿真图
RT-Thread提供FinSH功能,用于调试或查看系统信息,图2-12中的msh表示FinSH处于一种传统命令行模式,此模式下可以使用类似于Dos/Bash等传统的Shell命令。
比如,我们可以通过输入“help+回车”组合键或者直接按下Tab键,输出当前系统所支持的所有命令,如下:
msh >help RT-Thread shell commands: thread_sample - thread sample timer_sample - timer sample semaphore_sample - semaphore sample mutex_sample - mutex sample event_sample - event sample mailbox_sample - mailbox sample msgq_sample - msgq sample signal_sample - signal sample mempool_sample - mempool sample dynmem_sample - dynmem sample interrupt_sample - interrupt sample idle_hook_sample - idle hook sample producer_consumer - producer_consumer sample timeslice_sample - timeslice sample scheduler_hook - scheduler_hook sample pri_inversion - prio_inversion sample version - show RT-Thread version information list_thread - list thread list_sem - list semaphore in system list_event - list event in system list_mutex - list mutex in system list_mailbox - list mail box in system list_msgqueue - list message queue in system list_memheap - list memory heap in system list_mempool - list memory pool in system list_timer - list timer in system list_device - list device in system help - RT-Thread shell help. ps - List threads in the system. time - Execute command with time. free - Show the memory usage in the system. msh >
此时可以输入列表中的命令,如输入list_thread命令显示系统当前正在运行的线程,结果显示为tshell(FinSH线程)线程与tidle(空闲线程)线程:
msh >list_thread thread pri status sp stack size max used left tick error ------ --- ------- ---------- ---------- ------ ---------- --- tshell 20 ready 0x00000080 0x00001000 07% 0x0000000a 000 tidle 31 ready 0x00000054 0x00000100 32% 0x00000016000 msh >
FinSH具有命令自动补全功能,输入命令的部分字符(前几个字母,注意区分大小写),按下Tab键,则系统会根据当前已输入的字符,从系统中查找已经注册好的相关命令,如果找到与输入相关的命令,则会将完整的命令显示在终端上。例如,要使用version命令,可以先输入“v”,再按下Tab键,可以发现系统在下方补全了有关“v”开头的命令version,此时只需要按回车键,即可查看该命令的执行结果。
2.4.3 跑马灯的例子
对于从事电子方面开发的技术工程师来说,跑马灯大概是最简单的例子,这类似于每种编程语言中程序员接触的第一个程序Hello World,所以这个例子就从跑马灯开始,让它定时地对LED进行更新(亮或灭),详见代码清单2-1。
代码清单2-1 跑马灯例程
#include <rtthread.h> #include <rtdevice.h> #define LED_PIN 3 int main(void) { static rt_uint8_t count; rt_pin_mode(LED_PIN, PIN_MODE_OUTPUT); for(count = 0 ; count < 10 ; count++) { rt_pin_write(LED_PIN, PIN_HIGH); rt_kprintf("led on, count : %d\r\n", count); rt_thread_mdelay(500); rt_pin_write(LED_PIN, PIN_LOW); rt_kprintf("led off\r\n"); rt_thread_mdelay(500); } return 0; }
这是一个简单的LED跑马灯例程,代码清单中的rt_thread_mdelay()函数用于ms延时,使LED亮(500ms)灭(500ms)交替执行,每亮一次执行一次计数,10次之后退出执行。
仿真运行结果如下: