rt-thread+stm32 使用串口dma空闲中断接收不定长数据

rt-thread+stm32 使用串口dma空闲中断接收不定长数据


开发环境

IDE: RT-Thread Studio v2.1.0
系统版本:v4.0.2
芯片: STM32F407VG


一、工程配置

工程创建完成后,双击工程目录下的 RT-Thread Setting

在这里插入图片描述
选择右下角的更多配置

在这里插入图片描述
勾选使能串口DMA模式,设置缓冲区大小,ctrl+s保存配置后自动生成代码,然后退出配置页面。

在这里插入图片描述
打开 drivers/board.h ,按图示添加代码,引脚配置根据图示自行修改。

二、添加代码并测试

新建一对 uartdma.c && uartdma.h文件,在 uartdma.h中添加 Uart类定义,并声明UART1 和UART2对象。

#include "board.h"

typedef struct Uart
{
    rt_device_t serial;
    rt_mailbox_t mb;
    rt_size_t (*send)(char *, rt_size_t);
    rt_size_t (*recv)(char *, rt_int32_t);
    rt_err_t (*input)(rt_device_t, rt_size_t);
    int (*init)(uint32_t);
} Uart;

#ifdef BSP_UART1_RX_USING_DMA
extern Uart UART1;
#endif

#ifdef BSP_UART2_RX_USING_DMA
extern Uart UART2;
#endif

在 uartdma.c 中添加代码

#include "rtthread.h"
#include "uartdma.h"

#define RT_SERIAL_CONFIG_DEFAULT    \
{                                   \
    115200,    /* 115200 bits/s */  \
    8,          /* 8 databits */    \
    0,      /* 1 stopbit */         \
    0,      /* No parity  */        \
    0,    /* LSB first sent */      \
    0,       /* Normal mode */      \
    256, /* Buffer size */          \
    0                               \
}

struct serial_configure
{
    rt_uint32_t baud_rate;

    rt_uint32_t data_bits :4;
    rt_uint32_t stop_bits :2;
    rt_uint32_t parity :2;
    rt_uint32_t bit_order :1;
    rt_uint32_t invert :1;
    rt_uint32_t bufsz :16;
    rt_uint32_t reserved :6;
};

#ifdef BSP_UART1_RX_USING_DMA
#define UART1_NAME       "uart1"      /* 串口设备名称 */

static rt_size_t uart1_send(char *data, rt_size_t size);
static rt_size_t uart1_recv(char *buffer, rt_int32_t timeout);
static rt_err_t uart1_input(rt_device_t dev, rt_size_t size);
static int uart1_init(uint32_t baud_rate);

Uart UART1 = {
RT_NULL,
RT_NULL, uart1_send, uart1_recv, uart1_input, uart1_init };

static rt_size_t uart1_send(char *data, rt_size_t size)
{
    return rt_device_write(UART1.serial, 0, data, size);
}

static rt_size_t uart1_recv(char *buffer, rt_int32_t timeout)
{
    rt_size_t len;
    if (rt_mb_recv(UART1.mb, &len, timeout) != RT_EOK)
    {
        return 0;
    }
    len = rt_device_read(UART1.serial, 0, buffer, len);
    return len;
}

/* 接收数据回调函数 */
static rt_err_t uart1_input(rt_device_t dev, rt_size_t size)
{
    /* 发送邮件 */
    return rt_mb_send(UART1.mb, size);
}

static int uart1_init(uint32_t baud_rate)
{
    struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT; /* 初始化配置参数 */
    UART1.serial = rt_device_find(UART1_NAME);
    if (!UART1.serial)
    {
        rt_kprintf("find %s failed!\n", UART1_NAME);
        return RT_ERROR;
    }

    if (UART1.mb == RT_NULL)
    {
        UART1.mb = rt_mb_create("uart1_mb", 1, RT_IPC_FLAG_FIFO);
        if (UART1.mb == RT_NULL)
        {
            return RT_ERROR;
        }
    }
    /* step2:修改串口配置参数 */
    config.baud_rate = baud_rate;        //修改波特率
    /* step3:控制串口设备。通过控制接口传入命令控制字,与控制参数 */
    rt_device_control(UART1.serial, RT_DEVICE_CTRL_CONFIG, &config);
    rt_device_set_rx_indicate(UART1.serial, UART1.input);
    rt_device_open(UART1.serial, RT_DEVICE_FLAG_DMA_RX);
    return RT_EOK;
}
#endif

#ifdef BSP_UART2_RX_USING_DMA
#define UART2_NAME       "uart2"      /* 串口设备名称 */

static rt_size_t uart2_send(char *data, rt_size_t size);
static rt_size_t uart2_recv(char *buffer, rt_int32_t timeout);
static rt_err_t uart2_input(rt_device_t dev, rt_size_t size);
static int uart2_init(uint32_t baud_rate);

Uart UART2 = {
RT_NULL,
RT_NULL, uart2_send, uart2_recv, uart2_input, uart2_init };

static rt_size_t uart2_send(char *data, rt_size_t size)
{
    return rt_device_write(UART2.serial, 0, data, size);
}

static rt_size_t uart2_recv(char *buffer, rt_int32_t timeout)
{
    rt_size_t len;
    if (rt_mb_recv(UART2.mb, &len, timeout) != RT_EOK)
    {
        return 0;
    }
    len = rt_device_read(UART2.serial, 0, buffer, len);
    return len;
}

/* 接收数据回调函数 */
static rt_err_t uart2_input(rt_device_t dev, rt_size_t size)
{
    /* 发送邮件 */
    return rt_mb_send(UART2.mb, size);
}

static int uart2_init(uint32_t baud_rate)
{
    struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT; /* 初始化配置参数 */
    UART2.serial = rt_device_find(UART2_NAME);
    if (!UART2.serial)
    {
        rt_kprintf("find %s failed!\n", UART2_NAME);
        return RT_ERROR;
    }

    if (UART2.mb == RT_NULL)
    {
        UART2.mb = rt_mb_create("uart2_mb", 1, RT_IPC_FLAG_FIFO);
        if (UART2.mb == RT_NULL)
        {
            return RT_ERROR;
        }
    }
    /* step2:修改串口配置参数 */
    config.baud_rate = baud_rate;        //修改波特率
    /* step3:控制串口设备。通过控制接口传入命令控制字,与控制参数 */
    rt_device_control(UART2.serial, RT_DEVICE_CTRL_CONFIG, &config);
    rt_device_set_rx_indicate(UART2.serial, UART2.input);
    rt_device_open(UART2.serial, RT_DEVICE_FLAG_DMA_RX);
    return RT_EOK;
}
#endif

int uart_init(void)
{
#ifdef BSP_UART1_RX_USING_DMA
    if (UART1.init(115200) == RT_EOK)
    {
        rt_kprintf("uart1 dma init successful!\r\n");
    }
#endif

#ifdef BSP_UART2_RX_USING_DMA
    if (UART2.init(115200) == RT_EOK)
    {
        rt_kprintf("uart2 dma init successful!\r\n");
    }
#endif
    return RT_EOK;
}

INIT_ENV_EXPORT(uart_init); /* 使用组件自动初始化机制 */

编译下载运行

在这里插入图片描述
控制台打印出 串口 dma 初始化成功信息。

之后可以在应用层线程引入 uartdma.h ,调用 UART1.recv 和 UART1.recv,或者 UART2.send 和 UART2.recv进行收发数据。

但是在使用过程中,出现接收数据断帧问题。

在这里插入图片描述
接收数据有大概10%的概率出现错误。

三、解决问题

参考博文 https://blog.csdn.net/coderdd/article/details/108264369

在这里插入图片描述
根据上述博文连接描述进行代码修改。
在这里插入图片描述
修改完成后重新测试,以200ms一帧连续测试30分钟,未出现断帧问题。

  • 1
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
RT-Thread和LwIP移植到STM32F4平台需要一些步骤,下面是一个简单的指南: 1.下载RT-Thread源代码和LwIP源代码。可以从官方网站获取最新版本。 2.将RT-Thread和LwIP源代码添加到您的工程中。可以直接将源代码文件复制到您的工程目录中,也可以在工程中创建一个新的文件夹,并将源代码添加到该文件夹中。 3.根据您的硬件配置,对STM32F4的寄存器和外设进行初始化。通常,您需要根据硬件手册编写一些初始化代码,以使STM32F4与RT-Thread和LwIP兼容。 4.配置LwIP选项。通过修改lwipopts.h文件,您可以配置LwIP的各种选项,例如IP地址、子网掩码、网关等。 5.在RT-Thread的配置文件rtconfig.h中启用LwIP组件。找到RT-Thread中的lwip组件选项,并确保它被启用。 6.修改RT-Thread的初始化代码,以初始化并启动LwIP。在RT-Thread的应用程序入口函数中,添加初始化LwIP的代码。这包括为LwIP创建一个线程,并为网络接口分配内存等。 7.根据您的需求配置LwIP和RT-Thread的线程、任务和堆栈大小。这些参数的默认值可能不适合您的应用,您可以根据需要进行调整。 8.编译并烧录您的应用程序到STM32F4上。使用合适的编译工具和烧录器,将代码编译成二进制文件,并烧录到STM32F4上。 9.测试和调试。在STM32F4上运行您的应用程序,并使用适当的工具(例如串口终端)检查网络连接。您还可以使用调试器来调试您的应用程序,并解决可能遇到的问题。 这只是一个初步指南,具体的移植过程可能因个人需求和硬件平台的差异而有所不同。对于更深入的了解,建议参考LwIP和RT-Thread的官方文档和社区讨论。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值