RT-Thread系列04——串口设备

====>>> 文章汇总(有代码汇总) <<<====

目标:串口接收串口助手发来的数据,并且将数据重新发送出去。

  • RT-Thread studio,版本: 2.2.6,不一样其实区别也不大
  • RT-Thread:标准版,4.0.3版本
  • 芯片包版本:0.1.9
  • 开发板:正点原子战舰开发板,主控STM32F103ZET6。或者正点原子潘多拉开发板,主控STM32L475VET6。有两个串口接口,并且能想办法转 USB 就行。

1. 使用串口二

因为串口二默认是被 Shell 功能占用了,所以这里先用串口2进行测试。调通后再移植串口一。

第一步:在 RT-Thread Settings 中 -> 组件 -> 设备驱动程序 -> 使用UART设备驱动程序 -> 使能串口DMA模式,勾选上。

因为串口一用于SHELL窗口了。所以使用UART设备驱动程序 默认是打开的,这里只要把下面的DMA点开即可。

在这里插入图片描述
第二步:在 board.h 中,添加如下宏定义。注意根据自己使用的开发板引脚修改引脚编号。

// 新增 串口2 设备
#define BSP_USING_UART2
#define BSP_UART2_TX_PIN       "PA2"
#define BSP_UART2_RX_PIN       "PA3"
// 串口2 使用接收DMA
#define BSP_UART2_RX_USING_DMA

此时如果直接编译,然后在 Shel l窗口输入 list_device 命令,就已经能看到uart2设备了。

第三步:编写测试代码

/*
 * 程序清单:这是一个串口设备 DMA 接收使用例程
 * 例程导出了 uart2_dma_test 命令到控制终端
 * 命令调用格式:uart2_dma_test
 * 程序功能:运行后通过串口输出字符串"usart2 test is running!",之后,串口2会将接收到的数据重新发送出去。
 * 此功能需要做出的适配如下:1. 在board.h串口部分添加如下宏定义
 * #define BSP_USING_UART2
 * #define BSP_UART2_TX_PIN       "PA2"
 * #define BSP_UART2_RX_PIN       "PA3"
 * #define BSP_UART2_RX_USING_DMA
 * 2.在rt-thread settings-组件-设备驱动程序-串口中打开DMA设置
*/

#include <rtthread.h>

// 串口接收消息结构
struct rx_msg
{
    rt_device_t dev;
    rt_size_t size;
};

//  串口设备名称
#define TEST_UART_NAME       "uart2"

// 串口设备句柄
static rt_device_t usart_serial;

// 消息队列控制块
static struct rt_messagequeue usart_rx_mq;


/* 接收数据回调函数 */
// 若串口以 DMA 接收模式打开,当 DMA 完成一批数据的接收后会调用此回调函数。
// dev 是设备句柄
// size 是缓冲区中接收到的数据长度
static rt_err_t uart_input(rt_device_t dev, rt_size_t size)
{
    struct rx_msg msg;
    rt_err_t result;

    // 把接收消息的对象 和 消息的大小放到msg结构体
    msg.dev = dev;
    msg.size = size;

    // 把包装好的msg发送到消息队列
    result = rt_mq_send(&usart_rx_mq, &msg, sizeof(msg));

    // 如果放满了输出提示信息
    if ( result == -RT_EFULL)
    {
        /* 消息队列满 */
        rt_kprintf("message queue full!\n");
    }
    return result;
}

// 串口线程函数体
static void serial_thread_entry(void *parameter)
{
    struct rx_msg msg;
    rt_err_t result;
    rt_uint32_t rx_length;

    static char rx_buffer[RT_SERIAL_RB_BUFSZ + 1];

    // 循环接收消息
    while (1)
    {
        // 将msg中的内容清零
        rt_memset(&msg, 0, sizeof(msg));

        /* 从消息队列中读取消息 放到msg中,采用一直等待的方式 */
        result = rt_mq_recv(&usart_rx_mq, &msg, sizeof(msg), RT_WAITING_FOREVER);

        if (result == RT_EOK)
        {
            /* 从串口读取 msg.size个字节的数据,并放到rx_buffer中  */
            rx_length = rt_device_read(msg.dev, 0, rx_buffer, msg.size);

            // 最后补 \0
            rx_buffer[rx_length] = '\0';

            /* 通过串口设备 serial 输出读取到的消息  */
            rt_device_write(usart_serial, 0, rx_buffer, rx_length);

            /* 打印数据 */
            rt_kprintf("%s\n", rx_buffer);
        }
    }
}

static int uart2_dma_test(void)
{
    rt_err_t ret = RT_EOK;

    static char msg_pool[256];

    char str[] = "usart2 test is running!\r\n";

    // 步骤1 通过串口名字找到串口句柄, 名称定义在最上边。
    usart_serial = rt_device_find(TEST_UART_NAME);
    if (!usart_serial)
    {
        // 未找到输出提示
        rt_kprintf(TEST_UART_NAME);
        rt_kprintf("not find!\n");

        return RT_ERROR;
    }

    // 步骤2 设置串口初始化参数 这里跳过

    // 步骤3 以DMA接收及轮询发送方式打开串口设备
    rt_device_open(usart_serial, RT_DEVICE_FLAG_DMA_RX);

    // 步骤4 设置串口接收回调函数
    // 3.1 初始化消息队列(回调函数中需要使用)
    rt_mq_init(&usart_rx_mq,
                "usart_rx_mq",
                msg_pool,                 /* 存放消息的缓冲区 */
                sizeof(struct rx_msg),    /* 一条消息的最大长度 */
                sizeof(msg_pool),         /* 存放消息的缓冲区大小 */
                RT_IPC_FLAG_FIFO);        /* 如果有多个线程等待,按照先来先得到的方法分配消息 */
    // 3.2 设置接收回调函数
    rt_device_set_rx_indicate(usart_serial, uart_input);

    // 步骤4 创建并启动 串口线程
    // 发送开始了的提示信息
    rt_device_write(usart_serial, 0, str, (sizeof(str) - 1));
    // 创建 serial 线程
    rt_thread_t thread = rt_thread_create("serial", serial_thread_entry, RT_NULL, 1024, 25, 10);
    // 创建成功则启动线程
    if (thread != RT_NULL)
    {
        rt_thread_startup(thread);
    }
    else
    {
        ret = RT_ERROR;
    }

    return ret;
}

/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(uart2_dma_test, uart2 device dma test);

编译运行后,在SHELL窗口(串口一)输入uart2_dma_test命令,然后在串口二中发送信息,串口二会将收到的信息重新发送。

2. 使用串口一

如果想要使用串口一(被 Shell 占用的串口),需要做出的改动如下:

  1. board.h中的宏定义
#define BSP_USING_UART1
#define BSP_UART1_TX_PIN       "PA9"
#define BSP_UART1_RX_PIN       "PA10"
#define BSP_UART1_RX_USING_DMA
  1. 在 RT-Thread Settings 中 -> 组件 -> shell命令中,将其关闭。
  2. 将上述程序中的#define TEST_UART_NAME "uart2",2 改为 1。
  3. 其余的函数名、命令名改不改都行,不影响运行,要能分辨就行。

Shell 也不是非要关闭,在rtconfig.h中把 Shell 使用的串口改到其他串口上也行。
默认如下#define RT_CONSOLE_DEVICE_NAME "uart1"

3. 串口发送DMA

关于串口发送DMA:

经测试,在部分芯片包中貌似不支持发送DMA。

在潘多拉STM32L475VET6中,增加#define BSP_UART2_TX_USING_DMA宏定义会报错。

而在STM32F407VET6中,增加#define BSP_UART2_TX_USING_DMA宏定义就可以正常编译通过。

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RT-Thread Studio 中使用串口设备,可以按照以下步骤进行: 1. 在设备管理器中找到串口设备,并记录下其名称和端口号。 2. 在 RT-Thread Studio 中创建一个名为 uart设备对象,并设置好其配置参数,如波特率、数据位、停止位和校验位等。 3. 在应用程序中调用相应的 API 函数来进行串口通信,如发送数据、接收数据等。 以下是一个使用串口设备的示例代码: ```c #include <rtthread.h> #include <rthw.h> #define UART_NAME "uart1" // 串口设备名称 #define UART_BUFSZ 128 // 缓冲区大小 static rt_device_t uart_dev; // 串口设备对象 static char uart_buffer[UART_BUFSZ];// 串口数据缓冲区 static void uart_thread_entry(void *parameter) { rt_size_t rx_len; while (1) { rt_memset(uart_buffer, 0, UART_BUFSZ); // 从串口设备中读取数据 rx_len = rt_device_read(uart_dev, 0, uart_buffer, UART_BUFSZ); if (rx_len > 0) { // 处理接收到的数据 rt_kprintf("Received: %s\n", uart_buffer); } // 延时一段时间 rt_thread_mdelay(10); } } int main(void) { // 初始化串口设备 uart_dev = rt_device_find(UART_NAME); rt_device_open(uart_dev, RT_DEVICE_FLAG_RDWR); // 创建串口线程 rt_thread_t tid = rt_thread_create("uart", uart_thread_entry, RT_NULL, 1024, 25, 5); rt_thread_startup(tid); return 0; } ``` 在上述代码中,首先通过 rt_device_find() 函数找到名为 uart1 的串口设备,并通过 rt_device_open() 函数打开该设备。然后创建一个名为 uart 的线程,该线程不断从串口设备中读取数据,并进行处理。可以根据实际需要修改线程的优先级、堆栈大小等参数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值