文章目录
- [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的