裸机stm32移植双串口modbus从机(附源码)

文章目录

  • [1 背景](#1 背景)
  • [2 移植过程](#2 移植过程)
    • [2.1 串口](#2.1 串口)
    • [2.2 定时器](#2.2 定时器)
    • [2.3 modbus从机](#2.3 modbus从机)
    • [2.4 主函数](#2.4 主函数)
  • [3 移植中的问题和解决](#3 移植中的问题和解决)
    • [3.1 超时检测](#3.1 超时检测)
    • [3.2 485控制引脚的初始化](#3.2 485控制引脚的初始化)
    • [3.3 发送函数](#3.3 发送函数)
  • [4 源码](#4 源码)

1 背景

由于要使用两个串口,之前移植的一个串口的modbus从机的程序就不方便用了,在原来的上面修改也比较麻烦。所以要重新移植。

2 移植过程

2.1 串口

我要使用的是f103的串口1和2,和要移植的工程中一样。

c 复制代码
//usart.c
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    usart.c
  * @brief   This file provides code for the configuration
  *          of the USART instances.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2025 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 */
#define UART1_RXSIZE	128
#define UART1_TXSIZE	128
#define UART2_RXSIZE	128	
#define UART2_TXSIZE	128	

UART_BUF uart1;
UART_BUF uart2;

uint8_t uart1_rx_buf[UART1_RXSIZE];
uint8_t uart1_tx_buf[UART1_TXSIZE];
uint8_t uart2_rx_buf[UART2_RXSIZE];
uint8_t uart2_tx_buf[UART2_TXSIZE];

uint8_t Rx1Buffer;
uint8_t Rx2Buffer;
/* USER CODE END 0 */

UART_HandleTypeDef huart1;
UART_HandleTypeDef huart2;

/* USART1 init function */

void MX_USART1_UART_Init(void)
{

  /* USER CODE BEGIN USART1_Init 0 */

  /* USER CODE END USART1_Init 0 */

  /* USER CODE BEGIN USART1_Init 1 */

  /* USER CODE END USART1_Init 1 */
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 19200;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART1_Init 2 */

  /* USER CODE END USART1_Init 2 */

}
/* USART2 init function */

void MX_USART2_UART_Init(void)
{

  /* USER CODE BEGIN USART2_Init 0 */

  /* USER CODE END USART2_Init 0 */

  /* USER CODE BEGIN USART2_Init 1 */

  /* USER CODE END USART2_Init 1 */
  huart2.Instance = USART2;
  huart2.Init.BaudRate = 19200;
  huart2.Init.WordLength = UART_WORDLENGTH_8B;
  huart2.Init.StopBits = UART_STOPBITS_1;
  huart2.Init.Parity = UART_PARITY_NONE;
  huart2.Init.Mode = UART_MODE_TX_RX;
  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART2_Init 2 */

  /* USER CODE END USART2_Init 2 */

}

void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(uartHandle->Instance==USART1)
  {
  /* USER CODE BEGIN USART1_MspInit 0 */

  /* USER CODE END USART1_MspInit 0 */
    /* USART1 clock enable */
    __HAL_RCC_USART1_CLK_ENABLE();

    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**USART1 GPIO Configuration
    PA9     ------> USART1_TX
    PA10     ------> USART1_RX
    */
    GPIO_InitStruct.Pin = RS485_TX1_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(RS485_TX1_GPIO_Port, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = RS485_RX1_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(RS485_RX1_GPIO_Port, &GPIO_InitStruct);

    /* USART1 interrupt Init */
    HAL_NVIC_SetPriority(USART1_IRQn, 5, 0);
    HAL_NVIC_EnableIRQ(USART1_IRQn);
  /* USER CODE BEGIN USART1_MspInit 1 */

  /* USER CODE END USART1_MspInit 1 */
  }
  else if(uartHandle->Instance==USART2)
  {
  /* USER CODE BEGIN USART2_MspInit 0 */

  /* USER CODE END USART2_MspInit 0 */
    /* USART2 clock enable */
    __HAL_RCC_USART2_CLK_ENABLE();

    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**USART2 GPIO Configuration
    PA2     ------> USART2_TX
    PA3     ------> USART2_RX
    */
    GPIO_InitStruct.Pin = RS485_TX2_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(RS485_TX2_GPIO_Port, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = RS485_RX2_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(RS485_RX2_GPIO_Port, &GPIO_InitStruct);

    /* USART2 interrupt Init */
    HAL_NVIC_SetPriority(USART2_IRQn, 5, 0);
    HAL_NVIC_EnableIRQ(USART2_IRQn);
  /* USER CODE BEGIN USART2_MspInit 1 */

  /* USER CODE END USART2_MspInit 1 */
  }
}

void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
{

  if(uartHandle->Instance==USART1)
  {
  /* USER CODE BEGIN USART1_MspDeInit 0 */

  /* USER CODE END USART1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_USART1_CLK_DISABLE();

    /**USART1 GPIO Configuration
    PA9     ------> USART1_TX
    PA10     ------> USART1_RX
    */
    HAL_GPIO_DeInit(GPIOA, RS485_TX1_Pin|RS485_RX1_Pin);

    /* USART1 interrupt Deinit */
    HAL_NVIC_DisableIRQ(USART1_IRQn);
  /* USER CODE BEGIN USART1_MspDeInit 1 */

  /* USER CODE END USART1_MspDeInit 1 */
  }
  else if(uartHandle->Instance==USART2)
  {
  /* USER CODE BEGIN USART2_MspDeInit 0 */

  /* USER CODE END USART2_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_USART2_CLK_DISABLE();

    /**USART2 GPIO Configuration
    PA2     ------> USART2_TX
    PA3     ------> USART2_RX
    */
    HAL_GPIO_DeInit(GPIOA, RS485_TX2_Pin|RS485_RX2_Pin);

    /* USART2 interrupt Deinit */
    HAL_NVIC_DisableIRQ(USART2_IRQn);
  /* USER CODE BEGIN USART2_MspDeInit 1 */

  /* USER CODE END USART2_MspDeInit 1 */
  }
}

/* USER CODE BEGIN 1 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart )
{
	if(huart->Instance == USART1)
	{
 		if(uart1.rx_flag == 1)
		{
			return ;
		}
		if(uart1.rx_buf_cnt >= UART1_RXSIZE-1)	//???????????????????
		{
			uart1.rx_buf_cnt = 0;
			memset(uart1.rx_buf, 0x00, sizeof(*uart1.rx_buf));
		}
		else									//????????
		{
			uart1.rx_buf[uart1.rx_buf_cnt++] = Rx1Buffer;	//????????洢??rx_buf
			HAL_TIM_Base_Stop_IT(&htim7);
			__HAL_TIM_SET_COUNTER(&htim7, 0);
			HAL_TIM_Base_Start_IT(&htim7);		//???????7??????????????????
		}
		__HAL_UART_CLEAR_OREFLAG(huart);
		HAL_UART_Receive_IT(huart, (uint8_t *)&Rx1Buffer, 1);
	}else
	if(huart->Instance == USART2)
	{
		if(uart2.rx_flag == 1)
		{
			return ;
		}
		if(uart2.rx_buf_cnt >= UART2_RXSIZE-1)	//???????????????????
		{
			uart2.rx_buf_cnt = 0;
			memset(uart2.rx_buf, 0x00, sizeof(*uart2.rx_buf));
		}
		else									//????????
		{
			uart2.rx_buf[uart2.rx_buf_cnt++] = Rx2Buffer;	//????????洢??rx_buf
			HAL_TIM_Base_Stop_IT(&htim6);
			__HAL_TIM_SET_COUNTER(&htim6, 0);
			HAL_TIM_Base_Start_IT(&htim6);		//???????7??????????????????
		}
		__HAL_UART_CLEAR_OREFLAG(huart); //ORE-err
		HAL_UART_Receive_IT(huart, (uint8_t *)&Rx2Buffer, 1);
	}
}

/*****************************??UART_BUF????????uart1???**********************/
void E_USART_INIT(UART_HandleTypeDef *huart ,UART_BUF* uartbuf)
{
	if(huart->Instance == USART1)
	{
		uartbuf->rx_buf = uart1_rx_buf;	//????????????????
		uartbuf->rx_buf_cnt = 0;
		uartbuf->rx_size = 0;
		uartbuf->rx_flag = 0;
		
		uartbuf->tx_buf = uart1_rx_buf;	//????????????????
		uartbuf->tx_buf_cnt = UART1_TXSIZE;
		uartbuf->tx_size = 0;	
		
		huart1.Instance = USART1;
		huart1.Init.BaudRate = 115200;
		huart1.Init.WordLength = UART_WORDLENGTH_8B;
		huart1.Init.StopBits = UART_STOPBITS_1;
		huart1.Init.Parity = UART_PARITY_NONE;
		huart1.Init.Mode = UART_MODE_TX_RX;
		huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
		huart1.Init.OverSampling = UART_OVERSAMPLING_16;
		if (HAL_UART_Init(&huart1) != HAL_OK)
		{
			Error_Handler();
		}

		HAL_UART_Receive_IT(huart, (uint8_t *)&Rx1Buffer, 1);	//?????????ж?
	}else
	if(huart->Instance == USART2)
	{
		uartbuf->rx_buf = uart2_rx_buf;	//????????????????
		uartbuf->rx_buf_cnt = 0;
		uartbuf->rx_size = 0;
		uartbuf->rx_flag = 0;
		
		uartbuf->tx_buf = uart2_rx_buf;	//????????????????
		uartbuf->tx_buf_cnt = UART2_TXSIZE;
		uartbuf->tx_size = 0;		
		
		huart2.Instance = USART2;
		huart2.Init.BaudRate = 115200;		
		huart2.Init.WordLength = UART_WORDLENGTH_8B;
		huart2.Init.StopBits = UART_STOPBITS_1;
		huart2.Init.Parity = UART_PARITY_NONE;
		huart2.Init.Mode = UART_MODE_TX_RX;
		huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
		huart2.Init.OverSampling = UART_OVERSAMPLING_16;
		if (HAL_UART_Init(&huart2) != HAL_OK)
		{
			Error_Handler();
		}
			
		HAL_UART_Receive_IT(huart, (uint8_t *)&Rx2Buffer, 1);	//?????????ж?
	}

}

/* USER CODE END 1 */
c 复制代码
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    usart.h
  * @brief   This file contains all the function prototypes for
  *          the usart.c file
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2025 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 */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __USART_H__
#define __USART_H__

#ifdef __cplusplus
extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* USER CODE BEGIN Includes */
#include "string.h"
#include "tim.h"
/* USER CODE END Includes */

extern UART_HandleTypeDef huart1;

extern UART_HandleTypeDef huart2;

/* USER CODE BEGIN Private defines */
#define RS485_TX2_Pin GPIO_PIN_2
#define RS485_TX2_GPIO_Port GPIOA
#define RS485_RX2_Pin GPIO_PIN_3
#define RS485_RX2_GPIO_Port GPIOA
#define RS485_EN2_Pin GPIO_PIN_8
#define RS485_EN2_GPIO_Port GPIOC
#define RS485_EN1_Pin GPIO_PIN_9
#define RS485_EN1_GPIO_Port GPIOC
#define RS485_TX1_Pin GPIO_PIN_9
#define RS485_TX1_GPIO_Port GPIOA
#define RS485_RX1_Pin GPIO_PIN_10
#define RS485_RX1_GPIO_Port GPIOA	
	
	
typedef struct
{
	uint8_t *rx_buf;			//接收缓冲数组
	uint16_t rx_buf_cnt;	//接收缓冲计数值
	uint16_t rx_size;			//接收数据大小
	uint8_t  rx_flag;			//接收完成标志位
	
	uint8_t *tx_buf;			//发送缓冲数组
	uint16_t tx_buf_cnt;	//发送缓冲计数值
	uint16_t tx_size;			//实际发送数据大小
}UART_BUF;							//串口结构体

extern UART_BUF uart1;		//串口结构体实体
extern UART_BUF uart2;

/* USER CODE END Private defines */

void MX_USART1_UART_Init(void);
void MX_USART2_UART_Init(void);

/* USER CODE BEGIN Prototypes */
extern void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart );
extern void E_USART_INIT(UART_HandleTypeDef *huart ,UART_BUF* uartbuf);
/* USER CODE END Prototypes */

#ifdef __cplusplus
}
#endif

#endif /* __USART_H__ */

2.2 定时器

使用定时器6和7

c 复制代码
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    tim.c
  * @brief   This file provides code for the configuration
  *          of the TIM instances.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2025 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 "tim.h"

/* USER CODE BEGIN 0 */
#include "usart.h"

/* USER CODE END 0 */

TIM_HandleTypeDef htim2;
TIM_HandleTypeDef htim3;
TIM_HandleTypeDef htim4;
TIM_HandleTypeDef htim5;
TIM_HandleTypeDef htim6;
TIM_HandleTypeDef htim7;
TIM_HandleTypeDef htim8;

/* TIM2 init function */
void MX_TIM2_Init(void)
{

  /* USER CODE BEGIN TIM2_Init 0 */

  /* USER CODE END TIM2_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};

  /* USER CODE BEGIN TIM2_Init 1 */

  /* USER CODE END TIM2_Init 1 */
  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 71;
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = 99;
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM2_Init 2 */

  /* USER CODE END TIM2_Init 2 */

}
/* TIM3 init function */
void MX_TIM3_Init(void)
{

  /* USER CODE BEGIN TIM3_Init 0 */

  /* USER CODE END TIM3_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};

  /* USER CODE BEGIN TIM3_Init 1 */

  /* USER CODE END TIM3_Init 1 */
  htim3.Instance = TIM3;
  htim3.Init.Prescaler = 71;
  htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim3.Init.Period = 9;
  htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM3_Init 2 */

  /* USER CODE END TIM3_Init 2 */

}
/* TIM4 init function */
void MX_TIM4_Init(void)
{

  /* USER CODE BEGIN TIM4_Init 0 */

  /* USER CODE END TIM4_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};

  /* USER CODE BEGIN TIM4_Init 1 */

  /* USER CODE END TIM4_Init 1 */
  htim4.Instance = TIM4;
  htim4.Init.Prescaler = 7199;
  htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim4.Init.Period = 35;
  htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim4) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM4_Init 2 */

  /* USER CODE END TIM4_Init 2 */

}
/* TIM5 init function */
void MX_TIM5_Init(void)
{

  /* USER CODE BEGIN TIM5_Init 0 */

  /* USER CODE END TIM5_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};

  /* USER CODE BEGIN TIM5_Init 1 */

  /* USER CODE END TIM5_Init 1 */
  htim5.Instance = TIM5;
  htim5.Init.Prescaler = 0;
  htim5.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim5.Init.Period = 65535;
  htim5.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim5.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim5) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim5, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim5, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM5_Init 2 */

  /* USER CODE END TIM5_Init 2 */

}
/* TIM6 init function */
void MX_TIM6_Init(void)
{

  /* USER CODE BEGIN TIM6_Init 0 */

  /* USER CODE END TIM6_Init 0 */

  TIM_MasterConfigTypeDef sMasterConfig = {0};

  /* USER CODE BEGIN TIM6_Init 1 */

  /* USER CODE END TIM6_Init 1 */
  htim6.Instance = TIM6;
  htim6.Init.Prescaler = 7199;
  htim6.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim6.Init.Period = 35;
  htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim6) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim6, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM6_Init 2 */

  /* USER CODE END TIM6_Init 2 */

}
/* TIM7 init function */
void MX_TIM7_Init(void)
{

  /* USER CODE BEGIN TIM7_Init 0 */

  /* USER CODE END TIM7_Init 0 */

  TIM_MasterConfigTypeDef sMasterConfig = {0};

  /* USER CODE BEGIN TIM7_Init 1 */

  /* USER CODE END TIM7_Init 1 */
  htim7.Instance = TIM7;
  htim7.Init.Prescaler = 7199;
  htim7.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim7.Init.Period = 35;
  htim7.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim7) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim7, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM7_Init 2 */

  /* USER CODE END TIM7_Init 2 */

}
/* TIM8 init function */
void MX_TIM8_Init(void)
{

  /* USER CODE BEGIN TIM8_Init 0 */

  /* USER CODE END TIM8_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};

  /* USER CODE BEGIN TIM8_Init 1 */

  /* USER CODE END TIM8_Init 1 */
  htim8.Instance = TIM8;
  htim8.Init.Prescaler = 0;
  htim8.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim8.Init.Period = 65535;
  htim8.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim8.Init.RepetitionCounter = 0;
  htim8.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim8) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim8, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim8, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM8_Init 2 */

  /* USER CODE END TIM8_Init 2 */

}

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
{

  if(tim_baseHandle->Instance==TIM2)
  {
  /* USER CODE BEGIN TIM2_MspInit 0 */

  /* USER CODE END TIM2_MspInit 0 */
    /* TIM2 clock enable */
    __HAL_RCC_TIM2_CLK_ENABLE();

    /* TIM2 interrupt Init */
    HAL_NVIC_SetPriority(TIM2_IRQn, 5, 0);
    HAL_NVIC_EnableIRQ(TIM2_IRQn);
  /* USER CODE BEGIN TIM2_MspInit 1 */

  /* USER CODE END TIM2_MspInit 1 */
  }
  else if(tim_baseHandle->Instance==TIM3)
  {
  /* USER CODE BEGIN TIM3_MspInit 0 */

  /* USER CODE END TIM3_MspInit 0 */
    /* TIM3 clock enable */
    __HAL_RCC_TIM3_CLK_ENABLE();

    /* TIM3 interrupt Init */
    HAL_NVIC_SetPriority(TIM3_IRQn, 5, 0);
    HAL_NVIC_EnableIRQ(TIM3_IRQn);
  /* USER CODE BEGIN TIM3_MspInit 1 */

  /* USER CODE END TIM3_MspInit 1 */
  }
  else if(tim_baseHandle->Instance==TIM4)
  {
  /* USER CODE BEGIN TIM4_MspInit 0 */

  /* USER CODE END TIM4_MspInit 0 */
    /* TIM4 clock enable */
    __HAL_RCC_TIM4_CLK_ENABLE();

    /* TIM4 interrupt Init */
    HAL_NVIC_SetPriority(TIM4_IRQn, 5, 0);
    HAL_NVIC_EnableIRQ(TIM4_IRQn);
  /* USER CODE BEGIN TIM4_MspInit 1 */

  /* USER CODE END TIM4_MspInit 1 */
  }
  else if(tim_baseHandle->Instance==TIM5)
  {
  /* USER CODE BEGIN TIM5_MspInit 0 */

  /* USER CODE END TIM5_MspInit 0 */
    /* TIM5 clock enable */
    __HAL_RCC_TIM5_CLK_ENABLE();

    /* TIM5 interrupt Init */
    HAL_NVIC_SetPriority(TIM5_IRQn, 5, 0);
    HAL_NVIC_EnableIRQ(TIM5_IRQn);
  /* USER CODE BEGIN TIM5_MspInit 1 */

  /* USER CODE END TIM5_MspInit 1 */
  }
  else if(tim_baseHandle->Instance==TIM6)
  {
  /* USER CODE BEGIN TIM6_MspInit 0 */

  /* USER CODE END TIM6_MspInit 0 */
    /* TIM6 clock enable */
    __HAL_RCC_TIM6_CLK_ENABLE();

    /* TIM6 interrupt Init */
    HAL_NVIC_SetPriority(TIM6_IRQn, 5, 0);
    HAL_NVIC_EnableIRQ(TIM6_IRQn);
  /* USER CODE BEGIN TIM6_MspInit 1 */

  /* USER CODE END TIM6_MspInit 1 */
  }
  else if(tim_baseHandle->Instance==TIM7)
  {
  /* USER CODE BEGIN TIM7_MspInit 0 */

  /* USER CODE END TIM7_MspInit 0 */
    /* TIM7 clock enable */
    __HAL_RCC_TIM7_CLK_ENABLE();

    /* TIM7 interrupt Init */
    HAL_NVIC_SetPriority(TIM7_IRQn, 5, 0);
    HAL_NVIC_EnableIRQ(TIM7_IRQn);
  /* USER CODE BEGIN TIM7_MspInit 1 */

  /* USER CODE END TIM7_MspInit 1 */
  }
  else if(tim_baseHandle->Instance==TIM8)
  {
  /* USER CODE BEGIN TIM8_MspInit 0 */

  /* USER CODE END TIM8_MspInit 0 */
    /* TIM8 clock enable */
    __HAL_RCC_TIM8_CLK_ENABLE();
  /* USER CODE BEGIN TIM8_MspInit 1 */

  /* USER CODE END TIM8_MspInit 1 */
  }
}

void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle)
{

  if(tim_baseHandle->Instance==TIM2)
  {
  /* USER CODE BEGIN TIM2_MspDeInit 0 */

  /* USER CODE END TIM2_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_TIM2_CLK_DISABLE();

    /* TIM2 interrupt Deinit */
    HAL_NVIC_DisableIRQ(TIM2_IRQn);
  /* USER CODE BEGIN TIM2_MspDeInit 1 */

  /* USER CODE END TIM2_MspDeInit 1 */
  }
  else if(tim_baseHandle->Instance==TIM3)
  {
  /* USER CODE BEGIN TIM3_MspDeInit 0 */

  /* USER CODE END TIM3_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_TIM3_CLK_DISABLE();

    /* TIM3 interrupt Deinit */
    HAL_NVIC_DisableIRQ(TIM3_IRQn);
  /* USER CODE BEGIN TIM3_MspDeInit 1 */

  /* USER CODE END TIM3_MspDeInit 1 */
  }
  else if(tim_baseHandle->Instance==TIM4)
  {
  /* USER CODE BEGIN TIM4_MspDeInit 0 */

  /* USER CODE END TIM4_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_TIM4_CLK_DISABLE();

    /* TIM4 interrupt Deinit */
    HAL_NVIC_DisableIRQ(TIM4_IRQn);
  /* USER CODE BEGIN TIM4_MspDeInit 1 */

  /* USER CODE END TIM4_MspDeInit 1 */
  }
  else if(tim_baseHandle->Instance==TIM5)
  {
  /* USER CODE BEGIN TIM5_MspDeInit 0 */

  /* USER CODE END TIM5_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_TIM5_CLK_DISABLE();

    /* TIM5 interrupt Deinit */
    HAL_NVIC_DisableIRQ(TIM5_IRQn);
  /* USER CODE BEGIN TIM5_MspDeInit 1 */

  /* USER CODE END TIM5_MspDeInit 1 */
  }
  else if(tim_baseHandle->Instance==TIM6)
  {
  /* USER CODE BEGIN TIM6_MspDeInit 0 */

  /* USER CODE END TIM6_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_TIM6_CLK_DISABLE();

    /* TIM6 interrupt Deinit */
    HAL_NVIC_DisableIRQ(TIM6_IRQn);
  /* USER CODE BEGIN TIM6_MspDeInit 1 */

  /* USER CODE END TIM6_MspDeInit 1 */
  }
  else if(tim_baseHandle->Instance==TIM7)
  {
  /* USER CODE BEGIN TIM7_MspDeInit 0 */

  /* USER CODE END TIM7_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_TIM7_CLK_DISABLE();

    /* TIM7 interrupt Deinit */
    HAL_NVIC_DisableIRQ(TIM7_IRQn);
  /* USER CODE BEGIN TIM7_MspDeInit 1 */

  /* USER CODE END TIM7_MspDeInit 1 */
  }
  else if(tim_baseHandle->Instance==TIM8)
  {
  /* USER CODE BEGIN TIM8_MspDeInit 0 */

  /* USER CODE END TIM8_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_TIM8_CLK_DISABLE();
  /* USER CODE BEGIN TIM8_MspDeInit 1 */
  /* USER CODE END TIM8_MspDeInit 1 */
  }
}

/* USER CODE BEGIN 1 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  if(htim == &htim7)
  {
    __HAL_TIM_CLEAR_FLAG(&htim7, TIM_FLAG_UPDATE);
    HAL_TIM_Base_Stop_IT(&htim7);
    uart1.rx_size = uart1.rx_buf_cnt;
    uart1.rx_buf_cnt = 0;
    if(uart1.rx_buf[0] == 1)
    {
      uart1.rx_flag = 1;
    }
    else
    {
      uart1.rx_flag = 0;
    }
  }
  else if(htim == &htim6)
  {
    __HAL_TIM_CLEAR_FLAG(&htim6, TIM_FLAG_UPDATE);
    HAL_TIM_Base_Stop_IT(&htim6);
    uart2.rx_size = uart2.rx_buf_cnt;
    uart2.rx_buf_cnt = 0;
    if(uart2.rx_buf[0] == 1)
    {
      uart2.rx_flag = 1;
    }
    else
    {
      uart2.rx_flag = 0;
    }
  }
}

/* USER CODE END 1 */
c 复制代码
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    tim.h
  * @brief   This file contains all the function prototypes for
  *          the tim.c file
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2025 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 */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __TIM_H__
#define __TIM_H__

#ifdef __cplusplus
extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

extern TIM_HandleTypeDef htim2;

extern TIM_HandleTypeDef htim3;

extern TIM_HandleTypeDef htim4;

extern TIM_HandleTypeDef htim5;

extern TIM_HandleTypeDef htim6;

extern TIM_HandleTypeDef htim7;

extern TIM_HandleTypeDef htim8;

/* USER CODE BEGIN Private defines */

/* USER CODE END Private defines */

void MX_TIM2_Init(void);
void MX_TIM3_Init(void);
void MX_TIM4_Init(void);
void MX_TIM5_Init(void);
void MX_TIM6_Init(void);
void MX_TIM7_Init(void);
void MX_TIM8_Init(void);

/* USER CODE BEGIN Prototypes */
extern void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);
/* USER CODE END Prototypes */

#ifdef __cplusplus
}
#endif

#endif /* __TIM_H__ */

2.3 modbus从机

这里我的串口1是通过了485芯片,低电平发送,高电平接收

c 复制代码
#include "Modbus.h"
#include "string.h"

/***********调试***************/
//调试03发送次数
uint8_t tx_count=0;
char message[]="Hello world";
char message1[]="Hello usart1";
char message2[]="Hello usart2";
uint8_t UART1_high_count=0;
uint8_t UART1_low_count=0;
/*************调试*************/

uint8_t  CoilState[(MAX_DIS_NUM + 7) / 8] = {0x00};
uint8_t  DisState [(MAX_DIS_NUM + 7) / 8] = {0xAA};
uint16_t InputReg[MAX_INPUT_REG_NUM] = {0x0000,0x0000};//{0xAA55,0x55AA}; 
uint16_t HoldReg[MAX_HOLD_REG_NUM] =  {0x0000,0x0000};//{0xAA55, 0x55AA};

void MODBUS_ERRFunction(UART_HandleTypeDef* uartHandle,UART_BUF* uartbuf ,uint8_t uCmdCode, uint8_t uErrorCode);
void RS485_enable_send(UART_HandleTypeDef *uartHandle);
/*******************************************************************************
函数名称 : ModbusCRC16
功    能 : CRC校验
参    数 : ptr--校验数组指针  len--校验数据长度
返 回 值 : CRC校验码,双字节
*******************************************************************************/
uint16_t ModbusCRC16(uint8_t *ptr, uint16_t len)
{
    uint8_t i;
    uint16_t crc = ~0x00;

    if((ptr == 0) || (len == 0xFFFF)) return crc;

    while(len--)
    {
        crc ^= *ptr++;
        for(i = 0; i < 8; i++)
        {
            if(crc & 0x01)
            {
                crc >>= 1;
                crc ^= 0xA001;
            }
            else
            {
                crc >>= 1;
            }
        }
    }
    return(crc);
}

void GetOneCoilVal(uint16_t wCoilAddr, uint8_t *pCoilVal)
{
	uint8_t uVal;
	
	uVal = CoilState[(wCoilAddr - COIL_ADD_MIN) / 8 ];
	if(uVal & ( 1 << ((wCoilAddr - COIL_ADD_MIN) % 8 )))
	{
		*pCoilVal = 0x01;
	}
	else
	{
		*pCoilVal = 0x00;
	}
}


/*******************************************************************************
函数名称 : ReadCoilStateFUNC
功    能 : 功能码:0x01,读取线圈
参    数 : 无
返 回 值 : 无
*发送:[硬件地址][01][线圈起始地址高][线圈起始地址低][线圈数量高][线圈数量低][CRC低][CRC高]
*返回:[硬件地址][01][字节长度][线圈值][线圈值][线圈值][CRC低][CRC高]
*******************************************************************************/
void ReadCoilStateFUNC(UART_HandleTypeDef* uartHandle,UART_BUF* uartbuf , uint8_t * upRxdbuf, uint16_t wRxdLen)
{
	uint16_t wCoilStartAddr,wCoilNum,wTotalCoilNum,CRC16Temp;
    uint8_t  i,k,uCommIndexNum = 0,uByteCount,uCoilVal,uErrorCode,uExit = 0;
	uint8_t  upTxdbuf[50];

    wCoilStartAddr  = MAKEWORD(upRxdbuf[1], upRxdbuf[0]); //获取线圈起始地址
    wCoilNum        = MAKEWORD(upRxdbuf[3], upRxdbuf[2]); //获取线圈个数

	if((wCoilNum >= 0x0001) || (wCoilNum <= MAX_COIL_NUM))
	{
		if((wCoilStartAddr <= COIL_ADD_MAX) &&
			(wCoilNum + wCoilStartAddr <= COIL_ADD_MAX + 1))
		{
			uByteCount = (wCoilNum + 7) / 8;    //返回数据字节个数
	
			upTxdbuf[uCommIndexNum ++] = uartbuf->rx_buf[0];    //LOCAL_ADDRESS;
            upTxdbuf[uCommIndexNum ++] = ReadCoilState;
			upTxdbuf[uCommIndexNum ++] = uByteCount;
			
			wTotalCoilNum = 0;
            for(k = 0; k < uByteCount; k++)
			{
				upTxdbuf[uCommIndexNum] = 0;
				for(i = 0; i < 8; i++)
				{
					GetOneCoilVal(wCoilStartAddr + wTotalCoilNum,&uCoilVal);
					upTxdbuf[uCommIndexNum] |= uCoilVal << i;
 
					wTotalCoilNum ++;
					if(wTotalCoilNum >= wCoilNum)
					{
						 uExit = 1;
						 break;
					}
				}
				
				uCommIndexNum ++;
				
				if(uExit == 1)
				{
					break;
				}
			}

			CRC16Temp = ModbusCRC16(upTxdbuf, uCommIndexNum);
			upTxdbuf[uCommIndexNum ++] = (uint8_t)(CRC16Temp & 0xFF);
			upTxdbuf[uCommIndexNum ++] = (uint8_t)(CRC16Temp >> 8);
			RS485_enable_send(uartHandle);
			uartbuf->tx_size = (uCommIndexNum <= uartbuf->tx_buf_cnt ? uCommIndexNum : uartbuf->tx_buf_cnt);
			memcpy(uartbuf->tx_buf, upTxdbuf, uartbuf->tx_size);
			HAL_UART_Transmit_IT(uartHandle, uartbuf->tx_buf, uartbuf->tx_size);
			
			return;
		}
		else
		{
			uErrorCode = MB_EX_ILLEGAL_DATA_ADDRESS;
		}
	}
	else 
	{
		 uErrorCode = MB_EX_ILLEGAL_DATA_VALUE;
	}

    MODBUS_ERRFunction(uartHandle , uartbuf , ReadCoilState, uErrorCode);
    return;
}

void GetOneDisInputVal(uint16_t wDisInputAddr, uint8_t *pDisInputVal)
{
	uint8_t uVal;
	
	uVal = DisState[(wDisInputAddr - DIS_ADD_MIN) / 8 ];
	if(uVal & ( 1 << ((wDisInputAddr - DIS_ADD_MIN) % 8 )))
	{
		*pDisInputVal = 0x01;
	}
	else
	{
		*pDisInputVal = 0x00;
	}
}

/*******************************************************************************
函数名称 : ReadDisInputStateFUNC
功    能 : 功能码:0x02,读取离散量
参    数 : 无
返 回 值 : 无
*发送:[硬件地址][02][离散量起始地址高][离散量起始地址低][离散量数量高][离散量数量低][CRC低][CRC高]
*返回:[硬件地址][02][字节长度][离散量值][离散量值][离散量值][CRC低][CRC高]
*******************************************************************************/
void ReadDisInputStateFUNC(UART_HandleTypeDef* uartHandle,UART_BUF* uartbuf , uint8_t * upRxdbuf, uint16_t wRxdLen)
{
    uint16_t wDisStartAddr,wDisNum,wTotalDisNum,CRC16Temp;
    uint8_t  i,k,uCommIndexNum = 0,uByteCount,uDisVal,uErrorCode,uExit = 0;
		uint8_t  upTxdbuf[50];

    wDisStartAddr  = MAKEWORD(upRxdbuf[1], upRxdbuf[0]); //获取离散量起始地址
    wDisNum        = MAKEWORD(upRxdbuf[3], upRxdbuf[2]); //获取离散量个数

	if((wDisNum >= 0x0001) || (wDisNum <= MAX_DIS_NUM))
	{
		if((wDisStartAddr <= DIS_ADD_MAX) &&
			(wDisNum + wDisStartAddr <= DIS_ADD_MAX + 1))
		{
			uByteCount = (wDisNum + 7) / 8;    //返回数据字节个数
	
			upTxdbuf[uCommIndexNum ++] = uartbuf->rx_buf[0];    //LOCAL_ADDRESS;
            upTxdbuf[uCommIndexNum ++] = ReadDisInputState;
			upTxdbuf[uCommIndexNum ++] = uByteCount;
			
			wTotalDisNum = 0;
            for(k = 0; k < uByteCount; k++)
			{
				upTxdbuf[uCommIndexNum] = 0;
				for(i = 0; i < 8; i++)
				{
					GetOneDisInputVal(wDisStartAddr + wTotalDisNum,&uDisVal);
					upTxdbuf[uCommIndexNum] |= uDisVal << i;
 
					wTotalDisNum ++;
					if(wTotalDisNum >= wDisNum)
					{
						 uExit = 1;
						 break;
					}
				}
				
				uCommIndexNum ++;
				
				if(uExit == 1)
				{
					break;
				}
			}
            CRC16Temp = ModbusCRC16(upTxdbuf, uCommIndexNum);
            upTxdbuf[uCommIndexNum ++] = (uint8_t)(CRC16Temp & 0xFF);
            upTxdbuf[uCommIndexNum ++] = (uint8_t)(CRC16Temp >> 8);
						RS485_enable_send(uartHandle);
            uartbuf->tx_size = (uCommIndexNum <= uartbuf->tx_buf_cnt ? uCommIndexNum : uartbuf->tx_buf_cnt);
            memcpy(uartbuf->tx_buf, upTxdbuf, uartbuf->tx_size);
            HAL_UART_Transmit_IT(uartHandle, uartbuf->tx_buf, uartbuf->tx_size);
			
			return;
		}
		else
		{
			uErrorCode = MB_EX_ILLEGAL_DATA_ADDRESS;
		}
	}
	else 
	{
		 uErrorCode = MB_EX_ILLEGAL_DATA_VALUE;
	}

    MODBUS_ERRFunction(uartHandle , uartbuf , ReadDisInputState, uErrorCode);
    return;	
}

/*******************************************************************************
函数名称 : GetHoldRegData
功    能 : 获取RegAdd的数据
参    数 : u16 RegAdd
返 回 值 : 两字节寄存器数据
*******************************************************************************/
uint16_t GetHoldRegData(uint16_t RegAdd)
{
    int16_t wRegValue;

    wRegValue = HoldReg[RegAdd - HOLD_REG_ADD_MIN];

    return wRegValue;
}

/*******************************************************************************
函数名称 : ReadHoldRegFUNC
功    能 : 功能码:0x03,读取保持寄存器
参    数 : 无
返 回 值 : 无
*发送:[硬件地址][03][起始地址高][起始地址低][总寄存器数高][总寄存器数低][CRC低][CRC高]
*返回:[硬件地址][03][字节数][寄存器0高][寄存器0低][寄存器1高][寄存器1低][寄存器n高][寄存器n低][CRC低][CRC高]
*******************************************************************************/
void ReadHoldRegFUNC(UART_HandleTypeDef* uartHandle,UART_BUF* uartbuf , uint8_t * upRxdbuf, uint16_t wRxdLen)
{
    uint16_t wRegStartAdd, wRegLen, i, wRegValue, CRC16Temp;
    uint8_t  uErrorCode, uCommIndexNum = 0;
    uint8_t  upTxdbuf[50];

    if(upRxdbuf == 0)  return;

    wRegStartAdd = MAKEWORD(upRxdbuf[1], upRxdbuf[0]); //获取寄存器起始地址
    wRegLen      = MAKEWORD(upRxdbuf[3], upRxdbuf[2]); //获取读取寄存器长度

    if((wRegLen >= 0x01) && (wRegLen <= MAX_HOLD_REG_NUM))
    {
        if(((wRegStartAdd <= HOLD_REG_ADD_MAX)) &&
           ((wRegStartAdd + wRegLen) <= HOLD_REG_ADD_MAX + 1))
        {
            upTxdbuf[uCommIndexNum ++] = uartbuf->rx_buf[0];    //LOCAL_ADDRESS;
            upTxdbuf[uCommIndexNum ++] = ReadHoldReg;
            upTxdbuf[uCommIndexNum ++] = wRegLen * 2;

            for(i = 0; i < wRegLen; i++)
            {
                //获取16位数据并返回
                wRegValue = GetHoldRegData(wRegStartAdd + i);
                upTxdbuf[uCommIndexNum ++] = (uint8_t)(wRegValue >> 8);
                upTxdbuf[uCommIndexNum ++] = (uint8_t)(wRegValue & 0xFF);
            }

            CRC16Temp = ModbusCRC16(upTxdbuf, uCommIndexNum);
            upTxdbuf[uCommIndexNum ++] = (uint8_t)(CRC16Temp & 0xFF); // crc16低字节在前
            upTxdbuf[uCommIndexNum ++] = (uint8_t)(CRC16Temp >> 8);   // crc16高字节在后
						RS485_enable_send(uartHandle);
            uartbuf->tx_size = (uCommIndexNum <= uartbuf->tx_buf_cnt ? uCommIndexNum : uartbuf->tx_buf_cnt);
            memcpy(uartbuf->tx_buf, upTxdbuf, uartbuf->tx_size);
//            HAL_UART_Transmit_IT(uartHandle, uartbuf->tx_buf, uartbuf->tx_size);
						HAL_UART_Transmit(uartHandle, uartbuf->tx_buf, uartbuf->tx_size,100);
						//调试

//						HAL_UART_Transmit_IT(&huart1,(uint8_t*)message1,strlen(message1));//调试
//						HAL_UART_Transmit_IT(&huart2,(uint8_t*)message2,strlen(message2));//调试
//						HAL_UART_Transmit(&huart1,(uint8_t*)message1,strlen(message1),100);
//						HAL_UART_Transmit(&huart2,(uint8_t*)message2,strlen(message2),100);
						tx_count++;
            return;
        }
        else
        {
            uErrorCode = MB_EX_ILLEGAL_DATA_ADDRESS;
        }
    }
    else
    {
        uErrorCode = MB_EX_ILLEGAL_DATA_VALUE;
    }

    MODBUS_ERRFunction(uartHandle , uartbuf , ReadHoldReg, uErrorCode);
    return;
}


/*******************************************************************************
函数名称 : GetInputRegData
功    能 : 获取RegAdd的数据
参    数 : u16 RegAdd
返 回 值 : 两字节寄存器数据
*******************************************************************************/
uint16_t GetInputRegData(uint16_t RegAdd)
{
    int16_t wRegValue;

    wRegValue = InputReg[RegAdd - INPUT_REG_ADD_MIN];
	
    return wRegValue;
}


/*******************************************************************************
函数名称 : ReadInputRegFUNC
功    能 : 功能码:0x04,读取输入寄存器
参    数 : 无
返 回 值 : 无
*发送:[硬件地址][04][起始地址高][起始地址低][总寄存器数高][总寄存器数低][    CRC低   ][     CRC高  ]
*返回:[硬件地址][04][  字节数  ][寄存器0高 ][  寄存器0低 ][  寄存器1高 ][  寄存器1低 ][  寄存器n高 ][  寄存器n低 ][  CRC低 ][  CRC高 ]
*******************************************************************************/
void ReadInputRegFUNC(UART_HandleTypeDef* uartHandle,UART_BUF* uartbuf , uint8_t * upRxdbuf, uint16_t wRxdLen)
{
    uint16_t wRegStartAdd, wRegLen, i, wRegValue, CRC16Temp;
    uint8_t  uErrorCode, uCommIndexNum = 0;
		uint8_t  upTxdbuf[50];
   
    if(upRxdbuf == 0)  return;

    wRegStartAdd = MAKEWORD(upRxdbuf[1], upRxdbuf[0]); //获取寄存器起始地址
    wRegLen      = MAKEWORD(upRxdbuf[3], upRxdbuf[2]); //获取读取寄存器长度

    if((wRegLen >= 0x01) && (wRegLen <= MAX_INPUT_REG_NUM))
    {
        if((wRegStartAdd <= INPUT_REG_ADD_MAX) &&
           ((wRegStartAdd + wRegLen) <= INPUT_REG_ADD_MAX + 1))
        {
            upTxdbuf[uCommIndexNum ++] = uartbuf->rx_buf[0];    //LOCAL_ADDRESS;
            upTxdbuf[uCommIndexNum ++] = ReadInputReg;
            upTxdbuf[uCommIndexNum ++] = wRegLen * 2;

            for(i = 0; i < wRegLen; i++)
            {
                //获取16位数据并返回
                wRegValue = GetInputRegData(wRegStartAdd + i);
                upTxdbuf[uCommIndexNum ++] = (uint8_t)(wRegValue >> 8);
                upTxdbuf[uCommIndexNum ++] = (uint8_t)(wRegValue & 0xFF);
            }

            CRC16Temp = ModbusCRC16(upTxdbuf, uCommIndexNum);
            upTxdbuf[uCommIndexNum ++] = (uint8_t)(CRC16Temp & 0xFF); // crc16低字节在前
            upTxdbuf[uCommIndexNum ++] = (uint8_t)(CRC16Temp >> 8);   // crc16高字节在后
						RS485_enable_send(uartHandle);
            uartbuf->tx_size = (uCommIndexNum <= uartbuf->tx_buf_cnt ? uCommIndexNum : uartbuf->tx_buf_cnt);
            memcpy(uartbuf->tx_buf, upTxdbuf, uartbuf->tx_size);
            HAL_UART_Transmit_IT(uartHandle, uartbuf->tx_buf, uartbuf->tx_size);

            return;
        }
        else
        {
            uErrorCode = MB_EX_ILLEGAL_DATA_ADDRESS;
        }
    }
    else
    {
        uErrorCode = MB_EX_ILLEGAL_DATA_VALUE;
    }

    MODBUS_ERRFunction(uartHandle , uartbuf , ReadInputReg, uErrorCode);
    return;
}


/*******************************************************************************
函数名称 :  WriteHoldRegData
功    能 : 保存写入的保持寄存器数据
参    数 : u16 StartAdd
返 回 值 : 无
*******************************************************************************/
void WriteHoldRegData(uint16_t wRegAddr, uint16_t RegData)
{
    HoldReg[wRegAddr - HOLD_REG_ADD_MIN] = RegData;
}

/*******************************************************************************
函数名称 : WriteSingleRegFUNC
功    能 : 功能码:0x06 预设(写)单寄存器
参    数 : 无
返 回 值 : 无
*发送:[硬件地址][06][寄存器地址高][寄存器地址低][寄存器值高][寄存器值低][CRC低][CRC高]
*返回:[硬件地址][06][寄存器地址高][寄存器地址低][寄存器值高][寄存器值低][CRC低][CRC高]
*******************************************************************************/
extern unsigned char save_eeprom;
void WriteSingleRegFUNC(UART_HandleTypeDef* uartHandle,UART_BUF* uartbuf , uint8_t * upRxdbuf, uint16_t wRxdLen)
{
    uint16_t wRegAddr, wRegValue, CRC16Temp;
    uint8_t  uCommIndexNum = 0, uErrorCode;
    uint8_t  upTxdbuf[50];
	///
	unsigned char save_flag = 1;

    if(upRxdbuf == 0)  return;

    wRegAddr  = MAKEWORD(upRxdbuf[1], upRxdbuf[0]); //获取寄存器地址
    wRegValue = MAKEWORD(upRxdbuf[3], upRxdbuf[2]); //获取数据

    if(wRegAddr <= HOLD_REG_ADD_MAX)
    {
			if(save_flag == 1)
			{
					WriteHoldRegData(wRegAddr, wRegValue);
					//dh_ch.addr = wRegAddr;
					upTxdbuf[uCommIndexNum ++] = uartbuf->rx_buf[0];    //LOCAL_ADDRESS;
					upTxdbuf[uCommIndexNum ++] = WriteSingleReg;
					memcpy(upTxdbuf + uCommIndexNum, upRxdbuf, 4);
					uCommIndexNum += 4;

					CRC16Temp = ModbusCRC16(upTxdbuf, uCommIndexNum);
					upTxdbuf[uCommIndexNum ++] = (uint8_t)(CRC16Temp & 0xFF); // crc16低字节在前
					upTxdbuf[uCommIndexNum ++] = (uint8_t)(CRC16Temp >> 8);   // crc16高字节在后
					RS485_enable_send(uartHandle);
					uartbuf->tx_size = (uCommIndexNum <= uartbuf->tx_buf_cnt ? uCommIndexNum : uartbuf->tx_buf_cnt);
					memcpy(uartbuf->tx_buf, upTxdbuf, uartbuf->tx_size);
					HAL_UART_Transmit_IT(uartHandle, uartbuf->tx_buf, uartbuf->tx_size);
					return;
				}else
				{
					uErrorCode = MB_EX_ILLEGAL_DATA_ADDRESS;
				}
    }
    else
    {
        uErrorCode = MB_EX_ILLEGAL_DATA_ADDRESS;
    }

    MODBUS_ERRFunction(uartHandle , uartbuf , WriteSingleReg, uErrorCode);
    return;
}

/*******************************************************************************
函数名称 : WriteMultiRegFUNC
功    能 : 功能码:0x10 写多个保持寄存器
参    数 : 无
返 回 值 : 无
*******************************************************************************/
void WriteMultiRegFUNC(UART_HandleTypeDef* uartHandle,UART_BUF* uartbuf , uint8_t * upRxdbuf, uint16_t wRxdLen)
{
    uint16_t i, wRegStartAdd, wRegNum, CRC16Temp, uErrorCode, wRegValue;
    uint8_t  uCommIndexNum = 0, uByteNum;
    uint8_t  upTxdbuf[50];

    if(upRxdbuf == 0)  return;

    wRegStartAdd = MAKEWORD(upRxdbuf[1], upRxdbuf[0]);     //获取寄存器地址
    wRegNum      = MAKEWORD(upRxdbuf[3], upRxdbuf[2]);     //获取寄存器数量
    uByteNum     = upRxdbuf[4];                            //获取字节数

    if((wRegNum >= 0x01) && (wRegNum <= MAX_HOLD_REG_NUM) && (uByteNum == wRegNum * 2))
    {
        if((wRegStartAdd <= HOLD_REG_ADD_MAX) && 
			(wRegStartAdd + wRegNum <= HOLD_REG_ADD_MAX + 1))
        {
            for(i = 0; i < wRegNum; i++)
            {
                wRegValue = MAKEWORD(upRxdbuf[6 + i * 2], upRxdbuf[5 + i * 2]);
                WriteHoldRegData(wRegStartAdd + i, wRegValue);
            }

            upTxdbuf[uCommIndexNum ++] = uartbuf->rx_buf[0];    //LOCAL_ADDRESS;
            upTxdbuf[uCommIndexNum ++] = WriteMultiReg;
            memcpy(upTxdbuf + uCommIndexNum, upRxdbuf, 4);
            uCommIndexNum += 4;

            CRC16Temp = ModbusCRC16(upTxdbuf, uCommIndexNum);
            upTxdbuf[uCommIndexNum ++] = (uint8_t)(CRC16Temp & 0xFF);
            upTxdbuf[uCommIndexNum ++] = (uint8_t)(CRC16Temp >> 8);
						RS485_enable_send(uartHandle);
            uartbuf->tx_size = (uCommIndexNum <= uartbuf->tx_buf_cnt ? uCommIndexNum : uartbuf->tx_buf_cnt);
            memcpy(uartbuf->tx_buf, upTxdbuf, uartbuf->tx_size);
            HAL_UART_Transmit_IT(uartHandle, uartbuf->tx_buf, uartbuf->tx_size);

            return;
        }
        else
        {
            uErrorCode = MB_EX_ILLEGAL_DATA_ADDRESS;
        }
    }
    else
    {
        uErrorCode = MB_EX_ILLEGAL_DATA_VALUE;
    }

    MODBUS_ERRFunction(uartHandle , uartbuf , WriteMultiReg, uErrorCode);
    return;
}


/*******************************************************************************
函数名称 :  WriteOneCoilData
功    能 : 保存写入的线圈寄存器数据
参    数 : u16 StartAdd
返 回 值 : 无
*******************************************************************************/
void WriteOneCoilData(uint16_t wRegAddr, uint16_t RegData)
{
	if(RegData == 0xFF00)
    {
		CoilState[(wRegAddr - COIL_ADD_MIN) / 8] |= 1 << ((wRegAddr - COIL_ADD_MIN) % 8);
	}
	else if(RegData == 0x0000)
	{
		CoilState[(wRegAddr - COIL_ADD_MIN) / 8] &= ~(1 << ((wRegAddr - COIL_ADD_MIN) % 8));
		//CoilState[(COIL_ADD_MIN - wRegAddr) / 8] &= ~(1 << ((wRegAddr - COIL_ADD_MIN) % 8));

	}
}
/*******************************************************************************
函数名称 : WriteSingleCoilFUNC
功    能 : 功能码:0x05 写单个线圈寄存器
参    数 : 无
返 回 值 : 无
*******************************************************************************/
void WriteSingleCoilFUNC(UART_HandleTypeDef* uartHandle,UART_BUF* uartbuf , uint8_t * upRxdbuf, uint16_t wRxdLen)
{
    uint16_t wCoilAddr, wCoilValue, CRC16Temp;
    uint8_t  uCommIndexNum = 0, uErrorCode;
    uint8_t  upTxdbuf[50];

    wCoilAddr  = MAKEWORD(upRxdbuf[1], upRxdbuf[0]); //获取线圈地址
    wCoilValue = MAKEWORD(upRxdbuf[3], upRxdbuf[2]); //获取线圈数据

    if((wCoilValue == 0x0000) || (wCoilValue == 0xFF00))
    {
        if(wCoilAddr <= DIS_ADD_MAX)
        {
            WriteOneCoilData(wCoilAddr, wCoilValue);

            upTxdbuf[uCommIndexNum ++] = uartbuf->rx_buf[0];    //LOCAL_ADDRESS;
            upTxdbuf[uCommIndexNum ++] = WriteSingleCoil;
            memcpy(upTxdbuf + uCommIndexNum, upRxdbuf, 4);
            uCommIndexNum += 4;

            CRC16Temp = ModbusCRC16(upTxdbuf, uCommIndexNum);
            upTxdbuf[uCommIndexNum ++] = (uint8_t)(CRC16Temp & 0xFF);
            upTxdbuf[uCommIndexNum ++] = (uint8_t)(CRC16Temp >> 8);
						RS485_enable_send(uartHandle);
            uartbuf->tx_size = (uCommIndexNum <= uartbuf->tx_buf_cnt ? uCommIndexNum : uartbuf->tx_buf_cnt);
            memcpy(uartbuf->tx_buf, upTxdbuf, uartbuf->tx_size);
            HAL_UART_Transmit_IT(uartHandle, uartbuf->tx_buf, uartbuf->tx_size);
			
			return;
        }
        else
        {
            uErrorCode = MB_EX_ILLEGAL_DATA_ADDRESS;
        }
    }
    else
    {
        uErrorCode = MB_EX_ILLEGAL_DATA_VALUE;
    }

    MODBUS_ERRFunction(uartHandle , uartbuf , WriteSingleCoil, uErrorCode);
    return;
}

/*******************************************************************************
函数名称 : WriteMultiCoilFUNC
功    能 : 功能码:0x0F,写多个线圈
参    数 : 无
返 回 值 : 无
*发送:[硬件地址][0F][起始地址高][起始地址低][线圈数量高][线圈数量低][字节数][线圈值][CRC低][CRC高]
*返回:[硬件地址][0F][起始地址高][起始地址低][线圈数量高][线圈数量低][CRC低][CRC高]
*******************************************************************************/
void WriteMultiCoilFUNC(UART_HandleTypeDef* uartHandle,UART_BUF* uartbuf ,uint8_t * upRxdbuf, uint16_t wRxdLen)
{
	uint16_t wCoilStartAddr,wCoilNum,wCoilVal,wTotalCoilNum,CRC16Temp;
    uint8_t  i,k,uCommIndexNum = 0,uByteNum,uByteVal,uExit = 0,uErrorCode;
	uint8_t  upTxdbuf[50];

    wCoilStartAddr  = MAKEWORD(upRxdbuf[1], upRxdbuf[0]); //获取线圈地址
    wCoilNum        = MAKEWORD(upRxdbuf[3], upRxdbuf[2]); //获取线圈个数
	uByteNum        = upRxdbuf[4];                        //获取字节数

	if((wCoilNum >= 0x01) && (wCoilNum <= MAX_COIL_NUM) && (wCoilNum  <= 8 * uByteNum))
	{
		if((wCoilStartAddr <= COIL_ADD_MAX) && 
		   (wCoilStartAddr + wCoilNum <= COIL_ADD_MAX + 1))
		{
			wTotalCoilNum = 0;
            for(k = 0; k < uByteNum; k++)
			{
				uByteVal = upRxdbuf[5 + k];
				for(i = 0; i < 8; i++)
				{
					if(uByteVal & (1 << i)) wCoilVal = 0xFF00;
					else                    wCoilVal = 0x0000;
					
					WriteOneCoilData(wCoilStartAddr + wTotalCoilNum, wCoilVal);
					 
					wTotalCoilNum ++;
					if(wTotalCoilNum >= wCoilNum)
					{
						 uExit = 1;
						 break;
					}
				}
				
				if(uExit == 1)
				{
					break;
				}
			}
			
			upTxdbuf[uCommIndexNum ++] = uartbuf->rx_buf[0];    //LOCAL_ADDRESS;
			upTxdbuf[uCommIndexNum ++] = WriteMultiCoil;
			memcpy(upTxdbuf + uCommIndexNum, upRxdbuf, 4);
			uCommIndexNum += 4;

			CRC16Temp = ModbusCRC16(upTxdbuf, uCommIndexNum);
			upTxdbuf[uCommIndexNum ++] = (uint8_t)(CRC16Temp & 0xFF);
			upTxdbuf[uCommIndexNum ++] = (uint8_t)(CRC16Temp >> 8);
			RS485_enable_send(uartHandle);
			uartbuf->tx_size = (uCommIndexNum <= uartbuf->tx_buf_cnt ? uCommIndexNum : uartbuf->tx_buf_cnt);
			memcpy(uartbuf->tx_buf, upTxdbuf, uartbuf->tx_size);
			HAL_UART_Transmit_IT(uartHandle, uartbuf->tx_buf, uartbuf->tx_size);
			
			return;
		}
		else
		{
			uErrorCode = MB_EX_ILLEGAL_DATA_ADDRESS;
		}
	}
	else
	{
        uErrorCode = MB_EX_ILLEGAL_DATA_VALUE;
	}
	
    MODBUS_ERRFunction(uartHandle , uartbuf , WriteMultiCoil, uErrorCode);
    return;
}

/********
***********************************************************************
函数名称 : MODBUS_ERRFunction
功     能: 错误回应指令
参     数: 无
返 回  值: 无
异常功能码 = 功能码+0x80
*******************************************************************************/
void MODBUS_ERRFunction(UART_HandleTypeDef* uartHandle,UART_BUF* uartbuf , uint8_t uCmdCode, uint8_t uErrorCode)
{
    uint8_t  uCommIndexNum = 0;
    uint16_t CRC16Temp     = 0;
    uint8_t upTxdbuf[50];

    upTxdbuf[uCommIndexNum ++] = uartbuf->rx_buf[0];    //     LOCAL_ADDRESS;
    upTxdbuf[uCommIndexNum ++] = uCmdCode | 0x80;
    upTxdbuf[uCommIndexNum ++] = uErrorCode;

    CRC16Temp = ModbusCRC16(upTxdbuf, uCommIndexNum);
    upTxdbuf[uCommIndexNum ++] = (uint8_t)(CRC16Temp & 0xFF); //crc16低字节在前
    upTxdbuf[uCommIndexNum ++] = (uint8_t)(CRC16Temp >> 8);
		RS485_enable_send(uartHandle);
    uartbuf->tx_size = (uCommIndexNum <= uartbuf->tx_buf_cnt ? uCommIndexNum : uartbuf->tx_buf_cnt);
    memcpy(uartbuf->tx_buf, upTxdbuf, uartbuf->tx_size);
    HAL_UART_Transmit_IT(uartHandle, uartbuf->tx_buf, uartbuf->tx_size);
}

/*******************************************************************************
函数名称 : Modbus_Analysis
功    能 : CRC校验
参    数 : ptr--校验数组指针  len--校验数据长度
返 回 值 : CRC校验码,双字节
*******************************************************************************/
void Modbus_Analysis(UART_HandleTypeDef* uartHandle,UART_BUF* uartbuf , uint8_t * upRxdbuf, uint16_t wRxdLen , uint8_t SlaveID)
{
    uint8_t  uSlaveAdd, uCmdCode;

    if((upRxdbuf == 0) || (wRxdLen < 2))  return;

    uSlaveAdd    = upRxdbuf[0];
    uCmdCode     = upRxdbuf[1];

    // 从机地址为本机地址或者是广播帧
    if((uSlaveAdd == SlaveID) || (uSlaveAdd == BROADCAST_ADDRESS))
    {
      switch(uCmdCode)
      {
				case ReadCoilState:    //0x01
					ReadCoilStateFUNC(uartHandle , uartbuf ,upRxdbuf + 2, wRxdLen - 2);             // 读线圈状态
					break;
		
				case ReadDisInputState:    //0x02
					ReadDisInputStateFUNC(uartHandle , uartbuf , upRxdbuf + 2, wRxdLen - 2);         // 读离散输入状态
					break;
		
        case ReadHoldReg:    //0x03
						RS485_enable_send(uartHandle);
            ReadHoldRegFUNC(uartHandle , uartbuf , upRxdbuf + 2, wRxdLen - 2);               // 读取保持寄存器
            break;
		
        case ReadInputReg:   //0x04
            ReadInputRegFUNC(uartHandle , uartbuf , upRxdbuf + 2, wRxdLen - 2);              // 读取输入寄存器
            break;
		
        case WriteSingleReg:  //0x06
            WriteSingleRegFUNC(uartHandle , uartbuf , upRxdbuf + 2, wRxdLen - 2);            // 写单个寄存器
            break;

				case WriteMultiCoil:  //0x0F
            WriteMultiCoilFUNC(uartHandle , uartbuf , upRxdbuf + 2, wRxdLen - 2);            // 写多个线圈
            break;
		
        case WriteMultiReg:   //0x10
            WriteMultiRegFUNC(uartHandle , uartbuf , upRxdbuf + 2, wRxdLen - 2);             // 写多个寄存器
            break;

        case WriteSingleCoil:  //0x05
            WriteSingleCoilFUNC(uartHandle , uartbuf , upRxdbuf + 2, wRxdLen - 2);           // 写单个线圈
            break;

        default:
            MODBUS_ERRFunction(uartHandle , uartbuf , upRxdbuf[1], 0x01);                    // 错误码处理
            break;
        }
    }
}


void Modbus_Process(UART_HandleTypeDef* uartHandle,UART_BUF* uartbuf)
{
    uint8_t  *pFrame;
    uint16_t wFrameLen = 0;
    uint16_t wFrameCRC, wCalCRC;
		uint8_t setid ;
    pFrame    = uartbuf->rx_buf;    // 接收数据起始地址
    wFrameLen = uartbuf->rx_size;   // 接收数据长度

    if(wFrameLen < 2) return;    		// 数据长度不是有效值

    // 获取接收数据帧中的校验和
    wFrameCRC = MAKEWORD(pFrame[wFrameLen - 2], pFrame[wFrameLen - 1]);
    // 计算接收到的数据的校验和
    wCalCRC   = ModbusCRC16(pFrame, wFrameLen - 2);
    if(wFrameCRC != wCalCRC) return;

		if(uartHandle->Instance==USART1)
		{
			setid = 1;
		}
		else if(uartHandle->Instance==USART2)
		{
			setid = 1;
		}
				
    Modbus_Analysis(uartHandle , uartbuf , uartbuf->rx_buf, uartbuf->rx_size , setid);                        // 协议处理
}

extern unsigned int UART1_TIME ;
extern unsigned int UART2_TIME ;
static uint32_t last_rx_tick1=0;
static uint32_t last_rx_tick2=0;
void Modbus_Poll(void)
{

		static uint16_t CETimer1=0;
		static uint16_t CETimer2=0;	
	
		if(uart1.rx_flag == 1)
	  {
			Modbus_Process(&huart1,&uart1); // 处理接收到的Modbus帧
			uart1.rx_flag=0;// 清接收标志
			last_rx_tick1 = HAL_GetTick();
			CETimer1 = 1;              // 启动RS485方向切换定时器
	  }
		if(CETimer1)
		{
			if(CETimer1++ >= 30)
			{
				CETimer1 = 0;
				HAL_GPIO_WritePin(RS485_EN1_GPIO_Port,  RS485_EN1_Pin,  GPIO_PIN_SET);  //	UART1_CE 高:接收
				UART1_high_count++;
			}
		
		}
		
		 if(uart2.rx_flag == 1)	
	  {
			Modbus_Process(&huart2,&uart2);
			uart2.rx_flag=0;	
			last_rx_tick2 = HAL_GetTick();		
			CETimer2 = 1;
	  }
		
		if(CETimer2)
		{
			if(CETimer2++ >= 10)
			{
				CETimer2 = 0;
				HAL_GPIO_WritePin(RS485_EN2_GPIO_Port,  RS485_EN2_Pin,  GPIO_PIN_RESET);  //	UART2_CE
			}
		
		}
		//超时检测
		if((HAL_GetTick() - last_rx_tick1) >= 2000)
		{
			last_rx_tick1 = HAL_GetTick();
			E_USART_INIT(&huart1,&uart1);
			__HAL_TIM_CLEAR_FLAG(&htim7, TIM_FLAG_UPDATE);		//手动添加
			HAL_TIM_Base_Start_IT(&htim7);
		}
		if((HAL_GetTick() - last_rx_tick2) >= 2000)
		{
			last_rx_tick2 = HAL_GetTick();
			E_USART_INIT(&huart2,&uart2);
			__HAL_TIM_CLEAR_FLAG(&htim6, TIM_FLAG_UPDATE);		//手动添加
			HAL_TIM_Base_Start_IT(&htim6);
		}
}



void RS485_enable_send(UART_HandleTypeDef *uartHandle)
{
				if(uartHandle->Instance==USART1)
				{
					HAL_GPIO_WritePin(RS485_EN1_GPIO_Port,  RS485_EN1_Pin,  GPIO_PIN_RESET);  //	UART1_CE 低发送
					UART1_low_count++;
				}else
				if(uartHandle->Instance==USART2)
				{
					HAL_GPIO_WritePin(RS485_EN2_GPIO_Port,  RS485_EN2_Pin,  GPIO_PIN_SET);  //	UART2_CE
				}
}
c 复制代码
#ifndef __MODBUS_H
#define __MODBUS_H

//#include "tim.h"
#include "stdint.h"
#include "usart.h"
#include "crc.h"
//#include "main.h"

/*--------------------------------- 宏定义 -----------------------------------*/
//功能码
#define   ReadCoilState                 0x01         //读取线圈状态
#define   ReadDisInputState             0x02         //读取输入状态
#define   ReadHoldReg                   0x03         //读取保持寄存器
#define   ReadInputReg            			0x04         //读取输入寄存器
#define   WriteSingleCoil               0x05         //强制写单线圈输出状态
#define   WriteSingleReg                0x06         //预设(写)单寄存器
#define   WriteMultiCoil                0x0F         //强制写多线圈输出状态
#define   WriteMultiReg                 0x10         //预设(写)多寄存器
 


#define COIL_ADD_MIN       			((uint16_t)0)
#define COIL_ADD_MAX       			((uint16_t)15)
#define MAX_COIL_NUM       			((COIL_ADD_MAX) - (COIL_ADD_MIN) + ((uint16_t)1))

#define DIS_ADD_MIN        			((uint16_t)0)
#define DIS_ADD_MAX        			((uint16_t)15)
#define MAX_DIS_NUM        			((DIS_ADD_MAX) - (DIS_ADD_MIN) + ((uint16_t)1))

#define INPUT_REG_ADD_MIN       ((uint16_t)0)
#define INPUT_REG_ADD_MAX       ((uint16_t)99)
#define MAX_INPUT_REG_NUM       ((INPUT_REG_ADD_MAX) - (INPUT_REG_ADD_MIN) + ((uint16_t)1))

#define HOLD_REG_ADD_MIN        ((uint16_t)0)
#define HOLD_REG_ADD_MAX        ((uint16_t)499)
#define MAX_HOLD_REG_NUM        ((HOLD_REG_ADD_MAX) - (HOLD_REG_ADD_MIN) + ((uint16_t)1))

#define BROADCAST_ADDRESS   0x00
#define LOCAL_ADDRESS       0x02

#define MAKEWORD(a,b)      ((uint16_t)(((uint8_t)(a)) | ((uint16_t)((uint8_t)(b))) << 8))



extern uint16_t InputReg[MAX_INPUT_REG_NUM] ; 
extern uint16_t HoldReg[MAX_HOLD_REG_NUM] ;
extern uint8_t  CoilState[(MAX_DIS_NUM + 7) / 8];
extern uint8_t  DisState [(MAX_DIS_NUM + 7) / 8];
typedef enum
{
    MB_EX_NONE = 0x00,
    MB_EX_ILLEGAL_FUNCTION = 0x01,
    MB_EX_ILLEGAL_DATA_ADDRESS = 0x02,
    MB_EX_ILLEGAL_DATA_VALUE = 0x03,
    MB_EX_SLAVE_DEVICE_FAILURE = 0x04,
    MB_EX_ACKNOWLEDGE = 0x05,
    MB_EX_SLAVE_BUSY = 0x06,
    MB_EX_MEMORY_PARITY_ERROR = 0x08,
    MB_EX_GATEWAY_PATH_FAILED = 0x0A,
    MB_EX_GATEWAY_TGT_FAILED = 0x0B
} eMBException;


//save_eeprom

extern void Modbus_Process(UART_HandleTypeDef* uartHandle,UART_BUF* uartbuf);
extern void Modbus_Poll(void);

#endif

2.4 主函数

c 复制代码
int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_CRC_Init();
  MX_SPI2_Init();
  MX_TIM2_Init();
  MX_TIM3_Init();
  MX_TIM4_Init();
  MX_TIM5_Init();
  MX_TIM6_Init();
  MX_TIM7_Init();
  MX_TIM8_Init();
  MX_USART1_UART_Init();
  MX_USART2_UART_Init();
  /* USER CODE BEGIN 2 */
  E_USART_INIT(&huart1, &uart1);
  E_USART_INIT(&huart2, &uart2);
	
	char message[]="Hello world";
	
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
				/*从机轮询*/
	    	Modbus_Poll();	
     //	HAL_Delay(1);		
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

3 移植中的问题和解决

3.1 超时检测

原来的工程用的操作系统,试用计数的方式判断是否延时:

c 复制代码
		 uint16_t Timeout_Check1=0;
		 uint16_t Timeout_Check2=0;
void Modbus_Poll(void)
{

		static uint16_t CETimer1=0;
		static uint16_t CETimer2=0;	
	
		if(uart1.rx_flag == 1)
	  {
			Modbus_Process(&huart1,&uart1);
			uart1.rx_flag=0;
			Timeout_Check1 = 0;
			CETimer1 = 1;
	  }
		if(CETimer1)
		{
			if(CETimer1++ >= 30)
			{
				CETimer1 = 0;
				HAL_GPIO_WritePin(RS485_EN1_GPIO_Port,  RS485_EN1_Pin,  GPIO_PIN_SET);  //	UART1_CE
			}
		
		}
		
		 if(uart2.rx_flag == 1)	
	  {
			Modbus_Process(&huart2,&uart2);
			uart2.rx_flag=0;	
			Timeout_Check2 = 0;		
			CETimer2 = 1;
	  }
		
		if(CETimer2)
		{
			if(CETimer2++ >= 10)
			{
				CETimer2 = 0;
				HAL_GPIO_WritePin(RS485_EN2_GPIO_Port,  RS485_EN2_Pin,  GPIO_PIN_RESET);  //	UART2_CE
			}
		
		}
		//超时检测
		if(Timeout_Check1++ >= 2000)
		{
			Timeout_Check1 = 0;
			E_USART_INIT(&huart1,&uart1);
			__HAL_TIM_CLEAR_FLAG(&htim7, TIM_FLAG_UPDATE);		//手动添加
			HAL_TIM_Base_Start_IT(&htim7);
		}
		if(Timeout_Check2++ >= 2000)
		{
			Timeout_Check2 = 0;
			E_USART_INIT(&huart2,&uart2);
			__HAL_TIM_CLEAR_FLAG(&htim6, TIM_FLAG_UPDATE);		//手动添加
			HAL_TIM_Base_Start_IT(&htim6);
		}
}

但是我这个用的裸机,不能保证每次循环就是0.001秒,所以改用定时器判断

c 复制代码
static uint32_t last_rx_tick1=0;
static uint32_t last_rx_tick2=0;
void Modbus_Poll(void)
{

		static uint16_t CETimer1=0;
		static uint16_t CETimer2=0;	
	
		if(uart1.rx_flag == 1)
	  {
			Modbus_Process(&huart1,&uart1); // 处理接收到的Modbus帧
			uart1.rx_flag=0;// 清接收标志
			last_rx_tick1 = HAL_GetTick();
			CETimer1 = 1;              // 启动RS485方向切换定时器
	  }
		if(CETimer1)
		{
			if(CETimer1++ >= 30)
			{
				CETimer1 = 0;
				HAL_GPIO_WritePin(RS485_EN1_GPIO_Port,  RS485_EN1_Pin,  GPIO_PIN_SET);  //	UART1_CE 高:接收
				UART1_high_count++;
			}
		
		}
		
		 if(uart2.rx_flag == 1)	
	  {
			Modbus_Process(&huart2,&uart2);
			uart2.rx_flag=0;	
			last_rx_tick2 = HAL_GetTick();		
			CETimer2 = 1;
	  }
		
		if(CETimer2)
		{
			if(CETimer2++ >= 10)
			{
				CETimer2 = 0;
				HAL_GPIO_WritePin(RS485_EN2_GPIO_Port,  RS485_EN2_Pin,  GPIO_PIN_RESET);  //	UART2_CE
			}
		
		}
		//超时检测
		if((HAL_GetTick() - last_rx_tick1) >= 2000)
		{
			last_rx_tick1 = HAL_GetTick();
			E_USART_INIT(&huart1,&uart1);
			__HAL_TIM_CLEAR_FLAG(&htim7, TIM_FLAG_UPDATE);		//手动添加
			HAL_TIM_Base_Start_IT(&htim7);
		}
		if((HAL_GetTick() - last_rx_tick2) >= 2000)
		{
			last_rx_tick2 = HAL_GetTick();
			E_USART_INIT(&huart2,&uart2);
			__HAL_TIM_CLEAR_FLAG(&htim6, TIM_FLAG_UPDATE);		//手动添加
			HAL_TIM_Base_Start_IT(&htim6);
		}
}

或者

在主函数的while()中加延迟 HAL_Delay(1);

c 复制代码
  while (1)
  {
    /* USER CODE END WHILE */
				/*从机轮询*/
	    	Modbus_Poll();	
      	HAL_Delay(1);		
    /* USER CODE BEGIN 3 */
  }

3.2 485控制引脚的初始化

一开始485的控制端PC9是置低的,就导致串口1的485不能通讯,

后来初始化置高就好了,具体原因未知

c 复制代码
void MX_GPIO_Init(void)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOD_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();
  __HAL_RCC_GPIOC_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8|GPIO_PIN_9, GPIO_PIN_SET);

  /*Configure GPIO pins : PC8 PC9 */
  GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
}

3.3 发送函数

串口1不能用HAL_UART_Transmit_IT只能用HAL_UART_Transmit,否则不能正常发送数据,串口2两个就都可以(串口1通过485芯片,串口2是通过232),原因未知

c 复制代码
/*******************************************************************************
函数名称 : ReadHoldRegFUNC
功    能 : 功能码:0x03,读取保持寄存器
参    数 : 无
返 回 值 : 无
*发送:[硬件地址][03][起始地址高][起始地址低][总寄存器数高][总寄存器数低][CRC低][CRC高]
*返回:[硬件地址][03][字节数][寄存器0高][寄存器0低][寄存器1高][寄存器1低][寄存器n高][寄存器n低][CRC低][CRC高]
*******************************************************************************/
void ReadHoldRegFUNC(UART_HandleTypeDef* uartHandle,UART_BUF* uartbuf , uint8_t * upRxdbuf, uint16_t wRxdLen)
{
    uint16_t wRegStartAdd, wRegLen, i, wRegValue, CRC16Temp;
    uint8_t  uErrorCode, uCommIndexNum = 0;
    uint8_t  upTxdbuf[50];

    if(upRxdbuf == 0)  return;

    wRegStartAdd = MAKEWORD(upRxdbuf[1], upRxdbuf[0]); //获取寄存器起始地址
    wRegLen      = MAKEWORD(upRxdbuf[3], upRxdbuf[2]); //获取读取寄存器长度

    if((wRegLen >= 0x01) && (wRegLen <= MAX_HOLD_REG_NUM))
    {
        if(((wRegStartAdd <= HOLD_REG_ADD_MAX)) &&
           ((wRegStartAdd + wRegLen) <= HOLD_REG_ADD_MAX + 1))
        {
            upTxdbuf[uCommIndexNum ++] = uartbuf->rx_buf[0];    //LOCAL_ADDRESS;
            upTxdbuf[uCommIndexNum ++] = ReadHoldReg;
            upTxdbuf[uCommIndexNum ++] = wRegLen * 2;

            for(i = 0; i < wRegLen; i++)
            {
                //获取16位数据并返回
                wRegValue = GetHoldRegData(wRegStartAdd + i);
                upTxdbuf[uCommIndexNum ++] = (uint8_t)(wRegValue >> 8);
                upTxdbuf[uCommIndexNum ++] = (uint8_t)(wRegValue & 0xFF);
            }

            CRC16Temp = ModbusCRC16(upTxdbuf, uCommIndexNum);
            upTxdbuf[uCommIndexNum ++] = (uint8_t)(CRC16Temp & 0xFF); // crc16低字节在前
            upTxdbuf[uCommIndexNum ++] = (uint8_t)(CRC16Temp >> 8);   // crc16高字节在后
						RS485_enable_send(uartHandle);
            uartbuf->tx_size = (uCommIndexNum <= uartbuf->tx_buf_cnt ? uCommIndexNum : uartbuf->tx_buf_cnt);
            memcpy(uartbuf->tx_buf, upTxdbuf, uartbuf->tx_size);
 //           HAL_UART_Transmit_IT(uartHandle, uartbuf->tx_buf, uartbuf->tx_size); 
						HAL_UART_Transmit(uartHandle, uartbuf->tx_buf, uartbuf->tx_size,100);//改成HAL_UART_Transmit,串口1用HAL_UART_Transmit_IT不行

            return;
        }
        else
        {
            uErrorCode = MB_EX_ILLEGAL_DATA_ADDRESS;
        }
    }
    else
    {
        uErrorCode = MB_EX_ILLEGAL_DATA_VALUE;
    }

    MODBUS_ERRFunction(uartHandle , uartbuf , ReadHoldReg, uErrorCode);
    return;
}

4 源码

代码: https://wwbmh.lanzouw.com/iPp7p3evwqah

里面有DMA版本和不用DMA的

相关推荐
ACP广源盛1392462567322 分钟前
GSV2231@ACP# 增强型 8K MST 多屏扩展芯片
大数据·人工智能·分布式·嵌入式硬件
国科安芯12 小时前
航天器多路并联大功率电源系统设计与ASP4644均流特性分析
单片机·嵌入式硬件·fpga开发·安全性测试
茯苓gao14 小时前
嵌入式开发笔记:CANopen相关移位运算与通信协议术语详解
网络·嵌入式硬件·学习·信息与通信
梁朝辉17 小时前
STM32H750VBT6中ADCINP与INN什么区别
stm32·单片机·嵌入式硬件
省四收割者18 小时前
一文详解信号完整性(1)
python·嵌入式硬件·数学建模·信息与通信·信号处理·智能硬件
崇山峻岭之间19 小时前
单片机无感FOC驱动之ADC
单片机·嵌入式硬件
Ligocious19 小时前
1.点亮一颗小小的LED
单片机·嵌入式硬件
KaifuZeng1 天前
通信与接口协议面试八、CAN通信
单片机·嵌入式硬件·面试·通信与接口协议
智源单片机设计1 天前
基于单片机的直流电机双闭环调速系统设计
单片机·嵌入式硬件
kebidaixu1 天前
两轮车换电 BMS 的模拟前端中颖 SH367306 AFE 芯片详解
stm32