USART介绍

USART通讯是一种广泛使用的在硬件上使用的异步通讯协议。
USART通信可以自定义通讯协议。
USART是串口通信,用于2台设备之间的直接通信,其接口接线方式:

USART通讯过程

数据不传输

当不传输数据时,UART数据传输线通常保持高电平。

起始位

开始数据传输,发送端的会将传输线从高电平拉到低电平并保持1个时钟周期,当接收端检测到高到低电压跃迁时,便开始以波特率对应的频率读取数据帧中的位。

数据帧

数据帧包含所传输的实际数据。如果使用奇偶校验位,数据帧长度可以是5位到8位。
在不使用奇偶校验位的情况下,数据帧长度可以是9位。
在大多数情况下,数据以最低有效位优先方式发送。

奇偶校验

由于数据传输可以受到各种不确定因素导致出错,就需要使用奇偶校验来一定程度上确保数据的稳定性。
接收端读取数据帧后,将计数值为1的位,检查总数是偶数还是奇数。如果奇偶校验位为0(偶数奇偶校验),则数据帧中的1或逻辑高位总计应为偶数。如果奇偶校验位为1(奇数奇偶校验),则数据帧中的1或逻辑高位总计应为奇数。
当奇偶校验位与数据匹配时,UART会认为传输未出错。但是,如果奇偶校验位为0,而总和为奇数,或者奇偶校验位为1,而总和为偶数,则UART认为数据帧中的位已改变。

停止位

发送端将数据传输线从低电压驱动到高电压并保持1到2位时间。

HAL库使用USART通讯

在HAL库中,已经封装了对USART通讯的发送和接收函数,这里提供介绍。

数据类型

HAL_StatusTypeDef

枚举类型,表示USART串口状态

typedef enum
{
  HAL_OK       = 0x00U, // 成功
  HAL_ERROR    = 0x01U, // 错误
  HAL_BUSY     = 0x02U, // 繁忙
  HAL_TIMEOUT  = 0x03U  // 超时
} HAL_StatusTypeDef;

函数介绍

HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)

此函数用于开启某USART串口通信中断,来接收消息。
参数(UART_HandleTypeDef *huart)USART串口编号
参数(uint8_t *pData)接收数据缓冲区
参数(uint16_t Size)缓冲区大小
返回值:USART串口状态枚举类型(HAL_StatusTypeDef)
示例:

uint8_t __Usart1_Buffer;
uint8_t __Usart2_Buffer;

// 开启USART1串口通信
HAL_UART_Receive_IT(&huart1, &__Usart1_Buffer, 1);
// 开启USART2串口通信
HAL_UART_Receive_IT(&huart2, &__Usart2_Buffer, 1);

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)

此函数是一个中断函数,当发送端有消息发送时,接收端就受到消息时候,在接收端就会触发此中断(此函数需要自己定义),消息将会储存在缓冲区。
参数(UART_HandleTypeDef *huart)USART串口编号,常用于区分不同的Usart串口的消息
返回值:无
示例:

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  if (huart->Instance == USART1)
  {
    // USART1消息
  }
  else if (huart->Instance == USART2)
  {
    // USART2消息
  }
}

HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size, uint32_t Timeout)

此函数用于发送数据。
参数(UART_HandleTypeDef *huart)USART串口编号
参数(uint8_t *pData)发送的数据
参数(uint16_t Size)发送数据的大小
参数(uint32_t Timeout)超时时间,如果发送数据时,检测到串口繁忙,就会等待。
返回值:USART串口状态枚举类型(HAL_StatusTypeDef)
示例:

uint8_t message[] = "hello world";
// 通过USART1发送数据
HAL_UART_Transmit(&huart1, (uint8_t *)message, sizeof(message), 100);

设置私有协议示例

USART传输的数据是字节流,所以不带有协议,这里可以自己设计一个私有协议(一般情况)

设置协议头(帧头)

协议头的长度不限,一般长度为1或2个字节。
例如0x55 0x32

设置数据传输格式

方法一

可以设置数据结束标志位来判断消息是否结束

帧头标志位 数据 结束标识符(0x00)
示例:0x55 0x32 0xFA 0x44 0x00

这里中间的0xFA 0x44是接收数据,用于处理

方法二

可以设置数据长度来判断消息是否接受完成

帧头标志位 长度 数据
示例:0x55 0x32 0x02 0xFA 0x44

这里中间的0xFA 0x44是接收数据,0x02是表示有2个数据

单纯接收字符串示例

UART回调函数

在数据结尾必须带上\r\n

uint8_t USART1_RxBuffer[1]; //recv buffer
uint16_t USART1_RX_STA = 0; //recv state
uint8_t USART1_RX_BUF[200]; //recv content

uint8_t USART2_RxBuffer[1]; //recv buffer
uint16_t USART2_RX_STA = 0; //recv state
uint8_t USART2_RX_BUF[200]; //recv content

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	//usart1 -> PA9 TX | PA10 RX
	if(huart->Instance==USART1)
	{
		if((USART1_RX_STA&0x8000)==0)
		{
			if(USART1_RX_STA&0x4000)
			{
				if(USART1_RxBuffer[0]!=0x0a)USART1_RX_STA=0;
				else USART1_RX_STA|=0x8000;
			}
			else
			{	
				if(USART1_RxBuffer[0]==0x0d)USART1_RX_STA|=0x4000;
				else
				{
					USART1_RX_BUF[USART1_RX_STA&0X3FFF]=USART1_RxBuffer[0] ;
					USART1_RX_STA++;
					if(USART1_RX_STA>(200-1))USART1_RX_STA=0;	  
				}		 
			}
		}
		HAL_UART_Receive_IT(&huart1, (uint8_t *)USART1_RxBuffer, 1);
	}
	
	//usart2 -> PA2 TX | PA3 RX
	if(huart->Instance==USART2)
	{
		if((USART2_RX_STA&0x8000)==0)
		{
			if(USART2_RX_STA&0x4000)
			{
				if(USART2_RxBuffer[0]!=0x0a)USART2_RX_STA=0;
				else USART2_RX_STA|=0x8000;
			}
			else
			{	
				if(USART2_RxBuffer[0]==0x0d)USART2_RX_STA|=0x4000;
				else
				{
					USART2_RX_BUF[USART1_RX_STA&0X3FFF]=USART2_RxBuffer[0] ;
					USART2_RX_STA++;
					if(USART2_RX_STA>(200-1))USART2_RX_STA=0;	  
				}		 
			}
		}
		HAL_UART_Receive_IT(&huart2, (uint8_t *)USART2_RxBuffer, 1);
	}
}

UART接收完成检测

// 当字符串接收完成时,执行此函数,可以判断并回调
void Usart_CheckRecvFinish(void (*callback)(uint16_t, uint8_t), uint8_t isBlock, uint16_t *USART_RX_STA, uint8_t id)
{
	do
	{
		if (*USART_RX_STA & 0x8000)
		{
			callback(*USART_RX_STA & 0x3fff, id);
			*USART_RX_STA = 0;
		}
	} while (isBlock);
}

电赛E题代码

2023年OpenMV + STM32解决方案(国一)
2024年省一源码

此内容查看价格为20¥(VIP 8折),请先
本资源为付费资源。