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

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

  • 开发环境
  • 一、工程配置
  • 二、添加代码并测试
  • 三、解决问题


开发环境

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


一、工程配置

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

rt-thread+stm32 使用串口dma空闲中断接收不定长数据_第1张图片
选择右下角的更多配置

rt-thread+stm32 使用串口dma空闲中断接收不定长数据_第2张图片
勾选使能串口DMA模式,设置缓冲区大小,ctrl+s保存配置后自动生成代码,然后退出配置页面。

rt-thread+stm32 使用串口dma空闲中断接收不定长数据_第3张图片
打开 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); /* 使用组件自动初始化机制 */

编译下载运行

rt-thread+stm32 使用串口dma空闲中断接收不定长数据_第4张图片
控制台打印出 串口 dma 初始化成功信息。

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

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

rt-thread+stm32 使用串口dma空闲中断接收不定长数据_第5张图片
接收数据有大概10%的概率出现错误。

三、解决问题

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

rt-thread+stm32 使用串口dma空闲中断接收不定长数据_第6张图片
根据上述博文连接描述进行代码修改。
rt-thread+stm32 使用串口dma空闲中断接收不定长数据_第7张图片
修改完成后重新测试,以200ms一帧连续测试30分钟,未出现断帧问题。

你可能感兴趣的:(stm32,stm32,uart,dma,串口通信,嵌入式)