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

 问题不晓得出在哪了