- UART与USART介绍:
USART(universal synchronous asynchronous receiver and transmitte): 通用同步异步收发器
USART是一个串行通信设备,可以灵活地与外部设备进行全双工数据交换。
UART(universal asynchronous receiver and transmitter): 通用异步收发器
异步串行通信口(UART)就是我们在嵌入式中常说的串口,它还是一种通用的数据通信议。
区别:
USART是指单片机的一个端口模块,可以根据需要配置成同步模式(SPI,I2C),也可以将其配置为异步模式,后者就是UART。所以说UART姑且可以称之为一个与SPI,I2C对等的“协议”,而USART则不是一个协议,而是更应该理解为一个实体。
- UART基础配置
串口发送数据的时序图:
硬件基础:STM32G431RB(蓝桥杯嵌入式)
配置成异步模式即是UART,剩下的就是波特率等一些配置。
使能中断:
HAL_UART_Transmit();串口发送数据,使用超时管理机制
HAL_UART_Receive();串口接收数据,使用超时管理机制
HAL_UART_Transmit_IT();串口中断模式发送
HAL_UART_Receive_IT();串口中断模式接收
HAL_UART_Transmit_DMA();串口DMA模式发送
HAL_UART_Transmit_DMA();串口DMA模式接收
一般的情况下,发送数据是主观上的,所以用HAL_UART_Transmit();,接收数据是被动的,一般利用中断完成接收。
串口接收:
在main函数中启动中断接收:
HAL_UART_Receive_IT(&huart1,(uint8_t *)&RX_buf, 1);
在中断回调函数中要不断开启:(每次接收中断执行HAL_UART_IRQHandler函数之后,接收中断就会被关闭;)
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
HAL_UART_Receive_IT(&huart1,(uint8_t *)&RX_buf, 1);//接收一个字节
}
参考:单片机学习笔记-SMT32使用HAL库UART中断方式使用
了解到这个函数里主要是有:对后面要用到的一些参数进行配置。
huart->pRxBuffPtr = pData;
huart->RxXferSize = Size;
huart->RxXferCount = Size;
huart->RxISR = NULL;
//这里的size就是1,pDate就是接收的数组名
所以调用这个代替终端里重新调用HAL_UART_Receive_IT()函数
串口发送:
包含这俩个库才能使用sprintf和strlen函数。
char str[40];
sprintf(str, "Hello,world.\r\n");
HAL_UART_Transmit(&huart1,(unsigned char *)str, strlen(str), 50);
//int count=0;
//sprintf(str, "%d:Hello,world.\r\n",count);
- UART的DMA配置(太坑了,以后再说吧)
问题:
现在还不清楚选择AFOD和AFPP有什么影响,测试没发现什么问题,网上推荐选择AFOD,不懂为什么?
- 利用串口接收中断和空闲中断(直接访问寄存器)
串口接收中断:
使能接受中断RXEN后,串口接收8位数据位后,进入中断
使能:
__HAL_UART_ENABLE_IT(&huart2,UART_IT_RXNE);
实际处理函数:
USART2_IRQHandler(void)
一般在stm32cubemx中打开了串口中断,处理函数通常生成在stm32f1xx_it.c里面
自动生成的,这里面应该不需要使能(没实验过) HAL_UART_IRQHandler(&huart1);在main函数里使能就好
/******************************************************************************/
/* STM32F1xx Peripheral Interrupt Handlers */
/* Add here the Interrupt Handlers for the used peripherals. */
/* For the available peripheral interrupt handler names, */
/* please refer to the startup file (startup_stm32f1xx.s). */
/******************************************************************************/
/**
* @brief This function handles USART1 global interrupt.
*/
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
串口空闲中断:
使能IDLE,在串口接受完一帧数据后,在一个字节的时间内串口保持空闲则触发串口空闲中断
再次进入上文的处理函数 USART2_IRQHandler()
__HAL_UART_ENABLE_IT(&huart2,UART_IT_IDLE);
void USART3_IRQHandler(void){
uint8_t temp;
if(huart3.Instance->SR & UART_FLAG_RXNE){
Rx_uart3_signal=2;
temp=huart3.Instance->DR;
Rx_uart3_buf[Rx_uart3_cnt++]=temp;
}
else if(huart3.Instance->SR & UART_FLAG_IDLE){
temp=huart3.Instance->DR;
Rx_uart3_signal=0;
}
}
串口接受完后空闲必须清除空闲标志位。通过读串口DR寄存器里的值来清除IDLE标志位,否则程序一直触发空闲中断。
这里上下两部分分别是正常数据接收和串口空闲处理,给Rx_uart3_signal赋值,这样就可以在主循环里根据这个标志判断数据接收程度。
这里直接读取的是寄存器:
USART_SR:Status register
TXE: Transmit data register empty
RXNE: Read data register not empty
IDLE: IDLE line detected
USART_DR:包含接收或传输的数据字符
(SR包含了所有的寄存器状态,所以和对应寄存器相与就可以得到该寄存器的状态)
例如:huart3.Instance->SR & 0x40就是判断第7位寄存器TXE状态
更详细的参考: