前言

(1)本文将会介绍,如果使用RT-Thread studio配合STM32CubeMX创建一个基础的STM32F103ZERT-Thread标准版模板工程。
(2)RT-Thread studioSTM32CubeMX的适配并没有非常的完善,还是由一些步骤需要我们自己来做,但我所查阅到一些博客里面并没有提及,为了让各位有更好的开发体验,我也会进行提及。
(3)需要做的准备:

创建RT-Thread标准版工程

RT-Thread studio创建工程

(1)打开项目资源管理器。

在这里插入图片描述

(2)在项目资源管理器中右键 —> 新建 —> 项目。

在这里插入图片描述

(3)选择RT-Thread项目 —> 下一步。

在这里插入图片描述

(4)按照下图配置好工程,然后点击完成

在这里插入图片描述

(5)选择项目编译

在这里插入图片描述

(6)选择烧录器下载,控制台显示执行完毕,表示程序烧录完成。

在这里插入图片描述

(7)连接上设备复位之后有如下信息。

在这里插入图片描述

进行STM32CubeMX适配

STM32CubeMX中的操作

(1)打开STM32CubeMX,选择STM32F103ZETx

在这里插入图片描述

(2)因为我是STlink下载器,所以Debug设置为Serial Wire

在这里插入图片描述

(3)因为我开发板上是使用的外部无源晶振(陶瓷晶振),因此外部高速时钟配置为Crystal/Ceramic Resonator

在这里插入图片描述

(4)STM32F103的官方推荐系统主频72MHZ,因此我这里设置为72MHZ

在这里插入图片描述

(5)因为RT-ThreadShell默认使用的是串口1,因此我们需要使能串口1。最后生成代码。

在这里插入图片描述

RT-Thread studio中的操作

(1)在STM32CubeMX中生成代码之后,进入RT-Thread studio会有一个提示,直接点击确定即可。
== 注意:这个地方一定要先将STM32CubeMX关闭,否则这个提示可能不会出现,会对后续的操作产生影响!==

在这里插入图片描述

(2)找到cubemx/Src/main.c,将生成的SystemClock_Config()函数复制。

在这里插入图片描述

(3)找到drivers/drv_clk.c,在INIT_BOARD_EXPORT(clock_information);下面补充复制的SystemClock_Config()函数。

在这里插入图片描述

(4)然后在drivers/drv_clk.c中找到clk_init()函数,将extern void SystemClock_Config(void);删除。

在这里插入图片描述

(5)将cubemx/Src/main.c排除构建。

在这里插入图片描述

(6)编译烧录

利用STM32CubeMX生成一个LED闪烁程序

(1)通过上面的步骤,我们已经成功的在RT-Thread studio中适配好了STM32CubeMX。那么我们是不是可以试试添加一个LED闪烁的程序。

STM32CubeMX中的操作

(1)依旧是先双击打开STM32CubeMX。因为我开发板上的LED是连接的PB5,因此我只需要初始化PB5引脚为推挽输出。

在这里插入图片描述

(2)对外设初始化的文件单独生成.c/.h文件,最终生成代码

在这里插入图片描述

应用代码补充

(1)找到cubemx/Src/gpio.c文件,按照如下步骤添加构建。
<1>

在这里插入图片描述

<2>

在这里插入图片描述

<3>

在这里插入图片描述

(2)进入applications/main.c文件,补充如下代码

在这里插入图片描述

#include <rtthread.h>

#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "usart.h"
#include "gpio.h"

int main(void)
{
    int count = 1;
    /* Initialize all configured peripherals */
    MX_GPIO_Init();
    while (count++)
    {
        HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
        LOG_D("Hello RT-Thread!");
        rt_thread_mdelay(1000);
    }

    return RT_EOK;
}

(3)
<1>打开找到main.h —> 右键,点击打开声明进入main.h文件

在这里插入图片描述

<2>将void Error_Handler(void);注释掉。

在这里插入图片描述

(4)编译烧录,即可看到LED闪烁,终端出现Hello RT-Thread!的打印信息。

在这里插入图片描述

如何知道哪些外设文件需要添加构建

(1)对于上面添加构建的文件,包含的头文件。肯定会有朋友感到疑惑,我怎么知道应该添加哪些头文件?又应该使用包含那几个初始化函数?
(2)这个时候我们就需要打开之前排除构建的cubemx/Src/main.c

需要添加的头文件

(1)在cubemx/Src/main.c中找到USER CODE END Header,然后下图框框中的内容就是我们需要包含的头文件。

在这里插入图片描述

需要复制的初始化函数

(1)搜索Initialize all configured peripherals,下图框选部分除了MX_USART1_UART_Init()函数以外的其他外设初始化都需要被复制。

在这里插入图片描述

(2)可能会有同学会问,为什么MX_USART1_UART_Init()函数不需要被包含?原因很简单,因为RT-TreadFinSH默认使用的是串口1,如果再对串口1进行初始化,那么可能会导致FinSH失效。
注:我看别人说是会失效,但是我实操之后没有影响。个人感觉还是不要再使用MX_USART1_UART_Init()对串口进行初始化,以防万一。

需要添加构建的文件

(1)做完前面的操作之后,我们编译程序,可能会出现如下报错

在这里插入图片描述

(2)这个问题很简单,就是STM32CubeMX生成的外设初始化文件没有被参与构建。因此,我们只需要按住Ctrl+左键点击这个报错的函数,即可知道这个函数在哪里实现。STM32CubeMX生成的外设初始化文件都是在cubemx/Src路径下。

在这里插入图片描述

RT-Thread的设备框架

支持的设备框架

(1)RT-Thread标准版为了能够屏蔽不同芯片的HAL层区别,增加程序的可移植性,同时为了方便使用丰富软件包组件,它提出了利用统一的设备驱动 API 。因此,我们可以尝试使用RT-Thread标准版所提供的设备框架进行初始化,然后设置高低电平。

#include <rtthread.h>

#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>

#include <rtdevice.h>
#include "drv_common.h"
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "usart.h"
#include "gpio.h"

#define LED_PIN        GET_PIN(B, 5)

int main(void)
{
    int count = 1;
    /* Initialize all configured peripherals */
    //MX_GPIO_Init();
    rt_pin_mode(LED_PIN, PIN_MODE_OUTPUT);
    while (count++)
    {
        rt_pin_write(LED_PIN, PIN_LOW);
        LOG_D("Hello RT-Thread!");
        rt_thread_mdelay(1000);
        rt_pin_write(LED_PIN, PIN_HIGH);
        rt_thread_mdelay(1000);
    }

    return RT_EOK;
}

(2)一些人使用RT-Thread Nano版本的时候,也想使用RT-Thread标准版的一些组件,因此,他们也在RT-Thread Nano做了一些设备框架的适配。至于具体如何适配,请自行阅读官方文档。

不支持的设备框架

(1)如果我们发现,RT-Thread标准版本的设备框架还不支持某一个外设,那么我们这个时候就可以使用到STM32CubeMX进行工程的初始化了,至于如何进行适配,请阅读上文的利用STM32CubeMX生成一个LED闪烁程序如何知道哪些外设文件需要添加构建章节。

STM32CubeMX生成的main.c都做了什么?

(1)为了加深各位对RT-Thread studioSTM32CubeMX适配工作的理解。我将再说一下STM32CubeMX生成的main.c做了什么。
(2)首先,我们打开cubemx/Src/main.c文件,我们会发现,这个文件里面其实只有四个函数:

  • int main(void);
  • void SystemClock_Config(void);
  • void Error_Handler(void);
  • void assert_failed(uint8_t *file, uint32_t line);

main()函数

(1)首先,在applications/main.c中,已经有了一个main()函数了,那么我们尝试比对一下applications/main.ccubemx/Src/main.c中的main()函数有什么区别。
(2)我们会发现,cubemx/Src/main.c中的main()函数会多一个HAL_Init();和一个SystemClock_Config();函数。
(3)如果了解RT-Thread 启动流程的同学就会知道,在main()函数之前,有一个rtthread_startup()函数会被执行。而rtthread_startup()函数中的存在rt_hw_board_init()函数,这个函数里面包含了HAL_Init();SystemClock_Config();函数。

在这里插入图片描述

SystemClock_Config()函数

(1)在前面,我已经说了,我们会将SystemClock_Config()函数复制到drivers/drv_clk.c文件中。因此不再赘述

Error_Handler()函数

(1)这个函数是一个错误处理函数,如果时钟初始化错误,那么就会进入这个函数里面。在RT-Thread的中,已经对这个函数进行了宏定义。他其实就是_Error_Handler()函数。因此,我们在前面会在main.h中,将void Error_Handler(void);进行注释。否则会报错。

#define Error_Handler() _Error_Handler(__FILE__, __LINE__)

assert_failed()函数

(1)这个函数是ST官方推出的一个用于调试的函数接口。一般情况下,USE_FULL_ASSERT这个宏都处于关闭状态,因此不用理会。

参考

(1)STM32CubeMX环境安装(保姆级)
(2)90天韦东山实战训练营RTOS双架构双系统:5-2-1_RT-Thread Studio配置使用说明
(3)RT-Thread官方文档:在 RT-Thread Studio 上使用 RT-Thread Nano 并使用 PIN 设备接口
(4)RT-Thread官方文档:I/O 设备模型
(5)C站:RT-Thread系统启动过程,非常详细,通俗易懂!!!

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐