Bootstrap

HAL库(STM32CubeMX)——USART串口配置学习(中断接收/STM32G431RBT6)

  • 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);

实例:参考:STM32基于HAL库的串口接受中断和空闲中断

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状态

更详细的参考:

STM32F1串口寄存器解析及应用

;