实验要求
使用
DMA
的方式将串口接收缓存寄存器的值搬运到内存中,同时闪烁
LED1
。
CubeMX
配置
DMA
配置:
串口中断配置
代码实现
如何判断串口接收是否完成?如何知道串口收到数据的长度?
- 使用串口空闲中断(IDLE)!
- 串口空闲时,触发空闲中断;
空闲中断标志位由硬件置
1
,软件清零
利用串口空闲中断,可以用如下流程实现
DMA
控制的任意长数据接收:
1.
使能
IDLE
空闲中断;
2.
使能
DMA
接收中断;
3.
收到串口接收中断,
DMA
不断传输数据到缓冲区;
4.
一帧数据接收完毕,串口暂时空闲,触发串口空闲中断;
5.
在中断服务函数中,清除中断标志位,关闭
DMA
传输(防止干扰);
6.
计算刚才收到了多少个字节的数据。
7.
处理缓冲区数据,开启
DMA
传输,开始下一帧接收。
有三个文件需要修改:
main.c
rcvBuf
:用于存储接收到数据的缓冲区数组。rcvLen
:记录接收到的一帧数据的长度。__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE)
:启用UART1的IDLE(空闲)中断,用于检测接收完成。HAL_UART_Receive_DMA(&huart1, rcvBuf, 100)
:通过DMA方式使能UART1的接收中断,将接收到的数据存储到rcvBuf
中,每次接收100个字节。while (1)
:一个无限循环,在循环体内通过定时器操作,每300毫秒切换GPIOB的引脚状态,用于示例,可以理解为一个简单的心跳或指示灯。while(1)
循环内的点灯操作主要是为了说明在数据通过DMA传输的同时,CPU仍然可以继续执行其他任务。点灯操作是一个简单的示例,用于演示在数据传输的间隙里,CPU可以执行其他任务而不会阻塞。在实际应用中,这个循环内可能包含更复杂的逻辑、任务或者状态管理。
main.h
stm32f1xx_it.c
USART1_IRQHandler
:UART1的中断服务函数。__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE) == SET
:检查IDLE标志位是否被置位,即检测是否接收完成。__HAL_UART_CLEAR_IDLEFLAG(&huart1)
:清除IDLE标志位。HAL_UART_DMAStop(&huart1)
:停止DMA传输,防止DMA传输干扰。__HAL_DMA_GET_COUNTER(&hdma_usart1_rx)
:获取DMA传输的计数器信息,即还有多少数据未被传输。rcvLen = BUF_SIZE - temp
:计算接收到的数据长度。HAL_UART_Transmit_DMA(&huart1, rcvBuf, rcvLen)
:通过DMA发送接收到的数据。HAL_UART_Receive_DMA(&huart1, rcvBuf, BUF_SIZE)
:重新启动DMA接收,准备接收下一帧数据。
这段代码实现了当UART1接收到一帧完整的数据后,通过DMA将接收到的数据传输到缓冲区,并进行相应的处理。