文章目录
- 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 128static 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){}}
#endiftxbuff[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);}
}