1. 序言
对于 RT-Thread 学习了有一段时间了,是时候做个总结了,加强记忆,也是为了自己方便回来学习。
其实学了一小段时间之后,发现其实所有的外设感觉都差不大多,主要还是编程思想跟裸机变成不太一样。
后续学习路线其实就和裸机差不多了。
- 首先建议先学习官网的内核教程,了解实时操作系统和裸机编程的区别。而且其中用到的很多东西,比如信号量之类的,其实在后面学习外设还是需要用到的。
- 然后以标准版最优,学习工程的建立,知道工程目录中各个部分的作用。包括工程的支持文件之类的,比如每个地方的配置都在什么地方。
- 然后学习不同外设、软件包的使用。
- 最后搞点小项目案例,融会贯通。
官网文档毕竟是中文的,内核的教程B站也有视频,这里就不再拿出来记录了。
学习路线
2. 新建工程
用到的软件:
- RT-Thread studio,版本: 2.2.6,不一样其实区别也不大
- STM32CubeMX,版本:最新的
硬件:
- 正点原子战舰板,主控:STM32F103ZET6
- 正点原子潘多拉开发板,主控:STM32L475VET6
- 自己的开发板,主控:STM32F407VET6
后续在每个案例前都会说使用的开发板和需要注意的地方。
RT-Thread
- 标准版,4.0.3版本。
- 芯片包版本:0.1.9
芯片包版本这里用的三个主控都是用的这个版本,经过测试,芯片包版本太高很多其实不兼容。
接下来开始新建工程。
在RT-Thread Studio中,点击左上方文件
–>新建
–>RT-Thread 项目
。
然后在弹出的界面中,填写项目信息、选择RTT版本、选择处理器信息、选择调试方式,然后点击完成
,等待创建成功即可。
等待完成后,在左侧工程目录就能看到创建的工程了。各个目录的作用如下图所示。
在main.c中默认是有内容的。此时,直接编译工程,然后下载到开发板,就能看到串口不断发送信息了。
3. 启动流程
首先,在 libraries -> CMSIS -> Device -> ST -> STM32F1xx -> Source ->Templates -> gcc 文件夹中有 startup_stm32f103xe.s 汇编文件。系统启动后先从这里开始运行,并由此跳转到C代码,进行 RT-Thread 系统启动,最后进入用户程序入口函数 main()。
之后,在 rt-thread -> src 文件夹中有 components.c 文件,在此文件中有如下函数定义,系统从这里开始启动。
/* re-define main function */
int $Sub$$main(void)
{
rtthread_startup();
return 0;
}
还是在此文件中,有 rtthread_startup();
的定义。这个函数中的内容,就对应了上面流程图中从上到下的流程。
int rtthread_startup(void)
{
rt_hw_interrupt_disable();
/* 板级初始化:需在该函数内部进行系统堆的初始化 */
rt_hw_board_init();
/* 打印 RT-Thread 版本信息 */
rt_show_version();
/* 定时器初始化 */
rt_system_timer_init();
/* 调度器初始化 */
rt_system_scheduler_init();
#ifdef RT_USING_SIGNALS
/* 信号初始化 */
rt_system_signal_init();
#endif
/* 由此创建一个用户 main 线程 */
rt_application_init();
/* 定时器线程初始化 */
rt_system_timer_thread_init();
/* 空闲线程初始化 */
rt_thread_idle_init();
/* 启动调度器 */
rt_system_scheduler_start();
/* 不会执行至此 */
return 0;
}
目前,我主要关心这里到底是怎么进入到 main.c
函数中的,因此继续查看 rt_application_init();
函数。
void rt_application_init(void)
{
rt_thread_t tid;
#ifdef RT_USING_HEAP
tid = rt_thread_create("main", main_thread_entry, RT_NULL,
RT_MAIN_THREAD_STACK_SIZE, RT_MAIN_THREAD_PRIORITY, 20);
RT_ASSERT(tid != RT_NULL);
#else
rt_err_t result;
tid = &main_thread;
result = rt_thread_init(tid, "main", main_thread_entry, RT_NULL,
main_stack, sizeof(main_stack), RT_MAIN_THREAD_PRIORITY, 20);
RT_ASSERT(result == RT_EOK);
/* if not define RT_USING_HEAP, using to eliminate the warning */
(void)result;
#endif
rt_thread_startup(tid);
}
可以看到,就是创建了一个函数体为 main
函数的线程,然后启动了而已。
4. RT-Thread Setting
在了解启动流程之后,需要了解一下这个项目的一些配置信息,包含系统的也包含MCU的。
配置文件主要有两个,用户在使用RT_Thread的时候,只需要修改 board 和 rtconfig.h 这两个文件的内容即可。
- rtconfig.h:
- drivers -> board.h:(后面用到了说)
rtconfig.h:关于 RT-Thread 的内核配置信息主要包含在 rtconfig.h
文件中,在官网有对内核定义的介绍 内核配置示例。用户可以通过修改这个RT_Thread内核的配置头文件来裁剪RT_Thread的功能。
实际上,对于 rtconfig.h 里面的配置信息,可以通过 RT-Thread Setting 图形化界面配置后自动生成的,一般不需要我们手动更改。
在 RT-Thread Setting 中可以帮我们配置工程的参数,包括 RTT内核的、还有工程的驱动配置等。
如图,彩色的图标是已经在工程中添加的配置、黑白的是没有配置的。
还可以点开右侧箭头打开树状图。其包含了内核、组件、软件包、示例代码四部分。
比如,在此页面中修改内核参数,按下Ctrl + s
保存之后,在此打开rtconfig.h
即可看到其中的参数被自动修改。
再比如,打开组件中的 IIC 组件,就可以在 rt-thread 文件夹中看到 关于 IIC 的设备驱动代码。
另外,在示例中,还可以生成内核、组件等内容的示例代码,而且有详细介绍,方便学习。
这些示例代码在官网对应的章节也有,也可以直接复制过来用。
5. 内核学习
在看完这些知识之后,把官网所有内核章节最底部的相关的案例全部跑一遍,了解一下需要知道的东西,体会一下RTOS的新内容。
这部分比较简单,而且官网写的比较详细,这里就不写了,b站也有教程(目前,b站的教程都是带着跑完了内核的例程)。
内核这部分,把官方文档看看还是很有必要的,记不住是真的,能有个了解就可以。