STM32-UART-DMA HAL库缓冲收发

2023-12-15 17:42:32

1、说明

1.1、注意事项:

  • HAL库的DMA底层基本都会默认开启中断使能,如果在STM32CubeMx禁用了中断相关的功能,程序可能会进入空中断回调出不来。
  • 切记使用STM32-HAL库的DMA发送时需要开启USART中断和DMA中断。
  • 在一般时间要求不是很高很高的场合,使用HAL库自带的函数就可以,并不会很频繁的触发中断占用资源。

1.2、接收部分

  • 接收DMA初始化成循环传输模式。开启对应DMA通道中断和串口全局中断
  • 之前担心开启串口中断会在接收数据时连续触发中断、导致消耗CPU资源,实际HAL底层未开启接收中断,不会触发中断。

1.3、发送部分

  • 发送时如果要使用DAM功能,必须开启DMA中断和串口中断。HAL的全局状态需要在中断中得到更新,否则会发送完一次状态一直处于被占用中。
  • HAL底层开启了串口数据发送完成中断TC。该中断只有在DMA没有新的数据传入后,并且移位寄存器为空时才会触发一次,不会每发送一个字节就会触发中断

在这里插入图片描述


在这里插入图片描述

2、代码

2.1、初始化

初始化接收即可,发送会在有数据时才会去操作DMA
开启中断


在这里插入图片描述


在这里插入图片描述

 
#include "SEGGER_RTT.h"

#define TX_FIFO_SIZE 36
#define RX_FIFO_SIZE 128

static uint8_t rxbuff[RX_FIFO_SIZE];
static uint8_t txbuff[TX_FIFO_SIZE];

static uint16_t tx_tail = 0;
static uint16_t tx_head = 0;

2.2、缓冲接收

循环接收、需要开启DMA和UART中断

void dma_uart_init()
{
  HAL_UART_Receive_DMA(&huart1, rxbuff, RX_FIFO_SIZE);
}
///查询读取一个字节数据
int dma_uart_read_char()
{
  static int rx_tail = 0;
  int rx_head = (RX_FIFO_SIZE)-huart1.hdmarx->Instance->CNDTR; // 接收到的数据偏移量
  if (rx_head != rx_tail)
  {
    int ch = rxbuff[rx_tail++];
    if (rx_tail >= RX_FIFO_SIZE)
    {
      rx_tail = 0;
    }
    return ch;
  }
  return -1;
}

2.3、缓冲发送

单次DMA发送,需要开启DMA和UART中断

///查询状态并触发一次发送
static void dma_uart_write_trig()
{
  static int lock = 0;
  if (lock)//中断重入锁
    return;
  lock = 1;

  if (huart1.gState == HAL_UART_STATE_READY)
  {
    static uint8_t dma_tx_fifo[128];
    for (size_t n = 0; n < 128; n++)
    {
      if (tx_head != tx_tail)
      {
        dma_tx_fifo[n] = txbuff[tx_tail++];
        if (tx_tail >= TX_FIFO_SIZE)
          tx_tail = 0;
      }
      else
      {
        if (n > 0)
        {
          HAL_UART_Transmit_DMA(&huart1, dma_tx_fifo, n);
        }
        break;
      }
    }
  }
  lock = 0;
}

///DMA缓冲发送多个字节数据
void dma_uart_writes(const uint8_t *data, int size)
{
  for (size_t i = 0; i < size; i++)
  {
    uint16_t tmp = tx_head + 1;
    if (tmp >= TX_FIFO_SIZE)
    {
      tmp = 0;
    }
#if 0 // 丢弃新的数据
    if (tmp == tx_tail) // 数据溢出 发送慢于写入
    {
      break;  
    }
#else // 等待旧数据发送完
    if (tmp == tx_tail)
    {
      while (tmp == tx_tail)
      {
      }
    }
#endif
    txbuff[tx_head] = data[i];
    tx_head = tmp;
  }
  dma_uart_write_trig();
}

///中断回掉函数,该函数由串口发送完成中断TC触发
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
  dma_uart_write_trig();
}

2.4、格式化打印

#include "stdarg.h"
#include "stdio.h"

#define PRINT_BUFF_SIZE 500
static char print_buff[PRINT_BUFF_SIZE];
void print_x(void *format, ...)
{
  va_list ap;
  va_start(ap, format);
  int n = vsnprintf(print_buff, PRINT_BUFF_SIZE, format, ap);
  va_end(ap);
  if (n > 0)
  {
    dma_uart_writes((uint8_t *)print_buff, n);
  }
}

文章来源:https://blog.csdn.net/ai5945fei/article/details/135019730
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。