摘要:本文将从一个简单的需求出发,利用 RT-Thread Studio + CubeMX 这两个工具,基于 RT-Thread 完成系统创建及开发,目的是为了记录开发过程,方便以后回顾。
需求描述:
使用 RT-Thread Studio 创建基于 STM32F103RET6 的工程,并 USART1 和 USART2 ,USART1 用于 msh 的输入/输出,USART2 用于其他业务。
第一步、使用RT-Thread Studio创建工程(RttDemo)
软件安装不做赘述请看官方文档:安装 RTT Studio。
步骤:文件→新建→RT-Thread项目


注意:RTT Studio 生成的工程使用的是芯片内部HSI时钟,如需修改,请完善 drv_clk.c,将 drv_clk.c 文件中 system_clock_config(int target_freq_Mhz)函数中的内容,替换成我们用 CubeMX 生成的时钟初始化代码。
第二步、使用CubeMX配置工程(主要是配置时钟)
这里只简单说下,详细配置过程可以参考下文的链接,(需要注意的是生成代码的时候,不要勾选 “Generate peripheral initialization as a pair of".c/.h' files per peripheral” 选项):
- 工程创建,注意创建路


- RCC 设置

- 时钟配置

第三步、修改项目默认时钟配置为 CubeMX 配置的时钟
在 CubeMX 生成项目中找到 main.c 文件,并使用 main.c 文件中的 SystemClock_Config(void) 函数内容替换掉RTT工程中 drv_clk.c 文件中的 system_clock_config(int target_freq_Mhz) 函数。
第四步、新增串口(USART2)
可参考官方文档,新增串口部分:
在 RTT 项目 board.h 中添加对 USART2 的支持方法如下:
// 增加以下宏
#define BSP_USING_UART2
#define BSP_UART2_TX_PIN "PA2"
#define BSP_UART2_RX_PIN "PA3"

编译运行程序, PC 端连接 uart1,在 msh 中,输入 list_device 可以看到 uart2 设备。
msh >list_device
device type ref count
-------- -------------------- ----------
uart2 Character Device 0
uart1 Character Device 2
pin Miscellaneous Device 0
msh >
第五步、封装 USART2 并使用接口输出 “Hello RT-Thread!”
- 创建文件
在 applications 目录下创建 service/uart 文件夹,并创建文件 SerialUart2.h 和 SerialUart2.c ,
SerialUart2.h 主要内容如下:
#ifndef _SERIAL_UART_2_H_
#define _SERIAL_UART_2_H_
#include <rtdevice.h>
rt_bool_t serial2_init();
rt_size_t serial2_write(const void *buffer, rt_size_t size);
rt_size_t serial2_read(void *buffer, rt_size_t size);
rt_bool_t serial2_change_baudrate(rt_uint32_t rate);
#endif //_SERIAL_UART_2_H_
SerialUart2.c 主要内容如下:
#include "SerialUart2.h"
/* log */
#define DBG_TAG "SerialUart2"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>
/* uart */
#define UART_NAME "uart2"
static rt_device_t serial;
struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
/* circle buffer */
#define TX_RING_BUFFER_LEN 100
#define RX_RING_BUFFER_LEN 100
/* line buffer */
#define TX_RING_BUFFER_LEN 100
static rt_err_t serial_rx_callback(rt_device_t dev, rt_size_t size)
{
/* 更新超时检测时间 */
return RT_EOK;
}
rt_bool_t serial2_init()
{
rt_err_t ret = RT_EOK;
serial = rt_device_find(UART_NAME);
if (!serial)
{
LOG_D("find %s failed!\n", UART_NAME);
return RT_FALSE;
}
ret = rt_device_set_rx_indicate(serial, serial_rx_callback);
if(ret != RT_EOK)
{
LOG_D("uart2 set rx callback failed\r\n");
return RT_FALSE;
}
ret = rt_device_control(serial, RT_DEVICE_CTRL_CONFIG, &config);
if(ret != RT_EOK)
{
LOG_D("control device failed\r\n");
return RT_FALSE;
}
ret = rt_device_open(serial, RT_DEVICE_FLAG_INT_RX|RT_DEVICE_FLAG_INT_TX);
if (ret != RT_EOK)
{
LOG_D("open device failed\r\n");
return RT_FALSE;
}
return RT_TRUE;
}
rt_size_t serial2_write(const void *buffer, rt_size_t size)
{
return rt_device_write(serial, 0, str, (sizeof(str) - 1));
}
rt_size_t serial2_read(void *buffer, rt_size_t size)
{
return rt_device_read(serial, 0, buffer, size);
}
rt_bool_t serial2_change_baudrate(rt_uint32_t rate)
{
rt_err_t ret = RT_EOK;
struct serial_configure configtmp = config;
/* 修改串口波特率 */
configtmp.baud_rate = rate;
ret = rt_device_control(serial, RT_DEVICE_CTRL_CONFIG, &configtmp);
if(RT_EOK != ret)
{
LOG_D("open device failed\r\n");
return RT_FALSE;
}
return RT_TRUE;
}
文件重建完成后,加入头文件路径:
在项目上点击右键,再点击属性出现下图中的窗口,在其中添加自己刚创建的路径,并点击“应用并关闭”;


- 修改 main.c ,增加对 uart2 的测试代码:
#include <rtthread.h>
#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>
#include "SerialUart2.h"
int main(void)
{
int count = 1;
serial2_init();
while (count++)
{
LOG_D("Hello RT-Thread!");
serial2_write("Hello RT-Thread!", sizeof("Hello RT-Thread!"));
rt_thread_mdelay(1000);
}
return RT_EOK;
}
- 编译代码。
第六步、测试
- 使用 JLink 下载程序,并使用 TTL 转 USB 模块连接串口 2 到电脑,电脑上使用串口调试工具接收数据。



- 查看 uart1 的输出信息如下,可以看 uart2 已经被使用一次。
msh >list_device[D/main] Hello RT-Thread!
device type ref count
-------- -------------------- ----------
uart2 Character Device 1
uart1 Character Device 2
pin Miscellaneous Device 0