#include "usart3.h" #include <string.h> #include "stdarg.h" /* ******串口3初始化***************************************** * 函数功能: 串口3初始化 * 入口参数: baud:设定波特率 * 返回参数: 无 * 说明: TX-PB10 RX-PB11 ********************************************************** */ #define RECEIVE_BUF_SIZE 8 uint8_t WindRxFlag = 0; // 串口3接收标志0-未接受1-接收 uint8_t WindReceiveBuff[RECEIVE_BUF_SIZE]; // 串口3接收缓冲 uint16_t WindRxLen = 0; // 串口3接收长度 uint8_t WindDecid=0; float WindVelocity=0;//风速 //串口接收缓存区 u8 USART3_RX_BUF[USART3_MAX_RECV_LEN]; //接收缓冲,最大USART3_MAX_RECV_LEN个字节. u8 USART3_Cach_BUF[USART3_MAX_RECV_LEN]; //接收缓冲,最大USART_REC_LEN个字节. u8 USART3_TX_BUF[USART3_MAX_SEND_LEN]; //发送缓冲,最大USART3_MAX_SEND_LEN字节 u8 USART3_RX_Count=0; //通过判断接收连续2个字符之间的时间差不大于10ms来决定是不是一次连续的数据. //如果2个字符接收间隔超过10ms,则认为不是1次连续数据.也就是超过10ms没有接收到 //任何数据,则表示此次接收完毕. //接收到的数据状态 //[15]:0,没有接收到数据;1,接收到了一批数据. //[14:0]:接收到的数据长度 vu16 USART3_RX_STA=0; void Usart3_Init(unsigned int baud) { GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3 , ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB , &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOB , &GPIO_InitStructure); USART_InitStructure.USART_BaudRate = baud; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); USART_ITConfig(USART3, USART_IT_RXNE, ENABLE); USART_Init(USART3,&USART_InitStructure); USART_Cmd(USART3,ENABLE); USART3_RX_STA=0; //清零 } void USART3_IRQHandler(void) { uint8_t Res; if(USART_GetITStatus(USART3,USART_IT_RXNE) != RESET) //判断是否发生中断 { Res=USART_ReceiveData(USART3); if(Res=='A') { isKey1=1; // OperateMode=!OperateMode; // oled_Clear(); } else if(Res=='D') { if(OperateMode==1) Threshold.Switch1=!Threshold.Switch1; } else if(Res=='B') { Threshold.Geer++; } else if(Res=='E') { Threshold.Geer--; } Res='\0'; USART_ClearITPendingBit(USART3, USART_IT_RXNE); } } void WindRx_Handel(void) { uint16_t crc; if(USART3_RX_STA) { // printf("WindRx:"); // for(int i=0;i<7;i++) // { // printf("%x ",WindReceiveBuff[i]); // } // printf("\r\n"); crc= Crc16(WindReceiveBuff,7); if(crc==0) { // SensorData.WindVel=WindReceiveBuff[3]<<8; // SensorData.WindVel+=WindReceiveBuff[4]; // SensorData.WindVel=SensorData.WindVel*0.1; // printf("WindVelocity:%f\r\n",SensorData.WindVel); if(WindReceiveBuff[4]==1) WindDecid=1; else WindDecid=0; } // printf("crc:%d\r\n",crc); USART3_RX_STA = 0; WindRxLen = 0; memset(WindReceiveBuff, 0x00, sizeof(WindReceiveBuff)); } // printf("WindVelocity:%d\r\n",WindVelocity); } ///* //******串口发送单字节***************************************** //* 函数功能: 串口发送单字节 //* 入口参数: pUSARTx:串口号 // ch:需要发送的字节 //* 返回参数: 无 //********************************************************** //*/ void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch) { /* 发送一个字节数据到USART */ USART_SendData(pUSARTx,ch); /* 等待发送数据寄存器为空 */ while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET); } ///* //******串口发送多字节***************************************** //* 函数功能: 串口发送单字节 //* 入口参数: pUSARTx:串口号 // Buffer:需要发送的数组的指针 // Length:需要发送的数组的长度 //* 返回参数: 无 //********************************************************** //*/ void Usart_SendBytes( USART_TypeDef * pUSARTx, uint8_t *Buffer, uint8_t Length) { uint8_t i=0; while(i<Length) { // if(i<(Length-1)) // Buffer[Length-1]+=Buffer[i];//累加Length-1前的数据 Usart_SendByte(pUSARTx,Buffer[i++]); } } ///* //******串口发送字符串***************************************** //* 函数功能: 串口发送字符串 //* 入口参数: pUSARTx:串口号 // str:需要发送的字符串的首地址 //* 返回参数: 无 //********************************************************** //*/ //void Usart_SendString( USART_TypeDef * pUSARTx, char *str) //{ // unsigned int k=0; // do // { // Usart_SendByte( pUSARTx, *(str + k) ); // k++; // } while(*(str + k)!='\0'); // /* 等待发送完成 */ // while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET) // {} //} /* CRC16 余式表 */ static uint16_t crctalbeabs[] = { 0x0000, 0xCC01, 0xD801, 0x1400, 0xF001, 0x3C00, 0x2800, 0xE401, 0xA001, 0x6C00, 0x7800, 0xB401, 0x5000, 0x9C01, 0x8801, 0x4400 }; /*! * 功 能: CRC16校验 * param1: 指向要校验的数据的指针 * param2: 要校验的数据的长度 * retval: 校验所得到的值,uint16_t 类型 * * 说 明: 本次CRC校验为查表法,多项式为 x16+x15+x2+1(0x8005),CRC的初始值为0xFFFF */ uint16_t Crc16(uint8_t *ptr, uint32_t len) { uint16_t crc = 0xffff; uint32_t i; uint8_t ch; for (i = 0; i < len; i++) { ch = *ptr++; crc = crctalbeabs[(ch ^ crc) & 15] ^ (crc >> 4); crc = crctalbeabs[((ch >> 4) ^ crc) & 15] ^ (crc >> 4); } return crc; } __align(8) char USART3_TxBuff[128]; void u3_printf(char* fmt,...) { unsigned int i =0,length=0; va_list ap; va_start(ap,fmt); vsprintf(USART3_TxBuff,fmt,ap); va_end(ap); length=strlen((const char*)USART3_TxBuff); while(i<length) { Usart_SendByte(USART3,USART3_TxBuff[i]); i++; } while(USART_GetFlagStatus(USART3,USART_FLAG_TC)==RESET); }
时间: 2025-07-01 22:49:31 浏览: 10
你提供的代码是一个基于 STM32 微控制器的串口 3(USART3)通信模块实现,主要功能包括:
1. **串口初始化**:配置 PB10 和 PB11 引脚为 USART3 的 TX 和 RX 功能。
2. **中断接收处理**:在 `USART3_IRQHandler` 中接收数据并根据接收到的字符执行操作。
3. **CRC 校验处理**:对接收到的数据包进行 CRC16 校验,并解析风速数据。
4. **串口发送函数**:支持单字节、多字节和字符串的发送。
5. **自定义打印函数**:使用 `u3_printf()` 支持类似 `printf()` 的格式化输出。
---
### ✅ 详细分析与解释
#### 1. **USART3 初始化函数 `Usart3_Init()`**
- 使用标准外设库初始化 GPIOB 和 USART3。
- 配置波特率、数据位、停止位、校验方式等参数。
- 启用 USART3 接收中断(`USART_IT_RXNE`),用于接收数据。
- 设置 NVIC 中断优先级。
#### 2. **中断服务函数 `USART3_IRQHandler()`**
- 检查是否是接收中断(`USART_IT_RXNE`)。
- 读取接收到的数据,根据不同的字符(如 `'A'`, `'B'`, `'D'`, `'E'`)触发不同逻辑。
- 清除中断标志位。
#### 3. **CRC 校验函数 `Crc16()`**
- 使用查表法实现 CRC16 校验(多项式为 `0x8005`,初始值为 `0xFFFF`)。
- 用于验证数据完整性,常用于工业通信协议如 Modbus。
#### 4. **自定义 printf 函数 `u3_printf()`**
- 使用 `vsprintf()` 将格式化字符串写入缓冲区。
- 调用 `Usart_SendByte()` 逐字节发送出去。
- 等待发送完成标志 `USART_FLAG_TC` 来确保数据完全发送。
#### 5. **WindRx_Handel() 函数**
- 判断是否有完整的数据帧到达。
- 对接收到的数据进行 CRC 校验。
- 如果校验成功,则提取风速信息并更新全局变量。
---
### 🧩 可能存在的问题与优化建议:
1. **中断中直接调用 `printf` 或复杂操作**:
- 不推荐在中断中使用 `printf` 或耗时操作。应将数据放入队列或标志位,在主循环中处理。
2. **WindReceiveBuff 处理逻辑不完整**:
- 当前 WindVelocity 没有正确赋值,需要从 WindReceiveBuff 提取高低字节组合成浮点数。
3. **CRC 查表法效率较高,但可移植性一般**:
- 如果跨平台开发,可以考虑更通用的 CRC 实现。
4. **缓冲区溢出风险**:
- 在接收数据时没有做长度检查,容易造成缓冲区溢出。
---
### 🔁 示例改进:如何正确解析风速数据
假设数据格式如下:
```
[0] [1] [2] [3] [4] [5] [6]
ID CMD DATA_H DATA_L DECID CRC_H CRC_L
```
```c
void WindRx_Handel(void)
{
uint16_t crc;
if(USART3_RX_STA)
{
crc = Crc16(WindReceiveBuff, 7);
if(crc == 0)
{
uint16_t raw_velocity = (WindReceiveBuff[3] << 8) | WindReceiveBuff[4];
WindVelocity = raw_velocity * 0.1; // 假设单位为 0.1 m/s
WindDecid = WindReceiveBuff[5]; // 解析 Decid 字段
u3_printf("WindVelocity: %.1f m/s, Decid: %d\r\n", WindVelocity, WindDecid);
}
USART3_RX_STA = 0;
WindRxLen = 0;
memset(WindReceiveBuff, 0x00, sizeof(WindReceiveBuff));
}
}
```
---
###
阅读全文
相关推荐














