基础初始化过程
- APB EnableClock, 查找定时器所在APB及分组(一般APB1 GRP1),开启时钟
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_USARTx)
- 如果有相应的GPIO,初始化GPIO时钟、端口等。
- 填写
USART_InitStruct
。LL_USART_InitTypeDef USART_InitStruct = {0}; USART_InitStruct.BaudRate = 9600; USART_InitStruct.DataWidth = LL_USART_DATAWIDTH_8B; USART_InitStruct.StopBits = LL_USART_STOPBITS_1; USART_InitStruct.Parity = LL_USART_PARITY_NONE; USART_InitStruct.TransferDirection = LL_USART_DIRECTION_TX_RX; USART_InitStruct.HardwareFlowControl = LL_USART_HWCONTROL_NONE; USART_InitStruct.OverSampling = LL_USART_OVERSAMOLING_16;
- 根据需要关闭或打开Overrun检测。该检测启用后,硬件将自动判断是否在接受过程中发生了输入进入,从而造成数据丢失。同时启用后,开启RXNE中断同时会开启ORE中断,给中断处理造成麻烦。
LL_USART_DisableOverrunDetect(USARTx);
- 设置异步模式。
LL_USART_ConfigAsyncMode(USARTx);
- 初始化USART。
LL_USART_Init(USARTx, &USART_InitStruct);
- 启动USART。
LL_USART_Enable(USARTx);
软件发送一个字节
- 初始化完毕。
- 等待传输空闲。
while (!LL_USART_IsActiveFlag_TXE(USARTx));
- 发送数据。
LL_USART_TransmitData8(USARTx, data);
软件接收一个字节
- 初始化完毕。
- 读取内容。
while (LL_USART_IsActiveFlag_RXNE(USARTx)) { uint8_t data = LL_USART_ReceiveData8(USARTx); }
中断接收
- 初始化完毕。
- 开启 RXNE 中断。
LL_USART_EnableIT_RXNE(USARTx);
- 编写中断处理函数。
void USARTx_IRQHandler(void) { if (LL_USART_IsActiveFlag_RXNE(USARTx)) { uint8_t data = LL_USART_ReceiveData8(USARTx); } }
- 如果启用了Overrun,检查并清除ORE标志。
if (LL_USART_IsActiveFlag_ORE(USARTx)) { LL_USART_ClearFlag_ORE(USARTx); }
使用 DMA 接收
使用 DMA 接收可以最大限度避免丢失数据,同时可降低接收时的 CPU 占用。一种常用的通信模式是,发送数据前配置好 DMA,然后发送数据,同时 DMA 处理数据接收,发送完毕后,根据应接收的字节数判断是否已接收完毕。
- 初始化完毕。
- 查询外设应使用的DMA控制器及通道,配置 DMA。
LL_DMA_SetDataTransferDirection(DMAx, LL_DMA_CHANNEL_x, LL_DMA_DIRECTION_PERIPH_TO_MEMORY); LL_DMA_SetChannelPriorityLevel(DMAx, LL_DMA_CHANNEL_x, LL_DMA_PRIORITY_LOW); LL_DMA_SetMode(DMAx, LL_DMA_CHANNEL_x, LL_DMA_MODE_NORMAL); LL_DMA_SetPeriphIncMode(DMAx, LL_DMA_CHANNEL_x, LL_DMA_PERIPH_NOINCRMENT); LL_DMA_SetMemoryIncMode(DMAx, LL_DMA_CHANNEL_x, LL_DMA_MEMORY_INCREMENT); LL_DMA_SetPeriphSize(DMAx, LL_DMA_CHANNEL_x, LL_DMA_PDATAALIGN_BYTE); LL_DMA_SetMemorySize(DMAx, LL_DMA_CHANNEL_x, LL_DMA_MDATAALIGN_BYTE);
- 设置 DMA 地址,传输数据量。
LL_DMA_SetPeriphAddress(DMAx, LL_DMA_CHANNEL_x, LL_USART_DMA_GetRegAddr(USARTx, LL_USART_DMA_REG_DATA_RECEIVE)); LL_DMA_SetMemoryAddress(DMAx, LL_DMA_CHANNEL_x, (uint32_t)buffer); LL_DMA_SetDataLength(DMAx, LL_DMA_CHANNEL_x, bufferSize);
- 启动 DMA 通道。
LL_DMA_EnableChannel(DMAx, LL_DMA_CHANNEL_x);
- 清空 USART 接收缓冲。否则可能造成写入内存的第一个字节不是需要的内容。
while (LL_USART_IsActiveFlag_RXNE(USARTx)) { uint8_t drop = LL_USART_ReceiveData8(USARTx); }
- 启动 USART 发送到 DMA。
LL_USART_EnableDMAReq_RX(USARTx);
- 查询已接收的字节数。
static uint16_t __dma_read_size() { return BUFFER_SIZE - LL_DMA_GetDataLength(DMAx, LL_DMA_CHANNEL_x); }
- 等待接收到需要大小的数据。
static uint16_t __dma_wait_read(uint16_t sizeUntil, uint32_t timeout) { uint32_t tick = HAL_GetTick(); while (__dma_read_size() < sizeUntil) { if (HAL_GetTick() - tick > timeout) { return TIMEOUT; } } return SUCCESS; }