裸机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的

相关推荐
一路往蓝-Anbo2 小时前
C语言从句柄到对象 (五) —— 虚函数表 (V-Table) 与 RAM 的救赎
c语言·开发语言·stm32·单片机·物联网
古译汉书2 小时前
keil编译错误:Error: Flash Download failed
开发语言·数据结构·stm32·单片机·嵌入式硬件
不吃鱼的羊3 小时前
达芬奇PWM模块
单片机·嵌入式硬件·fpga开发
creeper_boom3 小时前
32单片机软件程序启动流程
单片机
d111111111d3 小时前
使用STM32 HAL库配置ADC单次转换模式详解
笔记·stm32·单片机·嵌入式硬件·学习
boneStudent3 小时前
STM32智能温湿度监测系统完整代码
stm32·单片机·嵌入式硬件
炸膛坦客4 小时前
Cortex-M3-STM32F1 开发:(三十八)DMA详细介绍(2):软件触发、数据传输流向、宏观流程图
stm32·单片机·嵌入式硬件·dma
polarislove02144 小时前
9.3 输出比较-嵌入式铁头山羊STM32笔记
笔记·stm32·嵌入式硬件
chen_mangoo4 小时前
Android10低电量无法打开相机
android·linux·驱动开发·嵌入式硬件