From e9adda50f604f26421d4df2b1cc8a7d57d73d3d7 Mon Sep 17 00:00:00 2001 From: ywh <2227158009@qq.com> Date: Sat, 1 Aug 2026 00:43:35 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BA=86=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E8=A7=84=E8=8C=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Core/Src/main.c | 483 +++++++++++++------------ Modbus/Inc/modbus_rtu_slave.h | 110 +++--- Modbus/Src/modbus_rtu_slave.c | 638 ++++++++++++++++++++-------------- 3 files changed, 665 insertions(+), 566 deletions(-) diff --git a/Core/Src/main.c b/Core/Src/main.c index 77e31aa..a4b9b45 100644 --- a/Core/Src/main.c +++ b/Core/Src/main.c @@ -1,20 +1,20 @@ /* USER CODE BEGIN Header */ /** - ****************************************************************************** - * @file : main.c - * @brief : Main program body - ****************************************************************************** - * @attention - * - * Copyright (c) 2026 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. - * - ****************************************************************************** - */ + ****************************************************************************** + * @file : main.c + * @brief : Main program body + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 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 "main.h" @@ -46,7 +46,7 @@ UART_HandleTypeDef huart1; DMA_HandleTypeDef hdma_usart1_rx; DMA_HandleTypeDef hdma_usart1_tx; - +static uint8_t ConnectFlag; /* USER CODE BEGIN PV */ static OS_STK AppTaskStartStk[APP_TASK_START_STK_SIZE]; @@ -59,148 +59,134 @@ static void MX_GPIO_Init(void); static void MX_DMA_Init(void); static void MX_USART1_UART_Init(void); /* USER CODE BEGIN PFP */ -static void AppTaskStart(void *p_arg); - - +static void AppTaskStart(void *pArg); /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ - -static void AppTaskStart(void *p_arg) +static void AppTaskStart(void *pArg) { - (void)p_arg; - - /* - * F4作为Modbus RTU从站,触摸屏作为主站 - * 初始化函数会立即启动USART1的DMA空闲接收 - */ - ModbusSlaveInit(&huart1, MODBUS_SLAVE_DEFAULT_ADDRESS); - ModbusRetainedRegistersLoad(); - while (1) - { - /* - * 维护几个供触摸屏首次联调读取的保持寄存器: - */ - (void)ModbusSlaveSetHoldingRegister(//OS时钟 - HMI_REG_UPTIME_SECONDS, - (uint16_t)(OSTimeGet() / OS_TICKS_PER_SEC)); - (void)ModbusSlaveSetHoldingRegister(//有效帧计数 - HMI_REG_RX_FRAME_COUNT, - (uint16_t)ModbusSlaveStatistics.validFrameCount); - - (void)ModbusSlaveSetHoldingRegister(//从站地址不匹配计数 - 3, - (uint16_t)ModbusSlaveStatistics.ignoredAddressCount); - (void)ModbusSlaveSetHoldingRegister(//非法功能码计数 - 4, - (uint16_t)ModbusSlaveStatistics.illegalFunctionCount); - - (void)ModbusSlaveSetHoldingRegister(//非法地址计数 - 5, - (uint16_t)ModbusSlaveStatistics.illegalAddressCount); - - (void)ModbusSlaveSetHoldingRegister(//非法数据值计数 - 6, - (uint16_t)ModbusSlaveStatistics.illegalValueCount); - - HistorySaveToRegisters(); - - - - - - - + (void)pArg; /* - * 每1ms轮询一次, + * F4作为Modbus RTU从站,触摸屏作为主站 + * 初始化函数会立即启动USART1的DMA空闲接收 */ - ModbusSlavePoll(); - ModbusRetainedRegistersPoll(); - // printf("123"); - OSTimeDly(1U); - } + (void)ModbusSlaveInit(&huart1, MODBUS_SLAVE_DEFAULT_ADDRESS); + ModbusRetainedRegistersLoad(); + while (1) + { + /* + * 维护几个供触摸屏首次联调读取的保持寄存器: + */ + (void)ModbusSlaveSetHoldingRegister( // OS时钟 + HMI_REG_UPTIME_SECONDS, (uint16_t)(OSTimeGet() / OS_TICKS_PER_SEC)); + (void)ModbusSlaveSetHoldingRegister( // 有效帧计数 + HMI_REG_RX_FRAME_COUNT, + (uint16_t)ModbusSlaveStatistics.validFrameCount); + + (void)ModbusSlaveSetHoldingRegister( // 从站地址不匹配计数 + 3, (uint16_t)ModbusSlaveStatistics.ignoredAddressCount); + (void)ModbusSlaveSetHoldingRegister( // 非法功能码计数 + 4, (uint16_t)ModbusSlaveStatistics.illegalFunctionCount); + + (void)ModbusSlaveSetHoldingRegister( // 非法地址计数 + 5, (uint16_t)ModbusSlaveStatistics.illegalAddressCount); + + (void)ModbusSlaveSetHoldingRegister( // 非法数据值计数 + 6, (uint16_t)ModbusSlaveStatistics.illegalValueCount); + + HistorySaveToRegisters(); + + /* + * 每1ms轮询一次, + */ + ModbusSlavePoll(); + ModbusRetainedRegistersPoll(); + + if (ModbusSlaveIsConnected(MODBUS_CONNECTION_TIMEOUT_MS) != 0U) + { + /* 主站在线 */ + ConnectFlag = 1; + } + else + { + /* 主站超时或断开 */ + ConnectFlag = 0; + } + + OSTimeDly(1U); + } } - /* USER CODE END 0 */ /** - * @brief The application entry point. - * @retval int - */ + * @brief The application entry point. + * @retval int + */ 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 BEGIN 1 */ - /* USER CODE END Init */ + /* USER CODE END 1 */ - /* Configure the system clock */ - SystemClock_Config(); + /* MCU + * Configuration--------------------------------------------------------*/ - /* USER CODE BEGIN SysInit */ + /* Reset peripherals and initialize the Flash interface and the Systick. */ + HAL_Init(); - /* USER CODE END SysInit */ + /* USER CODE BEGIN Init */ - /* Initialize all configured peripherals */ - MX_GPIO_Init(); - MX_DMA_Init(); - MX_USB_DEVICE_Init(); - MX_USART1_UART_Init(); - BackupSramInit(); + /* USER CODE END Init */ + /* Configure the system clock */ + SystemClock_Config(); - /* USER CODE BEGIN 2 */ - INT8U os_err; + /* USER CODE BEGIN SysInit */ + /* USER CODE END SysInit */ - OSInit(); + /* Initialize all configured peripherals */ + MX_GPIO_Init(); + MX_DMA_Init(); + MX_USB_DEVICE_Init(); + MX_USART1_UART_Init(); + (void)BackupSramInit(); + /* USER CODE BEGIN 2 */ + INT8U osError; - os_err = OSTaskCreateExt(AppTaskStart, - 0, - &AppTaskStartStk[APP_TASK_START_STK_SIZE - 1u], - APP_TASK_START_PRIO, - APP_TASK_START_PRIO, - &AppTaskStartStk[0], - APP_TASK_START_STK_SIZE, - 0, - (OS_TASK_OPT_STK_CHK | - OS_TASK_OPT_STK_CLR)); + OSInit(); - if (os_err != OS_ERR_NONE) - { - Error_Handler(); - } + osError = OSTaskCreateExt(AppTaskStart, 0, + &AppTaskStartStk[APP_TASK_START_STK_SIZE - 1u], + APP_TASK_START_PRIO, APP_TASK_START_PRIO, + &AppTaskStartStk[0], APP_TASK_START_STK_SIZE, 0, + (OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR)); + if (osError != OS_ERR_NONE) + { + Error_Handler(); + } - OSStart(); - /* USER CODE END 2 */ + OSStart(); + /* USER CODE END 2 */ - /* Infinite loop */ - /* USER CODE BEGIN WHILE */ - while (1) - { - /* USER CODE END WHILE */ + /* Infinite loop */ + /* USER CODE BEGIN WHILE */ + while (1) + { + /* USER CODE END WHILE */ - /* USER CODE BEGIN 3 */ - - } - /* USER CODE END 3 */ + /* USER CODE BEGIN 3 */ + } + /* USER CODE END 3 */ } static HAL_StatusTypeDef BackupSramInit(void) @@ -212,187 +198,182 @@ static HAL_StatusTypeDef BackupSramInit(void) } /** - * @brief System Clock Configuration - * @retval None - */ + * @brief System Clock Configuration + * @retval None + */ void SystemClock_Config(void) { - RCC_OscInitTypeDef RCC_OscInitStruct = {0}; - RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; - - /** Configure the main internal regulator output voltage - */ - __HAL_RCC_PWR_CLK_ENABLE(); - __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); - - /** Initializes the RCC Oscillators according to the specified parameters - * in the RCC_OscInitTypeDef structure. - */ - RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; - RCC_OscInitStruct.HSEState = RCC_HSE_ON; - RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; - RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; - RCC_OscInitStruct.PLL.PLLM = 12; - RCC_OscInitStruct.PLL.PLLN = 336; - RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; - RCC_OscInitStruct.PLL.PLLQ = 7; - if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) - { - Error_Handler(); - } - - /** Initializes the CPU, AHB and APB buses clocks - */ - RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK - |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; - RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; - RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; - RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; - RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; - - if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK) - { - Error_Handler(); - } - - /** Enables the Clock Security System - */ - HAL_RCC_EnableCSS(); + RCC_OscInitTypeDef RCC_OscInitStruct = {0}; + RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; + + /** Configure the main internal regulator output voltage + */ + __HAL_RCC_PWR_CLK_ENABLE(); + __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); + + /** Initializes the RCC Oscillators according to the specified parameters + * in the RCC_OscInitTypeDef structure. + */ + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; + RCC_OscInitStruct.HSEState = RCC_HSE_ON; + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; + RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; + RCC_OscInitStruct.PLL.PLLM = 12; + RCC_OscInitStruct.PLL.PLLN = 336; + RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; + RCC_OscInitStruct.PLL.PLLQ = 7; + if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) + { + Error_Handler(); + } + + /** Initializes the CPU, AHB and APB buses clocks + */ + RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK + | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2; + RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; + RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; + RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; + RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; + + if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK) + { + Error_Handler(); + } + + /** Enables the Clock Security System + */ + HAL_RCC_EnableCSS(); } /** - * @brief USART1 Initialization Function - * @param None - * @retval None - */ + * @brief USART1 Initialization Function + * @param None + * @retval None + */ static void MX_USART1_UART_Init(void) { - /* USER CODE BEGIN USART1_Init 0 */ - - /* USER CODE END USART1_Init 0 */ + /* USER CODE BEGIN USART1_Init 0 */ - /* USER CODE BEGIN USART1_Init 1 */ + /* USER CODE END USART1_Init 0 */ - /* USER CODE END USART1_Init 1 */ - huart1.Instance = USART1; - huart1.Init.BaudRate = 115200; - huart1.Init.WordLength = UART_WORDLENGTH_9B; - huart1.Init.StopBits = UART_STOPBITS_1; - huart1.Init.Parity = UART_PARITY_EVEN; - 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 BEGIN USART1_Init 1 */ - /* USER CODE END USART1_Init 2 */ + /* USER CODE END USART1_Init 1 */ + huart1.Instance = USART1; + huart1.Init.BaudRate = 115200; + huart1.Init.WordLength = UART_WORDLENGTH_9B; + huart1.Init.StopBits = UART_STOPBITS_1; + huart1.Init.Parity = UART_PARITY_EVEN; + 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 */ } /** - * Enable DMA controller clock - */ + * Enable DMA controller clock + */ static void MX_DMA_Init(void) { - /* DMA controller clock enable */ - __HAL_RCC_DMA2_CLK_ENABLE(); - - /* DMA interrupt init */ - /* DMA2_Stream2_IRQn interrupt configuration */ - HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, 5, 0); - HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn); - /* DMA2_Stream7_IRQn interrupt configuration */ - HAL_NVIC_SetPriority(DMA2_Stream7_IRQn, 5, 0); - HAL_NVIC_EnableIRQ(DMA2_Stream7_IRQn); + /* DMA controller clock enable */ + __HAL_RCC_DMA2_CLK_ENABLE(); + /* DMA interrupt init */ + /* DMA2_Stream2_IRQn interrupt configuration */ + HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn); + /* DMA2_Stream7_IRQn interrupt configuration */ + HAL_NVIC_SetPriority(DMA2_Stream7_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(DMA2_Stream7_IRQn); } /** - * @brief GPIO Initialization Function - * @param None - * @retval None - */ + * @brief GPIO Initialization Function + * @param None + * @retval None + */ static void MX_GPIO_Init(void) { - /* USER CODE BEGIN MX_GPIO_Init_1 */ + /* USER CODE BEGIN MX_GPIO_Init_1 */ - /* USER CODE END MX_GPIO_Init_1 */ + /* USER CODE END MX_GPIO_Init_1 */ - /* GPIO Ports Clock Enable */ - __HAL_RCC_GPIOH_CLK_ENABLE(); - __HAL_RCC_GPIOA_CLK_ENABLE(); + /* GPIO Ports Clock Enable */ + __HAL_RCC_GPIOH_CLK_ENABLE(); + __HAL_RCC_GPIOA_CLK_ENABLE(); - /* USER CODE BEGIN MX_GPIO_Init_2 */ + /* USER CODE BEGIN MX_GPIO_Init_2 */ - /* USER CODE END MX_GPIO_Init_2 */ + /* USER CODE END MX_GPIO_Init_2 */ } /* USER CODE BEGIN 4 */ void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) { - if (huart->Instance == USART1) - { - /* 应答发送完成后,协议模块重新启动DMA接收。 */ - ModbusSlaveOnTxComplete(huart); - } + if (huart->Instance == USART1) + { + /* 应答发送完成后,协议模块重新启动DMA接收。 */ + ModbusSlaveOnTxComplete(huart); + } } void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size) { - if (huart->Instance == USART1) - { - /* - * DMA遇到串口空闲事件后进入这里。 - * 仅复制帧并重启DMA - */ - ModbusSlaveOnRxEvent(huart, Size); - } + if (huart->Instance == USART1) + { + ModbusSlaveOnRxEvent(huart, Size); + } } void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart) { - if (huart->Instance == USART1) - { - /* 溢出、噪声、帧错误等异常后恢复USART1 DMA接收。 */ - ModbusSlaveOnUartError(huart); - } + if (huart->Instance == USART1) + { + /* 溢出、噪声、帧错误等异常后恢复USART1 DMA接收。 */ + ModbusSlaveOnUartError(huart); + } } /* USER CODE END 4 */ /** - * @brief This function is executed in case of error occurrence. - * @retval None - */ + * @brief This function is executed in case of error occurrence. + * @retval None + */ void Error_Handler(void) { - /* USER CODE BEGIN Error_Handler_Debug */ - /* User can add his own implementation to report the HAL error return state */ - __disable_irq(); - while (1) - { - } - /* USER CODE END Error_Handler_Debug */ + /* USER CODE BEGIN Error_Handler_Debug */ + /* User can add his own implementation to report the HAL error return state + */ + __disable_irq(); + while (1) + { + } + /* USER CODE END Error_Handler_Debug */ } #ifdef USE_FULL_ASSERT /** - * @brief Reports the name of the source file and the source line number - * where the assert_param error has occurred. - * @param file: pointer to the source file name - * @param line: assert_param error line source number - * @retval None - */ + * @brief Reports the name of the source file and the source line number + * where the assert_param error has occurred. + * @param file: pointer to the source file name + * @param line: assert_param error line source number + * @retval None + */ void assert_failed(uint8_t *file, uint32_t line) { - /* USER CODE BEGIN 6 */ - /* User can add his own implementation to report the file name and line number, - ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ - /* USER CODE END 6 */ + /* USER CODE BEGIN 6 */ + /* User can add code to report the file name and line number, + for example: printf("Wrong parameter: %s:%d\r\n", file, line) */ + /* USER CODE END 6 */ } #endif /* USE_FULL_ASSERT */ diff --git a/Modbus/Inc/modbus_rtu_slave.h b/Modbus/Inc/modbus_rtu_slave.h index cd6702c..e13bed2 100644 --- a/Modbus/Inc/modbus_rtu_slave.h +++ b/Modbus/Inc/modbus_rtu_slave.h @@ -14,77 +14,67 @@ extern "C" * 任务要求规定线圈和保持寄存器地址范围均为 0~0x270F, * 因此每种数据共有 10000 项 */ -#define MODBUS_MAP_LAST_ADDRESS (0x270FU)//保持寄存器或线圈地址 -#define MODBUS_MAP_ITEM_COUNT (0x2710U)//保持寄存器或线圈数量 +#define MODBUS_MAP_LAST_ADDRESS (0x270FU) // 保持寄存器或线圈地址 +#define MODBUS_MAP_ITEM_COUNT (0x2710U) // 保持寄存器或线圈数量 - - - -#define MODBUS_SLAVE_DEFAULT_ADDRESS (1U) -#define MODBUS_CONNECTION_TIMEOUT_MS (1000U) +#define MODBUS_SLAVE_DEFAULT_ADDRESS (1U) +#define MODBUS_CONNECTION_TIMEOUT_MS (1000U) /** * @brief 与 TouchWin 触摸屏联调使用的演示地址 * * 可以直接访问以下地址 */ -#define HMI_REG_DEVICE_ID (0U) -#define HMI_REG_UPTIME_SECONDS (1U) -#define HMI_REG_RX_FRAME_COUNT (2U) - +#define HMI_REG_DEVICE_ID (0U) +#define HMI_REG_UPTIME_SECONDS (1U) +#define HMI_REG_RX_FRAME_COUNT (2U) -#define HMI_REG_WRITE_TEST (10U) -#define HMI_COIL_WRITE_TEST (0U) +#define HMI_REG_WRITE_TEST (10U) +#define HMI_COIL_WRITE_TEST (0U) +#define MODBUS_RETAINED_D_START (100U) +#define MODBUS_RETAINED_D_END (120U) +#define MODBUS_RETAINED_D_COUNT (21U) -#define MODBUS_RETAINED_D_START (100U) -#define MODBUS_RETAINED_D_END (120U) -#define MODBUS_RETAINED_D_COUNT (21U) - -#define MODBUS_BACKUP_MAGIC (0x44313030UL) +#define MODBUS_BACKUP_MAGIC (0x44313030UL) +/** + * @brief 掉电保持寄存器在Backup SRAM中的存储格式 + */ typedef struct { - uint32_t magic; - uint16_t retainedD[MODBUS_RETAINED_D_COUNT]; + uint32_t magic; ///< 掉电保持数据有效标志 + uint16_t retainedD[MODBUS_RETAINED_D_COUNT]; ///< D100~D120保持值 } MODBUS_BACKUP_DATA; - -static volatile MODBUS_BACKUP_DATA *backupData =(volatile MODBUS_BACKUP_DATA *)BKPSRAM_BASE; - - - - /** * @brief Modbus 从站通信统计信息 */ typedef struct { - uint32_t rxEventCount; ///< 串口接收事件总数 - uint32_t validFrameCount; ///< CRC 和从站地址均有效的帧数 - uint32_t txFrameCount; ///< 成功启动 DMA 发送的帧数 - uint32_t crcErrorCount; ///< CRC 校验错误帧数 - uint32_t ignoredAddressCount; ///< 因从站地址不匹配而忽略的帧数 - uint32_t illegalFunctionCount; ///< 非法功能码计数 - uint32_t illegalAddressCount; ///< 非法数据地址计数 - uint32_t illegalValueCount; ///< 非法数据值计数 - uint32_t droppedFrameCount; ///< 接收槽占用或长度错误导致的丢帧数 - uint32_t uartErrorCount; ///< HAL 串口错误计数 + uint32_t rxEventCount; ///< 串口接收事件总数 + uint32_t validFrameCount; ///< CRC 和从站地址均有效的帧数 + uint32_t txFrameCount; ///< 成功启动 DMA 发送的帧数 + uint32_t crcErrorCount; ///< CRC 校验错误帧数 + uint32_t ignoredAddressCount; ///< 因从站地址不匹配而忽略的帧数 + uint32_t illegalFunctionCount; ///< 非法功能码计数 + uint32_t illegalAddressCount; ///< 非法数据地址计数 + uint32_t illegalValueCount; ///< 非法数据值计数 + uint32_t droppedFrameCount; ///< 接收槽占用或长度错误导致的丢帧数 + uint32_t uartErrorCount; ///< HAL 串口错误计数 } MODBUS_SLAVE_STATS; - +/** + * @brief 一次Modbus RTU通信的历史记录 + */ typedef struct { - uint32_t tick; - - uint16_t requestLength; - uint16_t responseLength; - - uint8_t request[256]; - uint8_t response[256]; + uint32_t tick; ///< 通信发生时的系统时间 + uint16_t requestLength; ///< 请求ADU长度 + uint16_t responseLength; ///< 响应ADU长度 + uint8_t request[256]; ///< 请求ADU数据 + uint8_t response[256]; ///< 响应ADU数据 } MODBUS_HISTORY_ITEM; - /** @brief Modbus 从站通信统计数据 */ extern volatile MODBUS_SLAVE_STATS ModbusSlaveStatistics; - /** * @brief 初始化 Modbus 从站并启动 USART DMA 空闲接收 * @param[in] huart 已由 HAL 初始化完成的串口句柄 @@ -93,9 +83,8 @@ extern volatile MODBUS_SLAVE_STATS ModbusSlaveStatistics; * @retval HAL_ERROR 输入参数无效 * @retval HAL_BUSY 串口或 DMA 当前忙 */ -HAL_StatusTypeDef ModbusSlaveInit(UART_HandleTypeDef *huart, uint8_t slaveAddress); - - +HAL_StatusTypeDef ModbusSlaveInit(UART_HandleTypeDef *huart, + uint8_t slaveAddress); /** * @brief 校验并处理一帧待处理请求 * @@ -103,54 +92,54 @@ HAL_StatusTypeDef ModbusSlaveInit(UART_HandleTypeDef *huart, uint8_t slaveAddres * CRC 校验、协议解析和响应发送均在任务上下文中执行 */ void ModbusSlavePoll(void); - /** * @brief 处理 HAL 串口 DMA 接收事件 * @param[in] huart 产生接收事件的串口句柄 * @param[in] size 本次接收到的字节数 */ void ModbusSlaveOnRxEvent(UART_HandleTypeDef *huart, uint16_t size); - /** * @brief 处理 HAL 串口 DMA 发送完成事件 * @param[in] huart 完成发送的串口句柄 */ void ModbusSlaveOnTxComplete(UART_HandleTypeDef *huart); - /** * @brief 处理 HAL 串口错误事件并恢复接收 * @param[in] huart 发生错误的串口句柄 */ void ModbusSlaveOnUartError(UART_HandleTypeDef *huart); - /** * @brief 写入一个保持寄存器 * @param[in] address 保持寄存器地址 * @param[in] value 待写入的 16 位数据 + * @retval 1 写入成功 + * @retval 0 保持寄存器地址无效 */ uint8_t ModbusSlaveSetHoldingRegister(uint16_t address, uint16_t value); - /** * @brief 读取一个保持寄存器 * @param[in] address 保持寄存器地址 * @param[out] value 用于保存读取结果的指针 + * @retval 1 读取成功 + * @retval 0 保持寄存器地址无效或输出指针为空 */ uint8_t ModbusSlaveGetHoldingRegister(uint16_t address, uint16_t *value); - /** * @brief 设置一个线圈的状态 * @param[in] address 线圈地址 * @param[in] state 0 表示复位,非 0 表示置位 + * @retval 1 设置成功 + * @retval 0 线圈地址无效 */ uint8_t ModbusSlaveSetCoil(uint16_t address, uint8_t state); - /** * @brief 读取一个线圈的状态 * @param[in] address 线圈地址 * @param[out] state 用于保存线圈状态的指针,结果为 0 或 1 + * @retval 1 读取成功 + * @retval 0 线圈地址无效或输出指针为空 */ uint8_t ModbusSlaveGetCoil(uint16_t address, uint8_t *state); - /** * @brief 判断指定时间内是否收到过有效请求 * @param[in] timeoutMs 连接超时时间,单位为毫秒 @@ -161,12 +150,7 @@ uint8_t ModbusSlaveIsConnected(uint32_t timeoutMs); void ModbusRetainedRegistersLoad(void); void ModbusRetainedRegistersPoll(void); void HistorySaveToRegisters(void); -static void ModbusHistorySave( - uint32_t tick, - const uint8_t *request, - uint16_t requestLength, - const uint8_t *response, - uint16_t responseLength); + #ifdef __cplusplus } #endif diff --git a/Modbus/Src/modbus_rtu_slave.c b/Modbus/Src/modbus_rtu_slave.c index 4bb2ebe..290267f 100644 --- a/Modbus/Src/modbus_rtu_slave.c +++ b/Modbus/Src/modbus_rtu_slave.c @@ -2,27 +2,32 @@ #include "ucos_ii.h" #include -#define MODBUS_RTU_ADU_SIZE_MAX (256U)//Modbus RTU 最大 ADU 长度,单位为字节 +#define MODBUS_RTU_ADU_SIZE_MAX (256U) // Modbus RTU 最大 ADU 长度,单位为字节 +#define MODBUS_RTU_T15_US (750UL) /* 高波特率下固定T1.5时间,单位us */ +#define MODBUS_RTU_T35_US (1750UL) /* 高波特率下固定T3.5时间,单位us */ +#define MODBUS_RTU_BITS_PER_CHAR (11UL) /* 8E1包含11个传输位 */ +#define MODBUS_RTU_HIGH_BAUD_LIMIT (19200UL) /* 高低波特率计算方式的分界值 */ -#define MODBUS_RTU_FRAME_GAP_MS (2U) +#define MODBUS_BROADCAST_ADDRESS (0U) // 广播地址 -#define MODBUS_BROADCAST_ADDRESS (0U)//广播地址 +#define MODBUS_EX_ILLEGAL_FUNCTION (0x01U) // 非法功能码的异常码 +#define MODBUS_EX_ILLEGAL_ADDRESS (0x02U) // 非法地址的异常码 +#define MODBUS_EX_ILLEGAL_VALUE (0x03U) // 非法数据的异常码 -#define MODBUS_EX_ILLEGAL_FUNCTION (0x01U)//非法功能码的异常码 -#define MODBUS_EX_ILLEGAL_ADDRESS (0x02U)//非法地址的异常码 -#define MODBUS_EX_ILLEGAL_VALUE (0x03U)//非法数据的异常码 +#define MODBUS_READ_COILS_MAX (2000U) // 一次ADU最大线圈读取数量 +#define MODBUS_READ_REGS_MAX (125U) // 一次ADU最大寄存器读取数量 +#define MODBUS_WRITE_COILS_MAX (1968U) // 一次ADU最大线圈写入数量 +#define MODBUS_WRITE_REGS_MAX (123U) // 一次ADU最大寄存器写入数量 -#define MODBUS_READ_COILS_MAX (2000U)//一次ADU最大线圈读取数量 -#define MODBUS_READ_REGS_MAX (125U) //一次ADU最大寄存器读取数量 -#define MODBUS_WRITE_COILS_MAX (1968U)//一次ADU最大线圈写入数量 -#define MODBUS_WRITE_REGS_MAX (123U) //一次ADU最大寄存器写入数量 - -#define MODBUS_COIL_VALUE_ON (0xFF00U) -#define MODBUS_COIL_VALUE_OFF (0x0000U) +#define MODBUS_COIL_VALUE_ON (0xFF00U) +#define MODBUS_COIL_VALUE_OFF (0x0000U) static UART_HandleTypeDef *ModbusUart; static uint8_t ModbusSlaveAddress; +static void ModbusHistorySave(uint32_t tick, const uint8_t *request, + uint16_t requestLength, const uint8_t *response, + uint16_t responseLength); static MODBUS_HISTORY_ITEM ModbusHistory[16]; static uint16_t ModbusHistoryWriteIndex; @@ -31,6 +36,8 @@ static uint16_t ModbusHistoryWriteIndex; * 随后由任务解析,避免 DMA 重启后覆盖尚未处理的数据 */ static uint8_t ModbusRxDmaBuffer[MODBUS_RTU_ADU_SIZE_MAX]; +/* 保存被UART IDLE事件分开的DMA片段,达到T3.5后再提交解析 */ +static uint8_t ModbusRxAssemblyBuffer[MODBUS_RTU_ADU_SIZE_MAX]; static uint8_t ModbusRxFrame[MODBUS_RTU_ADU_SIZE_MAX]; static uint8_t ModbusTxFrame[MODBUS_RTU_ADU_SIZE_MAX]; /* D100~D120 上一次已保存的值,用于检测数据是否变化 */ @@ -38,9 +45,16 @@ static uint16_t ModbusRetainedSnapshot[MODBUS_RETAINED_D_COUNT]; static volatile uint16_t ModbusRxFrameLength; static volatile uint8_t ModbusRxFrameReady; static volatile uint8_t ModbusTxBusy; -static volatile uint32_t ModbusRxEventTick; +static volatile uint16_t ModbusRxAssemblyLength; /* 当前拼帧长度 */ +static volatile uint8_t ModbusRxAssemblyInvalid; /* 帧内间隔超过T1.5时置1 */ +static volatile uint32_t ModbusRxLastByteCycle; /* 上一片段末字节结束时刻 */ +static uint32_t ModbusRtuT15Cycles; /* T1.5对应的CPU周期数 */ +static uint32_t ModbusRtuT35Cycles; /* T3.5对应的CPU周期数 */ +static uint32_t ModbusRtuCharCycles; /* 一个UART字符对应的CPU周期数 */ static volatile uint32_t ModbusLastValidFrameTick; static volatile uint8_t ModbusHasReceivedValidFrame; +static volatile MODBUS_BACKUP_DATA *ModbusBackupData = + (volatile MODBUS_BACKUP_DATA *)BKPSRAM_BASE; /** * 10000 个保持寄存器占用 20000 字节;10000 个线圈按位存储, @@ -48,7 +62,6 @@ static volatile uint8_t ModbusHasReceivedValidFrame; */ static uint16_t ModbusHoldingRegisters[40000]; - #pragma location = ".ccmram" #pragma data_alignment = 4 __root static uint16_t ModbusRegistersCcm[29999]; @@ -101,12 +114,13 @@ static uint16_t ModbusGetU16Be(const uint8_t *data) /** * @brief 提取一个 24 位无符号整数 - * @param[in] data 两个字节的数据地址 + * @param[in] data 3个字节的数据地址 * @return 转换后的 24 位无符号整数 */ static uint32_t ModbusGetU24Be(const uint8_t *data) { - return (uint32_t)((uint32_t)data[0] << 16U|((uint16_t)data[1] << 8U) | data[2]); + return (uint32_t)(((uint32_t)data[0] << 16U) | ((uint32_t)data[1] << 8U) + | (uint32_t)data[2]); } /** @@ -156,6 +170,107 @@ static void ModbusCoilSetUnchecked(uint16_t address, uint8_t state) } } +/** + * @brief 初始化用于RTU帧间隔测量的DWT周期计数器 + * @param[in] baudRate 当前串口波特率 + */ +static void ModbusRtuTimingInit(uint32_t baudRate) +{ + uint64_t coreClock; + /* 开启DWT周期计数器,CYCCNT每经过一个CPU时钟周期自动加1 */ + CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; + DWT->CYCCNT = 0U; + DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; + + coreClock = SystemCoreClock; + /* 一个字符周期数=CPU频率*每字符位数/波特率 */ + ModbusRtuCharCycles = + (uint32_t)((coreClock * MODBUS_RTU_BITS_PER_CHAR) / baudRate); + + if (baudRate > MODBUS_RTU_HIGH_BAUD_LIMIT) + { + /* 高波特率使用固定750us和1750us,999999用于向上取整 */ + ModbusRtuT15Cycles = + (uint32_t)((coreClock * MODBUS_RTU_T15_US + 999999UL) / 1000000UL); + + ModbusRtuT35Cycles = + (uint32_t)((coreClock * MODBUS_RTU_T35_US + 999999UL) / 1000000UL); + } + else + { + /* 低波特率按照1.5个字符时间和3.5个字符时间计算 */ + ModbusRtuT15Cycles = + (uint32_t)(((uint64_t)ModbusRtuCharCycles * 3UL + 1UL) / 2UL); + ModbusRtuT35Cycles = + (uint32_t)(((uint64_t)ModbusRtuCharCycles * 7UL + 1UL) / 2UL); + } +} + +/** + * @brief 结束当前RTU接收组帧 + * @note 调用本函数时必须保证不会与串口接收中断并发执行 + */ +static void ModbusRxAssemblyFinalize(void) +{ + if (ModbusRxAssemblyLength == 0U) + { + return; + } + /*拼帧区是否有数据*/ + if ((ModbusRxAssemblyInvalid == 0U) && (ModbusRxFrameReady == 0U)) + { + /* 当前帧未违反T1.5且解析缓冲区空闲时提交完整帧 */ + (void)memcpy(ModbusRxFrame, ModbusRxAssemblyBuffer, + ModbusRxAssemblyLength); + ModbusRxFrameLength = ModbusRxAssemblyLength; + ModbusRxFrameReady = 1U; + } + else + { + /* T1.5无效帧或上一帧尚未处理完成时丢弃 */ + ModbusSlaveStatistics.droppedFrameCount++; + } + + ModbusRxAssemblyLength = 0U; + ModbusRxAssemblyInvalid = 0U; +} + +/** + * @brief 静默时间达到T3.5后,将接收数据交给协议解析任务 + */ +static void ModbusTryFinalizeReceive(void) +{ + uint32_t now; + + if (ModbusRxAssemblyLength == 0U) + { + return; + } + + /* DMA缓冲区出现新数据时,说明串口仍在接收当前片段 */ + if ((ModbusUart->hdmarx != NULL) && /*串口DMA使能*/ + ((ModbusUart->Instance->CR3 & USART_CR3_DMAR) != 0U) + && (__HAL_DMA_GET_COUNTER(ModbusUart->hdmarx) + < MODBUS_RTU_ADU_SIZE_MAX)) + { + return; + } + + now = DWT->CYCCNT; + /* 从末字节结束时刻开始计算静默时间,未达到T3.5时继续等待 */ + if ((uint32_t)(now - ModbusRxLastByteCycle) < ModbusRtuT35Cycles) + { + return; + } + + /* 静默达到T3.5,当前RTU帧结束,发送响应前停止接收DMA */ + (void)HAL_UART_AbortReceive(ModbusUart); + + __disable_irq(); + ModbusRxAssemblyFinalize(); + __enable_irq(); +} + /** * @brief 启动 USART DMA 空闲接收 * @retval HAL_OK DMA 接收启动成功 @@ -171,8 +286,7 @@ static HAL_StatusTypeDef ModbusStartReceive(void) return HAL_BUSY; } - status = HAL_UARTEx_ReceiveToIdle_DMA(ModbusUart, - ModbusRxDmaBuffer, + status = HAL_UARTEx_ReceiveToIdle_DMA(ModbusUart, ModbusRxDmaBuffer, sizeof(ModbusRxDmaBuffer)); if ((status == HAL_OK) && (ModbusUart->hdmarx != NULL)) @@ -187,8 +301,6 @@ static HAL_StatusTypeDef ModbusStartReceive(void) return status; } - - /** * @brief 在 RTU 帧末尾追加 CRC 低字节和高字节 * @param[in,out] frame 待追加 CRC 的帧缓冲区 @@ -225,9 +337,10 @@ static uint16_t ModbusBuildException(uint8_t function, uint8_t exception) * @param[in] requestLength 请求帧长度 * @return 待发送响应长度,异常请求返回异常响应长度 */ -static uint16_t ModbusProcessReadCoils(const uint8_t *request, uint16_t requestLength) +static uint16_t ModbusProcessReadCoils(const uint8_t *request, + uint16_t requestLength) { - + uint16_t start; uint16_t quantity; uint16_t index; @@ -242,13 +355,14 @@ static uint16_t ModbusProcessReadCoils(const uint8_t *request, uint16_t requestL start = ModbusGetU16Be(&request[2]); quantity = ModbusGetU16Be(&request[4]); - if ((quantity == 0U) || (quantity > MODBUS_READ_COILS_MAX))//数量0或者数量大于最大值 + if ((quantity == 0U) + || (quantity > MODBUS_READ_COILS_MAX)) // 数量0或者数量大于最大值 { ModbusSlaveStatistics.illegalValueCount++; return ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_VALUE); } - if (ModbusAddressRangeIsValid(start, quantity) == 0U)//地址检查 + if (ModbusAddressRangeIsValid(start, quantity) == 0U) // 地址检查 { ModbusSlaveStatistics.illegalAddressCount++; return ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_ADDRESS); @@ -264,8 +378,8 @@ static uint16_t ModbusProcessReadCoils(const uint8_t *request, uint16_t requestL { if (ModbusCoilGetUnchecked((uint16_t)(start + index)) != 0U) { - ModbusTxFrame[3U + (index >> 3U)] |= (uint8_t)(1U << (index & 0x0007U)); - + ModbusTxFrame[3U + (index >> 3U)] |= + (uint8_t)(1U << (index & 0x0007U)); } } @@ -279,8 +393,9 @@ static uint16_t ModbusProcessReadCoils(const uint8_t *request, uint16_t requestL * @param[in] requestLength 请求帧长度 * @return 待发送响应长度,异常请求返回异常响应长度 */ -static uint16_t ModbusProcessReadHolding(const uint8_t *request,uint16_t requestLength) - +static uint16_t ModbusProcessReadHolding(const uint8_t *request, + uint16_t requestLength) + { uint16_t start; uint16_t quantity; @@ -296,22 +411,22 @@ static uint16_t ModbusProcessReadHolding(const uint8_t *request,uint16_t request start = ModbusGetU16Be(&request[2]); quantity = ModbusGetU16Be(&request[4]); - if ((quantity == 0U) || (quantity > MODBUS_READ_REGS_MAX))//数量0或者数量大于最大值 + if ((quantity == 0U) + || (quantity > MODBUS_READ_REGS_MAX)) // 数量0或者数量大于最大值 { ModbusSlaveStatistics.illegalValueCount++; return ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_VALUE); } - - if (ModbusAddressRangeIsValid(start, quantity) == 0U)//地址检查 + + if (ModbusAddressRangeIsValid(start, quantity) == 0U) // 地址检查 { - if ((start >= 20000U) && - (start < 25000U) && - (quantity > 0U) && - (quantity <= (25000U - start)))goto tx; + if ((start >= 20000U) && (start < 25000U) && (quantity > 0U) + && (quantity <= (25000U - start))) + goto tx; ModbusSlaveStatistics.illegalAddressCount++; return ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_ADDRESS); } - tx: +tx: ModbusTxFrame[0] = ModbusSlaveAddress; ModbusTxFrame[1] = 0X03; ModbusTxFrame[2] = (uint8_t)(quantity * 2U); @@ -319,7 +434,7 @@ static uint16_t ModbusProcessReadHolding(const uint8_t *request,uint16_t request for (index = 0U; index < quantity; index++) { uint16_t address = start + index; - /* D20000~D24999映射到D1、D3、D5……D9999 */ + /* D20000~D24999映射到D1、D3、D5……D9999 */ if (address >= 20000U) { address = (address - 20000U) * 2U + 1U; @@ -331,79 +446,75 @@ static uint16_t ModbusProcessReadHolding(const uint8_t *request,uint16_t request ModbusAppendCrc(ModbusTxFrame, (uint16_t)(3U + quantity * 2U)); return (uint16_t)(5U + quantity * 2U); - - - - } - /* -* 返回帧 -*从站地址 | 14 | 总字节数 | 子响应长度 | 06 | 寄存器数据 | CRC -* -* 01 从站地址 -* 14 功能码 -* 06 后续响应数据共6字节 -* 05 当前子响应长度,共5字节 -* 06 引用类型 -* 12 34 第一个寄存器 -* 56 78 第二个寄存器 -*/ -static uint16_t ModbusProcessFile(const uint8_t *request,uint16_t requestLength) + * 返回帧 + *从站地址 | 14 | 总字节数 | 子响应长度 | 06 | 寄存器数据 | CRC + * + * 01 从站地址 + * 14 功能码 + * 06 后续响应数据共6字节 + * 05 当前子响应长度,共5字节 + * 06 引用类型 + * 12 34 第一个寄存器 + * 56 78 第二个寄存器 + */ +static uint16_t ModbusProcessFile(const uint8_t *request, + uint16_t requestLength) { uint16_t fileNumber; uint16_t recordNumber; uint16_t quantity; uint16_t index; uint16_t value; - uint16_t*p; + uint16_t *historyRegister; if (requestLength != 12U) { ModbusSlaveStatistics.illegalValueCount++; return ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_VALUE); } - if ((request[2] != 7U) || (request[3] != 0x06U)) + if ((request[2] != 7U) || (request[3] != 0x06U)) { ModbusSlaveStatistics.illegalValueCount++; - return ModbusBuildException( request[1],MODBUS_EX_ILLEGAL_VALUE); + return ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_VALUE); } quantity = ModbusGetU16Be(&request[8]); fileNumber = ModbusGetU16Be(&request[4]); recordNumber = ModbusGetU16Be(&request[6]); - if ((quantity == 0U) || (quantity > 124U))//数量0或者数量大于最大值 + if ((quantity == 0U) || (quantity > 124U)) // 数量0或者数量大于最大值 { ModbusSlaveStatistics.illegalValueCount++; return ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_VALUE); } - if (fileNumber>15||recordNumber>=260||((uint32_t)recordNumber + quantity) > 260UL)//地址检查 + /* 检查文件号、记录号和读取范围 */ + if ((fileNumber > 15U) || (recordNumber >= 260U) + || (((uint32_t)recordNumber + quantity) > 260UL)) { ModbusSlaveStatistics.illegalAddressCount++; return ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_ADDRESS); } ModbusTxFrame[0] = ModbusSlaveAddress; ModbusTxFrame[1] = 0X14; - ModbusTxFrame[2] =(uint8_t)(2U + quantity * 2U); - ModbusTxFrame[3] =(uint8_t)(1U + quantity * 2U); - + ModbusTxFrame[2] = (uint8_t)(2U + quantity * 2U); + ModbusTxFrame[3] = (uint8_t)(1U + quantity * 2U); + ModbusTxFrame[4] = 0X06; - p = (uint16_t*)ModbusHistory; + historyRegister = (uint16_t *)ModbusHistory; for (index = 0U; index < quantity; index++) { - uint16_t address = fileNumber*260+recordNumber + index; + uint16_t address = fileNumber * 260 + recordNumber + index; - value = *(p+address); + value = *(historyRegister + address); ModbusTxFrame[5U + index * 2U] = (uint8_t)(value & 0x00FFU); ModbusTxFrame[6U + index * 2U] = (uint8_t)(value >> 8U); } ModbusAppendCrc(ModbusTxFrame, (uint16_t)(5U + quantity * 2U)); return (uint16_t)(7U + quantity * 2U); - } - /** * @brief 处理写单个保持寄存器功能码 0x06 * @param[in] request RTU 请求帧 @@ -411,10 +522,9 @@ static uint16_t ModbusProcessFile(const uint8_t *request,uint16_t requestLength) * @param[in] isBroadcast 非 0 表示当前请求为广播 * @return 单播响应长度;广播或无法响应时返回 0 */ -static uint16_t ModbusProcessWriteSingleRegister( - const uint8_t *request, - uint16_t requestLength, - uint8_t isBroadcast) +static uint16_t ModbusProcessWriteSingleRegister(const uint8_t *request, + uint16_t requestLength, + uint8_t isBroadcast) { uint16_t address; uint16_t value; @@ -422,8 +532,9 @@ static uint16_t ModbusProcessWriteSingleRegister( if (requestLength != 8U) { ModbusSlaveStatistics.illegalValueCount++; - return (isBroadcast != 0U) ? 0U : - ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_VALUE); + return (isBroadcast != 0U) + ? 0U + : ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_VALUE); } address = ModbusGetU16Be(&request[2]); @@ -432,8 +543,9 @@ static uint16_t ModbusProcessWriteSingleRegister( if (address >= MODBUS_MAP_ITEM_COUNT) { ModbusSlaveStatistics.illegalAddressCount++; - return (isBroadcast != 0U) ? 0U : - ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_ADDRESS); + return (isBroadcast != 0U) ? 0U + : ModbusBuildException( + request[1], MODBUS_EX_ILLEGAL_ADDRESS); } ModbusHoldingRegisters[address] = value; @@ -456,10 +568,9 @@ static uint16_t ModbusProcessWriteSingleRegister( * @param[in] isBroadcast 非 0 表示当前请求为广播 * @return 单播响应长度;广播或无法响应时返回 0 */ -static uint16_t ModbusProcessWriteSingleCoil( - const uint8_t *request, - uint16_t requestLength, - uint8_t isBroadcast) +static uint16_t ModbusProcessWriteSingleCoil(const uint8_t *request, + uint16_t requestLength, + uint8_t isBroadcast) { uint16_t address; uint16_t value; @@ -467,8 +578,9 @@ static uint16_t ModbusProcessWriteSingleCoil( if (requestLength != 8U) { ModbusSlaveStatistics.illegalValueCount++; - return (isBroadcast != 0U) ? 0U : - ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_VALUE); + return (isBroadcast != 0U) + ? 0U + : ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_VALUE); } address = ModbusGetU16Be(&request[2]); @@ -478,24 +590,23 @@ static uint16_t ModbusProcessWriteSingleCoil( * 0x05 只接受 0xFF00(线圈置位)和 0x0000(线圈复位); * 其他数值属于非法数据值 */ - if ((value != MODBUS_COIL_VALUE_ON) - && (value != MODBUS_COIL_VALUE_OFF)) + if ((value != MODBUS_COIL_VALUE_ON) && (value != MODBUS_COIL_VALUE_OFF)) { ModbusSlaveStatistics.illegalValueCount++; - return (isBroadcast != 0U) ? 0U : - ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_VALUE); + return (isBroadcast != 0U) + ? 0U + : ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_VALUE); } if (address >= MODBUS_MAP_ITEM_COUNT) { ModbusSlaveStatistics.illegalAddressCount++; - return (isBroadcast != 0U) ? 0U : - ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_ADDRESS); + return (isBroadcast != 0U) ? 0U + : ModbusBuildException( + request[1], MODBUS_EX_ILLEGAL_ADDRESS); } - ModbusCoilSetUnchecked( - address, - (value == MODBUS_COIL_VALUE_ON) ? 1U : 0U); + ModbusCoilSetUnchecked(address, (value == MODBUS_COIL_VALUE_ON) ? 1U : 0U); if (isBroadcast != 0U) { @@ -515,10 +626,9 @@ static uint16_t ModbusProcessWriteSingleCoil( * @param[in] isBroadcast 非 0 表示当前请求为广播 * @return 单播响应长度;广播或无法响应时返回 0 */ -static uint16_t ModbusProcessWriteMultipleCoils( - const uint8_t *request, - uint16_t requestLength, - uint8_t isBroadcast) +static uint16_t ModbusProcessWriteMultipleCoils(const uint8_t *request, + uint16_t requestLength, + uint8_t isBroadcast) { uint16_t start; uint16_t quantity; @@ -529,8 +639,9 @@ static uint16_t ModbusProcessWriteMultipleCoils( if (requestLength < 9U) { ModbusSlaveStatistics.illegalValueCount++; - return (isBroadcast != 0U) ? 0U : - ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_VALUE); + return (isBroadcast != 0U) + ? 0U + : ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_VALUE); } start = ModbusGetU16Be(&request[2]); @@ -538,30 +649,30 @@ static uint16_t ModbusProcessWriteMultipleCoils( byteCount = request[6]; expectedByteCount = (uint8_t)((quantity + 7U) / 8U); - if ((quantity == 0U) - || (quantity > MODBUS_WRITE_COILS_MAX) + if ((quantity == 0U) || (quantity > MODBUS_WRITE_COILS_MAX) || (byteCount != expectedByteCount) || (requestLength != (uint16_t)(9U + byteCount))) { ModbusSlaveStatistics.illegalValueCount++; - return (isBroadcast != 0U) ? 0U : - ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_VALUE); + return (isBroadcast != 0U) + ? 0U + : ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_VALUE); } if (ModbusAddressRangeIsValid(start, quantity) == 0U) { ModbusSlaveStatistics.illegalAddressCount++; - return (isBroadcast != 0U) ? 0U : - ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_ADDRESS); + return (isBroadcast != 0U) ? 0U + : ModbusBuildException( + request[1], MODBUS_EX_ILLEGAL_ADDRESS); } for (index = 0U; index < quantity; index++) { uint8_t state; - state = (uint8_t)((request[7U + (index >> 3U)] - >> (index & 0x0007U)) - & 0x01U); + state = (uint8_t)((request[7U + (index >> 3U)] >> (index & 0x0007U)) + & 0x01U); ModbusCoilSetUnchecked((uint16_t)(start + index), state); } @@ -584,10 +695,9 @@ static uint16_t ModbusProcessWriteMultipleCoils( * @param[in] isBroadcast 非 0 表示当前请求为广播 * @return 单播响应长度;广播或无法响应时返回 0 */ -static uint16_t ModbusProcessWriteMultipleRegisters( - const uint8_t *request, - uint16_t requestLength, - uint8_t isBroadcast) +static uint16_t ModbusProcessWriteMultipleRegisters(const uint8_t *request, + uint16_t requestLength, + uint8_t isBroadcast) { uint16_t start; uint16_t quantity; @@ -597,29 +707,31 @@ static uint16_t ModbusProcessWriteMultipleRegisters( if (requestLength < 9U) { ModbusSlaveStatistics.illegalValueCount++; - return (isBroadcast != 0U) ? 0U : - ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_VALUE); + return (isBroadcast != 0U) + ? 0U + : ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_VALUE); } start = ModbusGetU16Be(&request[2]); quantity = ModbusGetU16Be(&request[4]); byteCount = request[6]; - if ((quantity == 0U) - || (quantity > MODBUS_WRITE_REGS_MAX) + if ((quantity == 0U) || (quantity > MODBUS_WRITE_REGS_MAX) || (byteCount != (uint8_t)(quantity * 2U)) || (requestLength != (uint16_t)(9U + byteCount))) { ModbusSlaveStatistics.illegalValueCount++; - return (isBroadcast != 0U) ? 0U : - ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_VALUE); + return (isBroadcast != 0U) + ? 0U + : ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_VALUE); } if (ModbusAddressRangeIsValid(start, quantity) == 0U) { ModbusSlaveStatistics.illegalAddressCount++; - return (isBroadcast != 0U) ? 0U : - ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_ADDRESS); + return (isBroadcast != 0U) ? 0U + : ModbusBuildException( + request[1], MODBUS_EX_ILLEGAL_ADDRESS); } for (index = 0U; index < quantity; index++) @@ -640,16 +752,14 @@ static uint16_t ModbusProcessWriteMultipleRegisters( return 8U; } - /** * @brief 处理读取扩展地址保持寄存器功能码0x48 * @param[in] request RTU请求帧 * @param[in] requestLength 请求帧长度 * @return 待发送响应长度,异常请求返回异常响应长度 */ -static uint16_t ModbusProcessReadBigHolding( - const uint8_t *request, - uint16_t requestLength) +static uint16_t ModbusProcessReadBigHolding(const uint8_t *request, + uint16_t requestLength) { uint32_t start; uint32_t currentAddress; @@ -662,9 +772,7 @@ static uint16_t ModbusProcessReadBigHolding( { ModbusSlaveStatistics.illegalValueCount++; - return ModbusBuildException( - request[1], - MODBUS_EX_ILLEGAL_VALUE); + return ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_VALUE); } /* 提取24位起始地址和16位寄存器数量 */ @@ -672,14 +780,11 @@ static uint16_t ModbusProcessReadBigHolding( quantity = ModbusGetU16Be(&request[5]); /* 一次最多读取125个寄存器 */ - if ((quantity == 0U) || - (quantity > MODBUS_READ_REGS_MAX)) + if ((quantity == 0U) || (quantity > MODBUS_READ_REGS_MAX)) { ModbusSlaveStatistics.illegalValueCount++; - return ModbusBuildException(request[1],MODBUS_EX_ILLEGAL_VALUE); - - + return ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_VALUE); } /* @@ -687,13 +792,11 @@ static uint16_t ModbusProcessReadBigHolding( * 总地址范围为0~69998 */ if ((start >= 69999UL) || ((uint32_t)quantity > (69999UL - start))) - + { ModbusSlaveStatistics.illegalAddressCount++; - return ModbusBuildException(request[1],MODBUS_EX_ILLEGAL_ADDRESS); - - + return ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_ADDRESS); } /* 组成正常响应帧头 */ @@ -716,17 +819,15 @@ static uint16_t ModbusProcessReadBigHolding( else { value = ModbusRegistersCcm[currentAddress - 40000UL]; - } /* 每个寄存器按照高字节、低字节装入响应帧 */ ModbusTxFrame[3U + index * 2U] = (uint8_t)(value >> 8U); ModbusTxFrame[4U + index * 2U] = (uint8_t)(value & 0x00FFU); - } /* 添加CRC */ - ModbusAppendCrc( ModbusTxFrame, (uint16_t)(3U + quantity * 2U)); - + ModbusAppendCrc(ModbusTxFrame, (uint16_t)(3U + quantity * 2U)); + return (uint16_t)(5U + quantity * 2U); } @@ -736,7 +837,8 @@ static uint16_t ModbusProcessReadBigHolding( * @param[in] requestLength 请求帧长度 * @return 待发送响应长度;无需响应时返回 0 */ -static uint16_t ModbusProcessRequest(const uint8_t *request,uint16_t requestLength) +static uint16_t ModbusProcessRequest(const uint8_t *request, + uint16_t requestLength) { uint16_t calculatedCrc; uint16_t receivedCrc; @@ -748,78 +850,86 @@ static uint16_t ModbusProcessRequest(const uint8_t *request,uint16_t requestLeng } calculatedCrc = ModbusCrc16(request, (uint16_t)(requestLength - 2U)); - receivedCrc = - (uint16_t)(request[requestLength - 2U] - | ((uint16_t)request[requestLength - 1U] << 8U)); + receivedCrc = (uint16_t)(request[requestLength - 2U] + | ((uint16_t)request[requestLength - 1U] << 8U)); - if (calculatedCrc != receivedCrc)//CRC校验 + if (calculatedCrc != receivedCrc) // CRC校验 { ModbusSlaveStatistics.crcErrorCount++; return 0U; } if ((request[0] != ModbusSlaveAddress) - && (request[0] != MODBUS_BROADCAST_ADDRESS))//非法从站地址 + && (request[0] != MODBUS_BROADCAST_ADDRESS)) // 非法从站地址 { ModbusSlaveStatistics.ignoredAddressCount++; return 0U; } - isBroadcast = (request[0] == MODBUS_BROADCAST_ADDRESS) ? 1U : 0U;//是否广播请求 + isBroadcast = + (request[0] == MODBUS_BROADCAST_ADDRESS) ? 1U : 0U; // 是否广播请求 ModbusSlaveStatistics.validFrameCount++; ModbusLastValidFrameTick = HAL_GetTick(); ModbusHasReceivedValidFrame = 1U; switch (request[1]) { - case 0X01U://读线圈 - // 广播请求不允许读取,从站不作响应 - return (isBroadcast != 0U) ? 0U : - ModbusProcessReadCoils(request, requestLength); + case 0X01U: // 读线圈 + // 广播请求不允许读取,从站不作响应 + return (isBroadcast != 0U) + ? 0U + : ModbusProcessReadCoils(request, requestLength); - case 0X03U://读保持寄存器 - return (isBroadcast != 0U) ? 0U : - ModbusProcessReadHolding(request, requestLength); + case 0X03U: // 读保持寄存器 + return (isBroadcast != 0U) + ? 0U + : ModbusProcessReadHolding(request, requestLength); case 0x14U: - return (isBroadcast != 0U) ? 0U : - ModbusProcessFile(request,requestLength); + return (isBroadcast != 0U) + ? 0U + : ModbusProcessFile(request, requestLength); - case 0x05U://写单个线圈 - return ModbusProcessWriteSingleCoil(request, - requestLength, + case 0x05U: // 写单个线圈 + return ModbusProcessWriteSingleCoil(request, requestLength, isBroadcast); - case 0x06U://写单个保持寄存器 - return ModbusProcessWriteSingleRegister(request, - requestLength, + case 0x06U: // 写单个保持寄存器 + return ModbusProcessWriteSingleRegister(request, requestLength, isBroadcast); - case 0x0FU://写多个线圈 - return ModbusProcessWriteMultipleCoils(request, - requestLength, - isBroadcast); + case 0x0FU: // 写多个线圈 + return ModbusProcessWriteMultipleCoils(request, requestLength, + isBroadcast); - case 0x10U://写多个保持寄存器 - return ModbusProcessWriteMultipleRegisters(request, - requestLength, - isBroadcast); + case 0x10U: // 写多个保持寄存器 + return ModbusProcessWriteMultipleRegisters(request, requestLength, + isBroadcast); - case 0x48U://读大地址保持寄存器 - return ModbusProcessReadBigHolding(request, requestLength); - - default://未知功能码 + case 0x48U: // 读大地址保持寄存器 + return ModbusProcessReadBigHolding(request, requestLength); + + default: // 未知功能码 ModbusSlaveStatistics.illegalFunctionCount++; - return (isBroadcast != 0U) ? 0U : - ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_FUNCTION); + return (isBroadcast != 0U) + ? 0U + : ModbusBuildException(request[1], + MODBUS_EX_ILLEGAL_FUNCTION); } } HAL_StatusTypeDef ModbusSlaveInit(UART_HandleTypeDef *huart, - uint8_t slaveAddress) + uint8_t slaveAddress) + { ModbusUart = huart; ModbusSlaveAddress = slaveAddress; + /* 清空拼帧状态并根据当前波特率初始化T1.5和T3.5 */ + ModbusRxAssemblyLength = 0U; + ModbusRxAssemblyInvalid = 0U; + ModbusRxFrameReady = 0U; + ModbusTxBusy = 0U; + ModbusRtuTimingInit(huart->Init.BaudRate); ModbusHoldingRegisters[HMI_REG_DEVICE_ID] = 0xF407U; @@ -830,28 +940,23 @@ void ModbusSlavePoll(void) { uint16_t responseLength; + /* 检查末字节后的静默时间是否已经达到T3.5 */ + ModbusTryFinalizeReceive(); if ((ModbusRxFrameReady == 0U) || (ModbusTxBusy != 0U)) { return; } - - responseLength = ModbusProcessRequest(ModbusRxFrame, ModbusRxFrameLength); - ModbusHistorySave(OSTimeGet() / 1000,ModbusRxFrame, - ModbusRxFrameLength, - ModbusTxFrame, - responseLength); - - + ModbusHistorySave(OSTimeGet() / 1000, ModbusRxFrame, ModbusRxFrameLength, + ModbusTxFrame, responseLength); if (responseLength > 0U) { ModbusTxBusy = 1U; - if (HAL_UART_Transmit_DMA(ModbusUart, - ModbusTxFrame, - responseLength) == HAL_OK) + if (HAL_UART_Transmit_DMA(ModbusUart, ModbusTxFrame, responseLength) + == HAL_OK) { ModbusSlaveStatistics.txFrameCount++; } @@ -859,12 +964,12 @@ void ModbusSlavePoll(void) { ModbusTxBusy = 0U; ModbusSlaveStatistics.uartErrorCount++; - (void)ModbusStartReceive();//重启DMA接收 + (void)ModbusStartReceive(); // 重启DMA接收 } } - else + else { - (void)ModbusStartReceive(); + (void)ModbusStartReceive(); } /* @@ -875,28 +980,78 @@ void ModbusSlavePoll(void) void ModbusSlaveOnRxEvent(UART_HandleTypeDef *huart, uint16_t size) { + HAL_UART_RxEventTypeTypeDef eventType; + uint32_t now; + uint32_t lastByteCycle; + uint32_t firstByteCycle; + uint32_t chunkCycles; + uint32_t interFrameGap; - ModbusSlaveStatistics.rxEventCount++;//串口接收事件计数 + ModbusSlaveStatistics.rxEventCount++; // 串口接收事件计数 + + if ((huart != ModbusUart) || (ModbusUart == NULL)) + { + return; + } if ((size > 0U) && (size <= MODBUS_RTU_ADU_SIZE_MAX)) { - if (ModbusRxFrameReady == 0U) + now = DWT->CYCCNT; + eventType = HAL_UARTEx_GetRxEventType(huart); + + /* IDLE事件比末字节结束晚约一个字符时间,减去字符时间得到末字节时刻 */ + lastByteCycle = now; + if (eventType == HAL_UART_RXEVENT_IDLE) + { + lastByteCycle -= ModbusRtuCharCycles; + } + + /* 根据本次接收字节数反推DMA片段首字节的开始时刻 */ + chunkCycles = (uint32_t)((uint64_t)size * ModbusRtuCharCycles); + firstByteCycle = lastByteCycle - chunkCycles; + + if (ModbusRxAssemblyLength > 0U) + { + interFrameGap = (uint32_t)(firstByteCycle - ModbusRxLastByteCycle); + + if (interFrameGap >= ModbusRtuT35Cycles) + { + /* 间隔达到T3.5,结束上一帧,本片段作为新帧开始 */ + ModbusRxAssemblyFinalize(); + } + else if (interFrameGap > ModbusRtuT15Cycles) + { + /* 帧内静默超过T1.5但不足T3.5,标记整帧无效 */ + ModbusRxAssemblyInvalid = 1U; + } + else + { + /* 间隔不超过T1.5,当前片段继续拼入同一帧 */ + } + } + + if (size + <= (uint16_t)(MODBUS_RTU_ADU_SIZE_MAX - ModbusRxAssemblyLength)) { - (void)memcpy(ModbusRxFrame, ModbusRxDmaBuffer, size); - ModbusRxFrameLength = size; - ModbusRxEventTick = HAL_GetTick(); - ModbusRxFrameReady = 1U; + (void)memcpy(&ModbusRxAssemblyBuffer[ModbusRxAssemblyLength], + ModbusRxDmaBuffer, size); + ModbusRxAssemblyLength += size; } else { - //前一帧未处理完毕 - ModbusSlaveStatistics.droppedFrameCount++; + ModbusRxAssemblyInvalid = 1U; } + + /* 保存末字节时刻并立即重启DMA,继续等待可能的后续片段 */ + ModbusRxLastByteCycle = lastByteCycle; + (void)ModbusStartReceive(); } else { - //长度异常帧 + // 长度异常帧 ModbusSlaveStatistics.droppedFrameCount++; + ModbusRxAssemblyLength = 0U; + ModbusRxAssemblyInvalid = 0U; (void)ModbusStartReceive(); } } @@ -909,7 +1064,7 @@ void ModbusSlaveOnTxComplete(UART_HandleTypeDef *huart) } ModbusTxBusy = 0U; - (void)ModbusStartReceive();//重启DMA接收 + (void)ModbusStartReceive(); // 重启DMA接收 } void ModbusSlaveOnUartError(UART_HandleTypeDef *huart) @@ -921,8 +1076,10 @@ void ModbusSlaveOnUartError(UART_HandleTypeDef *huart) ModbusSlaveStatistics.uartErrorCount++; ModbusTxBusy = 0U; - (void)HAL_UART_Abort(huart);//立即终止这个串口当前正在进行的发送和接收操作 - (void)ModbusStartReceive();//重启DMA接收 + ModbusRxAssemblyLength = 0U; + ModbusRxAssemblyInvalid = 0U; + (void)HAL_UART_Abort(huart); // 立即终止这个串口当前正在进行的发送和接收操作 + (void)ModbusStartReceive(); // 重启DMA接收 } uint8_t ModbusSlaveSetHoldingRegister(uint16_t address, uint16_t value) @@ -976,77 +1133,66 @@ uint8_t ModbusSlaveIsConnected(uint32_t timeoutMs) return 0U; } - return ((HAL_GetTick() - ModbusLastValidFrameTick) <= timeoutMs) - ? 1U - : 0U; + return ((HAL_GetTick() - ModbusLastValidFrameTick) <= timeoutMs) ? 1U : 0U; } -//上电恢复函数 +// 上电恢复函数 void ModbusRetainedRegistersLoad(void) { uint16_t index; - if (backupData->magic == MODBUS_BACKUP_MAGIC) + if (ModbusBackupData->magic == MODBUS_BACKUP_MAGIC) { - for (index = 0U; index < MODBUS_RETAINED_D_COUNT;index++) + for (index = 0U; index < MODBUS_RETAINED_D_COUNT; index++) { - ModbusHoldingRegisters[MODBUS_RETAINED_D_START + index] = - backupData->retainedD[index]; + ModbusHoldingRegisters[MODBUS_RETAINED_D_START + index] = + ModbusBackupData->retainedD[index]; } } else { - for (index = 0U;index < MODBUS_RETAINED_D_COUNT;index++) + for (index = 0U; index < MODBUS_RETAINED_D_COUNT; index++) { - ModbusHoldingRegisters[ - MODBUS_RETAINED_D_START + index] = 0U; + ModbusHoldingRegisters[MODBUS_RETAINED_D_START + index] = 0U; - backupData->retainedD[index] = 0U; + ModbusBackupData->retainedD[index] = 0U; } /* * 数据初始化完成后最后写magic,避免初始化中途断电 * 却把不完整数据标记成有效 */ - backupData->magic = MODBUS_BACKUP_MAGIC; + ModbusBackupData->magic = MODBUS_BACKUP_MAGIC; } } void ModbusRetainedRegistersPoll(void) { uint16_t index; - // uint16_t address; uint16_t value; - for(index=0;indexretainedD[index]=value; + ModbusBackupData->retainedD[index] = value; } ModbusRetainedSnapshot[index] = value; } - - - - } -static void ModbusHistorySave( - uint32_t tick, - const uint8_t *request, - uint16_t requestLength, - const uint8_t *response, - uint16_t responseLength) +static void ModbusHistorySave(uint32_t tick, const uint8_t *request, + uint16_t requestLength, const uint8_t *response, + uint16_t responseLength) { MODBUS_HISTORY_ITEM *item; - if(requestLength > 256U) + if (requestLength > 256U) { requestLength = 256U; } - if(responseLength > 256U) + if (responseLength > 256U) { responseLength = 256U; } @@ -1057,36 +1203,27 @@ static void ModbusHistorySave( item->requestLength = requestLength; item->responseLength = responseLength; - (void)memcpy( - item->request, - request, - requestLength); + (void)memcpy(item->request, request, requestLength); - if(responseLength > 0U) + if (responseLength > 0U) { - (void)memcpy( - item->response, - response, - responseLength); + (void)memcpy(item->response, response, responseLength); } ModbusHistoryWriteIndex++; - if(ModbusHistoryWriteIndex >= 16U) + if (ModbusHistoryWriteIndex >= 16U) { ModbusHistoryWriteIndex = 0U; } } void HistorySaveToRegisters(void) { - // (void)memcpy( - // &ModbusHoldingRegisters[1000], - // ModbusHistory, - // sizeof(ModbusHistory)); + uint16_t index; - if(ModbusHistoryWriteIndex == 0U) + if (ModbusHistoryWriteIndex == 0U) { index = 15U; } @@ -1095,9 +1232,6 @@ void HistorySaveToRegisters(void) index = ModbusHistoryWriteIndex - 1U; } - (void)memcpy( - &ModbusHoldingRegisters[ - 1000U + index * 260U], - &ModbusHistory[index], - sizeof(ModbusHistory[index])); -} \ No newline at end of file + (void)memcpy(&ModbusHoldingRegisters[1000U + index * 260U], + &ModbusHistory[index], sizeof(ModbusHistory[index])); +}