文章目录
- 1、说明
- 1.1、注意事项:
- 1.2、接收部分
- 1.3、发送部分
- 2、代码
- 2.1、初始化
- 2.2、缓冲接收
- 2.3、缓冲发送
- 2.4、格式化打印
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);
}
}