STM32自定义串口通信协议
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file usart.c
* @brief This file provides code for the configuration
* of the USART instances.
******************************************************************************
* @attention
*
* Copyright (c) 2023 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "usart.h"
/* USER CODE BEGIN 0 */
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart3, (uint8_t *)&ch,1,0xffff);
return ch;
}
#include <string.h>
#define UART_BUFFER_SIZE 100
#define MAX_RETRIES 2 // 最大重试次数
#define TIMEOUT_MS 100
// 自定义通信协议数据结构
typedef struct
{
uint8_t start_byte; // 开始标识(1字节)
uint8_t source; // 数据来源(1字节)
uint8_t type; // 数据类型(1字节)
uint16_t length; // 数据长度(2字节)
uint8_t* data; // 数据
uint16_t checksum; // 校验和(2字节)
uint16_t end_byte[2]; // 结束标识(2字节)
} CustomProtocol;
// 定时器超时标志
volatile uint8_t timeoutFlag = 0;
/* USER CODE END 0 */
UART_HandleTypeDef huart3;
/* USART3 init function */
void MX_USART3_UART_Init(void)
{
/* USER CODE BEGIN USART3_Init 0 */
/* USER CODE END USART3_Init 0 */
/* USER CODE BEGIN USART3_Init 1 */
/* USER CODE END USART3_Init 1 */
huart3.Instance = USART3;
huart3.Init.BaudRate = 115200;
huart3.Init.WordLength = UART_WORDLENGTH_8B;
huart3.Init.StopBits = UART_STOPBITS_1;
huart3.Init.Parity = UART_PARITY_NONE;
huart3.Init.Mode = UART_MODE_TX_RX;
huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart3.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart3) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN USART3_Init 2 */
/* USER CODE END USART3_Init 2 */
}
void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(uartHandle->Instance==USART3)
{
/* USER CODE BEGIN USART3_MspInit 0 */
/* USER CODE END USART3_MspInit 0 */
/* USART3 clock enable */
__HAL_RCC_USART3_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/**USART3 GPIO Configuration
PB10 ------> USART3_TX
PB11 ------> USART3_RX
*/
GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF7_USART3;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* USART3 interrupt Init */
HAL_NVIC_SetPriority(USART3_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(USART3_IRQn);
/* USER CODE BEGIN USART3_MspInit 1 */
/* USER CODE END USART3_MspInit 1 */
}
}
void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
{
if(uartHandle->Instance==USART3)
{
/* USER CODE BEGIN USART3_MspDeInit 0 */
/* USER CODE END USART3_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_USART3_CLK_DISABLE();
/**USART3 GPIO Configuration
PB10 ------> USART3_TX
PB11 ------> USART3_RX
*/
HAL_GPIO_DeInit(GPIOB, GPIO_PIN_10|GPIO_PIN_11);
/* USART3 interrupt Deinit */
HAL_NVIC_DisableIRQ(USART3_IRQn);
/* USER CODE BEGIN USART3_MspDeInit 1 */
/* USER CODE END USART3_MspDeInit 1 */
}
}
/* USER CODE BEGIN 1 */
// 计算CRC校验码的函数
uint16_t calculateCRC(uint8_t* data, uint8_t length)
{
// 在此实现CRC计算逻辑
uint16_t crc = 0xFFFF;
for (int i = 0; i < length; i++) {
crc ^= data[i];
for (int j = 0; j < 8; j++) {
if (crc & 0x0001) {
crc >>= 1;
crc ^= 0xA001;
} else {
crc >>= 1;
}
}
}
return crc;
}
// 发送数据函数
void sendData(uint8_t* data, uint8_t length, uint8_t source)
{
// 计算CRC校验码
uint16_t crc = calculateCRC(data, length);
// 创建发送缓冲区,包括数据和CRC校验码
uint8_t uartTxBuffer[UART_BUFFER_SIZE];
uint8_t ack_RxBuffer[UART_BUFFER_SIZE];
uint8_t txIndex = 0;
uint8_t ack_rxIndex = 0;
// 添加开始标识
uartTxBuffer[txIndex++] = 0xAA; // 可根据需要修改为实际的开始标识
// 添加数据来源
uartTxBuffer[txIndex++] = source;
// 添加数据类型
uartTxBuffer[txIndex++] = 0x00; // 数据类型为0x00
// 添加数据长度
uartTxBuffer[txIndex++] = length & 0xFF;
uartTxBuffer[txIndex++] = (length >> 8) & 0xFF;
// 添加数据
memcpy(uartTxBuffer + txIndex, data, length);
txIndex += length;
// 添加校验和
uartTxBuffer[txIndex++] = crc & 0xFF;
uartTxBuffer[txIndex++] = (crc >> 8) & 0xFF;
// 添加结束标识
uartTxBuffer[txIndex++] = 0xBB;
uartTxBuffer[txIndex++] = 0xCC;
// 使用UART发送数据
//HAL_UART_Transmit(&huart3, uartTxBuffer, txIndex, HAL_MAX_DELAY);
for (int i = 0; i < txIndex; i++)
{
printf("%02x ", uartTxBuffer[i]);
}
printf("\n");
// 等待接收ACK超时时间
uint32_t startTime = HAL_GetTick();
// 接收ACK确认消息
while (1)
{
if (HAL_UART_Receive(&huart3, &ack_RxBuffer[ack_rxIndex], 1, HAL_MAX_DELAY) == HAL_OK)
{
// 检查是否接收到开始标识
if (ack_RxBuffer[ack_rxIndex] == 0xAA) // 可根据实际情况修改为实际的开始标识
{
if (ack_rxIndex >= 4) // 校验接收到的数据长度,确保长度足够包含相关字段
{
uint16_t length = ack_RxBuffer[2] + (ack_RxBuffer[3] << 8);
if (ack_rxIndex == length + 5) // 校验数据长度
{
CustomProtocol protocol;
// 解析接收到的数据
protocol.start_byte = ack_RxBuffer[0];
protocol.source = ack_RxBuffer[1];
protocol.length = length;
protocol.data = &ack_RxBuffer[4];
protocol.checksum = ack_RxBuffer[ack_rxIndex - 2] + (ack_RxBuffer[ack_rxIndex - 1] << 8);
protocol.end_byte[0] = ack_RxBuffer[ack_rxIndex - 6];
protocol.end_byte[1] = ack_RxBuffer[ack_rxIndex - 5];
// 校验校验和和结束标识
if (protocol.checksum == calculateCRC(protocol.data, protocol.length) &&
protocol.end_byte[0] == 0xBB && protocol.end_byte[1] == 0xCC)
{
// 判断数据类型是否为0xFF
if (protocol.data[0] == 0xFF)
{
// 接收到ACK确认消息,处理确认逻辑
handleAck();
break;
}
else
{
// 接收到无效数据,继续等待
continue;
}
} else
{
continue;
}
}
}
}
}
ack_rxIndex++;
}
// 检查是否超时
if (HAL_GetTick() - startTime >= TIMEOUT_MS)
{
timeoutFlag = 1;
//break;
}
// 处理超时重传
if (timeoutFlag)
{
for (int i = 0; i < MAX_RETRIES; i++)
{
timeoutFlag = 0;
// 重新发送数据
HAL_UART_Transmit(&huart3, uartTxBuffer, txIndex, HAL_MAX_DELAY);
// 等待接收ACK确认消息
// ...
}
// 达到最大重试次数后处理错误逻辑
handleTransmissionError();
}
}
void receiveData()
{
uint8_t uartRxBuffer[UART_BUFFER_SIZE];
uint16_t rxIndex = 0;
while (1)
{
if (HAL_UART_Receive(&huart3, &uartRxBuffer[rxIndex], 1, HAL_MAX_DELAY) == HAL_OK)
{
if (uartRxBuffer[rxIndex] == 0xAA) // 可根据实际情况修改为实际的开始标识
{
if (rxIndex >= 4) // 校验接收到的数据长度,确保长度足够包含相关字段
{
uint16_t length = uartRxBuffer[2] + (uartRxBuffer[3] << 8);
if (rxIndex == length + 5) // 校验数据长度
{
CustomProtocol protocol;
// 解析接收到的数据
protocol.start_byte = uartRxBuffer[0];
protocol.source = uartRxBuffer[1];
protocol.length = length;
protocol.data = &uartRxBuffer[4];
protocol.checksum = uartRxBuffer[rxIndex - 2] + (uartRxBuffer[rxIndex - 1] << 8);
protocol.end_byte[0] = uartRxBuffer[rxIndex - 6];
protocol.end_byte[1] = uartRxBuffer[rxIndex - 5];
// 校验校验和和结束标识
if (protocol.checksum == calculateCRC(protocol.data, protocol.length) &&
protocol.end_byte[0] == 0xBB && protocol.end_byte[1] == 0xCC)
{
// 判断数据类型是否为0xFF
if (protocol.data[0] != 0xFF)
{
// 发送确认消息
sendAck(0x01);
// 处理接收到的数据
processData(protocol.data, protocol.length);
}
else
{
// 数据类型为0xFF,忽略该数据
}
break;
} else
{
// 数据校验失败,处理错误逻辑
handleReceptionError();
break;
}
}
}
}
rxIndex++;
if (rxIndex >= UART_BUFFER_SIZE)
{
// 接收缓冲区已满,处理错误逻辑
handleReceptionError();
break;
}
}
}
}
// 发送错误处理函数
void handleTransmissionError()
{
// 在此实现重发机制或其他错误处理逻辑
printf("\r\nTransmissionError !\n\r");
}
void sendAck(uint8_t source)
{
// 创建发送缓冲区
uint8_t ackBuffer[UART_BUFFER_SIZE];
uint8_t txIndex = 0;
// 添加开始标识
ackBuffer[txIndex++] = 0xAA; // 可根据需要修改为实际的开始标识
// 添加数据来源
ackBuffer[txIndex++] = source;
// 添加数据长度
ackBuffer[txIndex++] = 0x01; // 数据长度为1字节
// 添加数据类型
ackBuffer[txIndex++] = 0xFF;
// 添加数据内容
ackBuffer[txIndex++] = 0x00; // 数据内容全为0
// 计算并添加校验和
uint16_t checksum = calculateCRC(&ackBuffer[4], txIndex - 4);
ackBuffer[txIndex++] = checksum & 0xFF; // 校验和低字节
ackBuffer[txIndex++] = (checksum >> 8) & 0xFF; // 校验和高字节
// 添加结束标识
ackBuffer[txIndex++] = 0xBB;
ackBuffer[txIndex++] = 0xCC;
// 使用UART发送数据
//HAL_UART_Transmit(&huart3, ackBuffer, txIndex, HAL_MAX_DELAY);
for (int i = 0; i < txIndex; i++)
{
printf("%02x", ackBuffer[i]);
}
}
// 处理接收到的数据的函数
void processData(uint8_t* data, uint8_t length)
{
// 将数据存储到数组中,并打印出来
uint8_t receivedData[UART_BUFFER_SIZE];
memcpy(receivedData, data, length);
for (int i = 0; i < length; i++)
{
printf("%02X ", receivedData[i]);
}
printf("\n");
}
// 接收错误处理函数
void handleReceptionError()
{
// 在此处理接收错误逻辑
printf("\r\nReceptionError !\n\r");
}
// 处理ACK确认消息的函数
void handleAck()
{
// 处理ACK确认消息的逻辑
printf("\r\nACK received !\n\r");
}
/* USER CODE END 1 */
发送的数据格式是对的,但是确认机制有点问题,无法正常ack确认
uint8_t sendDataBuffer[] = {0x01,0x02,0x03,0x04,0x05};
uint8_t sendDataLength = sizeof(sendDataBuffer);
uint8_t sendDataSource = 0x01;
sendData(sendDataBuffer, sendDataLength, sendDataSource);

问题不晓得出在哪了