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

复制代码
c
1234567
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)
示例:

复制代码
1234567
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串口的消息
返回值:无
示例:

复制代码
c
1234567891011
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)
示例:

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

设置私有协议示例

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

设置协议头(帧头)

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

设置数据传输格式

方法一

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

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

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

方法二

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

复制代码
text
帧头标志位 长度 数据 示例:0x55 0x32 0x02 0xFA 0x44

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

单纯接收字符串示例

UART回调函数

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

复制代码
c
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
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接收完成检测

复制代码
c
123456789101112
// 当字符串接收完成时,执行此函数,可以判断并回调 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折),请先
本资源为付费资源。