串口通信概述
通用同步异步收发器 (USART Universal Synchronous Asynchronous Receiver/Transmitter) 能够灵活地与外部设备进行全双工数据交换,满足外部设备对 工业标准 NRZ 异步串行数据格式的要求。USART 通过小数波特率发生器提供了多种波特率。它支持同步单向通信和半双工单线通信;还支持 LIN(局域互连网络)、智能卡协议与 IrDA (红外线数据协会)SIR ENDEC 规范,以及调制解调器操作 (CTS/RTS)。而且,它还支持 多处理器通信。通过配置多个缓冲区使用 DMA 可实现高速数据通信。
串口通信接口概述
USART接口最多五个信号:
TX:串行输出信号
RX:并行输出信号
nCTS:允许发送信号(Clear to Send)低电平有效,是对方设备发来的信号。假设nCTS信号为低电平,则表示对方已经准备好接受数据,本机可以发送数据了。
nRTS:请求发送(Request to Send)低电平有效,是发送给对方设备的信号。假设,本机做好接受数据准备,nRTS置为低电平,通知对方可以发送数据。
SCLK:发送器输出的时钟信号,仅用于同步模式。
TX和RX是必须的,nCTS和nRTS为硬件流控制信号,在异步通信时,可以选择是否启用,在同步通信是,没有硬件流控制信号。
UART只有RX和TX。
串口通信软件协议
接口通过三个引脚从外部连接到其它设备。任何 USART 双向通信均需要至少两个引脚:接收数据输入引脚 (RX) 和发送数据引脚输出 (TX):
RX:接收数据输入引脚就是串行数据输入引脚。过采样技术可区分有效输入数据和噪声,从而用于恢复数据。
TX:发送数据输出引脚。如果关闭发送器,该输出引脚模式由其 I/O 端口配置决定。如果使 能了发送器但没有待发送的数据,则 TX 引脚处于高电平。在单线和智能卡模式下,该 I/O 用于发送和接收数据(USART 电平下,随后在 SW_RX 上接收数据)。
注:使用ttl或者RS232进行通讯是,一般需要共地,否则会出现传输乱码。485通信由于采用差分信号表示不同的逻辑信号,仅需要两根线即可。
TX 引脚在起始位工作期间处于低电平状态。在停止位工作期间处于高电平状态。
串口通信的基本参数如下:
数据位:8位或者9位
奇偶校验位:
停止位:1个或者两个停止位
波特率:串行数据传输的速率,单位bit/s
STM32F4中有一个过采样(over sampling)参数,可以设置位8次采样和16次采样。8次采样速度快,容错性差,16次采样速度慢,但容错性好。
常用的串口电路
TLL和CMOS电平通信
串口转RS232
串口转RS485
串口转USB
串口的HAL的驱动程序
常用功能的函数
串口通信的驱动文件stm32f4xx_hal_uart.h
HAL_StatusTypeDef HAL_UARTEx_ReceiveToIdle_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
不同函数数据发送和接收方式说明
串口传输模式有两种:
- 阻塞模式(blocking mode) 即轮询模式,在函数执行阶段,函数会一直执行,知道函数数据传输完成或者超时。
- 非阻塞模式(non-blocking mode)即使用中断或者DMA方式进行传输。
阻塞模式函数说明 略
中断模式函数说明
- 串口发送中断
HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size)
其中pData是存放数据的指针,参数size是数据的长度。数据发送结束以后,会触发中断并且调用回调函数:
__weak void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
若需要在完成数据以后进行操作可以重新定义回调函数
- 串口接收中断
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
其中pData是存放数据的指针,参数size是数据的长度。数据发送结束以后,会触发中断并且调用回调函数:
__weak void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
若需要在完成数据以后进行操作可以重新定义回调函数
注:这个函数执行一次只能接收固定长度的数据。在完成数据接收后悔自动关闭中断,不会再继续接受数据。这个函数是“一次性”的,若需要再次使用程接收,需要再次执行这个函数。但是,不能在回调函数中再次调用这个函数启动重复调用。原因?
例:串口通信
使用USART2进行串口通信,接口与RS232芯片进行连接,转化成233电平,通过RS232引脚引出。
- Cubemx配置
- 时钟配置 略
- USART2 配置
模式配置,配置对应的波特率,字长度,停止位,校验位等参数。在NVIC Setting中打开串口中断。生成代码。
- 代码配置
在完成初始化串口函数以后,即可使用HAL库的串口函数进行数据传送
数据发送代码
uint8_t text[]="test";
HAL_UART_Transmit(&huart2, text, sizeof(text), 100);
数据接收:在数据接收时,最好外部设备向接收端发送数据时,串口启动的方式较好。因此一般不采用轮训的方式进行串口接受的操作,而使用中断或者DMA的方式进行串口接收数据。DMA数据方式,在DMA中讲,本次只解释中断方式接收串口数据。
根据函数定义,HAL_UART_Receive_IT()需要指定串口号,接收数据存储位和接受数据长度。
uint8_t rxBuffer[50];需要指定接受数据存放的数组
在接受完成数据以后 HAL_UART_Receive_IT(&huart2, rxBuffer, 5)跳转到中断函数中,执行中断回调函数HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)。
注:看到很多人在HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)中重新调用HAL_UART_Receive_IT(&huart2, rxBuffer, 5) 。但不知道会出现什么问题。
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
for(int i=0;i<5;i++)
{
proBuffer[i]=rxBuffer[i];
}
HAL_UART_Transmit(&huart2, proBuffer, 5, 100);
HAL_UART_Receive_IT(&huart2, rxBuffer, 5);
}
该中断回调函数 实现的是将接受到的数据完成传输后发送回串口。在接受数据满数据长度 5 时触发中断。代码存疑
方法2 使用串口空闲中断发送数据——指定数据长度
使用串口空闲中断进行函数重启的操作
在开启空闲中断以后,串口中断完成时,立即清除空闲中断标志位。因为串口经常处于空闲状态,会非常占用处理器时间。
1 void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) 2 { 3 4 rxCompleted = SET; 5 for(uint16_t i=0;i<RX_CMD_LEN;i++) 6 { 7 proBuffer[i]=rxBuffer[i]; 8 9 } 10 __HAL_UART_ENABLE_IT(huart, UART_IT_IDLE); 11 } 12 void on_UART_IDLE(UART_HandleTypeDef *huart) 13 { 14 if(__HAL_UART_GET_FLAG(huart, UART_FLAG_IDLE) ==RESET) 15 { 16 return; 17 } 18 __HAL_UART_CLEAR_IDLEFLAG(huart); 19 __HAL_UART_DISABLE_IT(huart,UART_IT_IDLE); 20 if(rxCompleted) 21 { 22 HAL_UART_Transmit(&huart2,proBuffer,5,100); 23 rxCompleted = RESET; 24 HAL_UART_Receive_IT(huart, rxBuffer, RX_CMD_LEN); 25 } 26 }
在中断函数中添加空闲中断的处理
1 void USART2_IRQHandler(void) 2 3 { 4 5 /* USER CODE BEGIN USART2_IRQn 0 */ 6 7 /* USER CODE END USART2_IRQn 0 */ 8 9 HAL_UART_IRQHandler(&huart2); 10 11 /* USER CODE BEGIN USART2_IRQn 1 */ 12 13 on_UART_IDLE(&huart2); 14 15 /* USER CODE END USART2_IRQn 1 */ 16 17 }