一、背景
个人认为:编写应用程序应该有一个基础框架,多数应用可以基于此框架实现。
框架完成基础功能,对于单片机而言就是串口通讯以及任务分配。在基于 FreeRTOS构建框架时,因为只有内核功能,故还自己编写了一个调试信息输出功能。而RT-Thread 可以方便的添加 uLog 组件,故无需再自己编写了。
但一次将框架构建好,需要涉及的内容较多,对于学习者而言是否合适?
我觉得:就RT-Thread的学习而言,单个功能的示例官方已经提供,缺少的是结合实际需求(或接近实际的需求)的编程示例,比如说多文件的编程,因为随着代码增加,放在一个文件中会导致阅读费力,调试困难;更无法实现多人合作,而这在实际工作中是必须面对的!
所以在此我还是主张先构建一个框架,学习者可以不必一次性将其吃透,而是在此基础上编写应用,在实践过程中逐步消化。
至于应用程序的框架如何构思,在前面已有文章专述,此处不再重复。
本篇重点是将前面设计的程序框架移植到 RT-Thread上,代替原来的 Free RTOS。
二、需求
将前面基于 Free RTOS 编写的应用程序框架,改写为基于 RT-Thread的应用程序框架,实现原来的所有功能。
具体而言:
- 开发环境从 Arduino IDE 替换为 RT-Thread Studio;
- 将Free RTOS 替换为 RT-Thread 标准版;
- 优化原程序框架中设计不合理的地方;
- 结合 RT-Thread 的特点优化部分功能的处理方式。
三、实施
因为是应用程序框架,应该不包含任何功能,故重新创建一个工程。
原来的程序框架设计不做任何改动,保留原来的所有功能,包括实现的代码,只是将两个 RTOS不同之处改写。
具体改动如下:
1、RT-Thread 配置中修改:
A)对象名称从 8 改为 16字符,以便定义的名称易于理解
B)支持标准C库
C)添加uLog,并支持线程标识。
D)控制台使用 UART1(PA9、PA10)
2、因uLog功能很完善,故删除原框架中的 Dump 任务。
3、在main()函数中编写消息、线程等创建过程,对应原来的 Setup()函数。
4、和原来一样使用 UART2(PA2、PA3)作为命令交互接口,按RT-Thread方式初始化,在工程中drivers 目录下的board.h 中添加定义:
5、Free RTOS 的事件组和 RT-Thread 的事件功能一致,只是做语法上的修改。
6、因按RT-Thread 官方文档说明,使用邮箱比使用队列效率要高,只是邮箱一次只能传4字节,而原设计使用队列,也是一次只传4字节,为消息存放的指针,故在此改为使用邮箱实现信息交互。处理方式不变,按 RT-Thread语法改写即可。
7、我设计的程序中一般会设计一个时基(timebase),作为程序中低速定时用。FreeRTOS 支持Tick 回调函数,故直接使用 Tick。但在 RT-Thread 中没有找到,故启用一个定时器代替原来的Tick 回调函数功能,实现定时唤醒相关处理。
8、RT-Thread 的线程创建遇到点麻烦,因为我希望实现多文件(模块),每个线程对应一个文件,这就牵涉到函数说明。RT-Thread 创建函数中的线程函数定义必须在同一文件下,用头文件按我理解的方式说明,编译不通过。官方文档中又没有交代多文件时该如何处理,还是在RTT官网的参考设计中心找到一个示例才实现的:
A)先在线程文件中定义一个创建线程函数;
B)再在main()中调用此创建函数即可,此创建函数可以用头文件定义。
9、RT-Thread 的串口处理支持中断接收,等于将原来 Arduino 封装的内容开放了,我自己需要编写一个中断接收处理,代替Arduino 的函数。功能基本一样,实现效果也相同。可靠性要等长时间运行才能知道,目前功能是实现了。
10、串口发送方式被折腾了一下,按说明,RT-Thread 提供了发送完成回调函数,这样就不必通过查询方式知道是否发送完成了(原来是通过发送缓存是否空判断发送是否完成的)。但实施后发现回调函数无法动作,查阅资料后更混乱,网上各种说辞都有。我尝试了使用 UART V2,结果没有用起来,只好暂时搁置,日后慢慢琢磨。通过跟踪调试,发现发送方式基本是阻塞完成的,故默认按阻塞逻辑处理,功能是实现了,后续再仔细分析一下。总之,串口发送不是太让人放心。
所有程序只是语法上做改动,逻辑上未做改变,基本是将原来的程序拷贝。
因 STM32F411CE内存较大(128K RAM、512K Falsh),故目前还不用精打细算,先完成功能,后续再琢磨如何降低无效的内存占用。
改写后的应用文件如下:
程序编译通过后,用原来的PC端程序测试,完美!
至此,基于RT-Thread 系统的应用编程应该说算是启动了,前面几步只是熟悉一下 开发环境,这一步才算真正引入 RTOS。后续在此基础上逐步添加具体应用功能,感受一下 RT-Thread 的实时性、可靠性、可维护性及易用性。
四、结语
虽说改写的过程还算顺利,实现了原来的功能,但还是有不少疑惑需要逐步消化,具体如下:
1)RT-Thread 创建线程多了一个参数:Slice,按说明是在轮流执行时,线程的执行时间,单位为 Tick,也就是说,RT-Thread 可以定义每个线程在轮流执行时的时间,而非每次Tick都转换线程。按此设计是增加了不小的灵活性,但最好有相应的应用说明,以便使这个功能能够发挥最佳效用。否则,随意定义是否反而会降低系统的性能(实时性)?
2)UART发送功能的说明太少,感觉V1版本是阻塞完成的,且未释放系统资源,用的是 HAL的函数等待 TC标志,这在 RTOS中似乎不太合适。后续再深入理解,争取能用V2,既然官方针对 STM32 推出了V2版本,一定是 V1存在一定不足。
3)按说明,uLog 也是一个线程,不知道占用资源如何?对系统实时性有无影响?目前框架所用的资源还行,至少对于 STM32F411CE而言 还有足够的开发空间:
不清楚上面的 RAM 资源是否包含了系统运行需要的堆栈空间?
要真正用好 RT-Thread,还需要下点功夫,不过至少到目前为止,感觉上手难度不算大,应该可以选用。
——————————————
文章中程序下载:
1、RTT应用程序框架:
链接:https://pan.baidu.com/s/1VsIE5HdMlgBSora1CdxU6w
提取码:hk07
2、PC端程序(基于 Processing 编写)
链接:https://pan.baidu.com/s/1s2gaolp20O0eiEHIFZKqdQ
提取码:1054