STM32 HAL 详述串口收发的所有方式
串口收发方式
串口收发的使用无外乎下面这些使用方式
串口发送
轮询发送
HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
轮询发送函数,根据TXE标志一字节一字节的将数据传输到移位寄存器,再根据TC标志判断发送完成。
中断发送
HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
中断发送函数,首先将要发送的数据及大小赋值给串口句柄的发送缓存,然后开启发送数据寄存器为空(TXE)中断,每传输完一个字节便会触发一次进入一次中断,在传输最后一个字节数据时关闭发送数据寄存器为空(TXE)中断,开启发送数据完成(TC)中断。发送完成后会执行发送完成的回调函数HAL_UART_TxCpltCallback(huart);
- 直接使用
HAL_UART_Transmit_IT()
函数发送不定长的数据,要注意等到上次数据发送完成后才能开启下次发送,否则会出现发送异常 - 可以将要发送的数据存入ringbuffer中,再通过发送中断一个一个将字符发送出去
DMA发送
通过DMA方式发送数据,只能通过正常模式,且要等上次数据通过DMA传输完成后才能开启下次传输。(可以通过发送完成中断或DMA传输完成中断两种方式判断数据发送完成)
串口接收
轮询接收
一般情况下,并不知道什么时候会有数据到来,若一直再while
循环中接收会过于占用单片机资源。正常情况下,串口接收会采用前台的处理方式,有数据到来就响应,也就是下面几种方式。
中断接收
- 一个字符一个字符的接收直到接收到结束标记(如\r\n)
- 定义一个ringbuffer,将接收到的字符不断入队,在后台程序中进行处理(参考之前实现的3D打印机固件,数据的接收方式)
中断+IDLE接收
中断中不断接收单个字符,在触发IDLE中断后说明接收到了一帧数据(一般情况下,这一帧数据便是一条完整的指令)
DMA+IDLE接收
开启DMA接收后,会自动将串口数据搬运到内存区域,在触发IDLE中断后说明接收到了一帧数据(一般情况下,这一帧数据便是一条完整的指令)
正常DMA
触发IDLE中断后需要暂时关闭DMA接收(防止此时再有数据到来),需要在处理数据后再次开启DMA接收
循环DMA
开启DMA循环模式后,没有必要每次触发idle中断后重新开启DMA接收,否则边和正常模式一样了。DMA开启循环模式后本身就相当于一个ringbuffer,只需设定两个指向头尾的变量即可将本帧数据读出来,而且idle中断中不需要关闭DMA接收。
附注
- 裸机系统中一般使用标志位来判断是否接收完成,而RTOS系统可以通过信号量来进行任务同步
- 使用ringbuffer时可以将字符存入其中,由字符组成的命令可以再放入一个ringbuffer,这样便构成了二级缓存更好的提高数据处理效率(可以参考marlin固件gcode解析)