/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @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 "main.h" #include "dma.h" #include "lwip.h" #include "tim.h" #include "usart.h" #include "gpio.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "modbus.h" #include "tim.h" #include "lwip.h" #include "tcpserver.h" /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN PV */ /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); /* USER CODE BEGIN PFP */ /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ uint8_t addr_array[7] = {0xee,0x00,0x00,0x00,0x00,0x00,0x00};//地址分配数组 int send_cnt = 0,hart_cnt = 0;//用于计时,超时10ms为收到回应,发送下一条指令 int send_flag = 0,hart_send_flag = 0;//发送标志 int send_num = 0,dina_num = 0,din_num = 0,ain_num = 0;//记录需要读取的模块数量 long test_cnt = 0; /* USER CODE END 0 */ /** * @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 END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_DMA_Init(); MX_USART1_UART_Init(); MX_USART3_UART_Init(); MX_USART6_UART_Init(); MX_LWIP_Init(); MX_TIM1_Init(); MX_TIM3_Init(); MX_TIM4_Init(); MX_TIM5_Init(); /* USER CODE BEGIN 2 */ HAL_TIM_Base_Start_IT(&htim1);//基础定时,定时1ms modbus_rtu_init();//modbus串口通讯初始化 modbus_host_init();//模块板间通讯初始化 tcp_server_init();//modbus网口TCP通讯及HART通讯初始化 /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ MX_LWIP_Process();//网线热插拔识别 if(send_flag)//间隔发送指令,超时10ms未接收到回应发送下条指令 { if(hart_flag == 0)//进行HART通讯时禁止modbus通讯发送,HART超时时间500ms { if(send_num == 0)//地址分配指令,根据回应判断当前连接模块数量 { uart_send(&huart6,addr_array,7); send_num++; } else if(write_coil_flag)//发生线圈寄存器写入事件时,同步更新对应模块卡的线圈寄存器数据 { writemulticoil_host(((write_coil_addr - COIL_ADD_MIN) / 8) * 5 + 1, 0x10, 0x08, CoilState[(write_coil_addr - COIL_ADD_MIN) / 8]); write_coil_flag = 0; } else if(write_hold_flag)//发生保持寄存器写入时间时,同步更新对应模块卡的保持寄存器数据 { writesinglereg_host((write_hold_addr / 4) * 5 + 4, write_hold_addr % 4, HoldReg[write_hold_addr - HOLD_REG_ADD_MIN]); write_hold_flag = 0; } else if(send_num < (addr_array[3] + addr_array[4] + addr_array[6] + 1))//根据需要读取的模块卡数量,循环读取卡内数据 { if(dina_num < addr_array[3])//namur型开关量输入数据读取 { readdisinputstate_host((dina_num * 5 + 2), 0, 8); dina_num ++; send_num++; } else if(din_num < addr_array[4])//基础开关量输入数据读取 { readdisinputstate_host((din_num * 5 + 3), 0, 8); din_num ++; send_num++; } else if(ain_num < addr_array[6])//模量量输入数据读取 { readinputreg_host((ain_num * 5 + 5), 0, 8); ain_num++; send_num++; } } else { send_num = 0; dina_num = 0; din_num = 0; ain_num = 0; } } else if(hart_flag == 1 && hart_send_flag == 0)//串口接收到HART指令转发到对应的模块卡 { hart_send_flag = 1; uart_send(&huart6,MODBUS_UART.rx_buf,MODBUS_UART.rx_size); } else if(hart_flag == 2 && hart_send_flag == 0)//网口接收到HART指令转发到对应的模块卡 { hart_send_flag = 1; uart_send(&huart6,tcp_rx_data,rx_data_len); } else if(hart_flag == 3 && hart_send_flag == 1)//收到HART数据回应,转发回应数据 { hart_cnt = 0; hart_flag = 0; hart_send_flag = 0; uart_send(&huart1,uart6_rx_buf,uart6_rx_size); tcp_write(server_pcb_hart,uart6_rx_buf,uart6_rx_size,1); } send_flag = 0; } if(it_1000ms_flag)//指示灯闪烁 { it_1000ms_flag = 0; HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin); HAL_GPIO_TogglePin(LED2_GPIO_Port,LED2_Pin); } } /* USER CODE END 3 */ } /** * @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 = 4; RCC_OscInitStruct.PLL.PLLN = 72; RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; RCC_OscInitStruct.PLL.PLLQ = 4; 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_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) { Error_Handler(); } } /* USER CODE BEGIN 4 */ int it_5ms_flag = 0; int it_5ms_cnt = 0; int it_1000ms_flag = 0; int it_1000ms_cnt = 0; /* *发送:[ee][00][DO模块数量][NAMURDI模块数量][DI模块数量][AO模块数量][AI模块数量] *接收:[ee][01][DO模块数量][NAMURDI模块数量][DI模块数量][AO模块数量][AI模块数量] */ void set_addr_cb(void) { int i = 0; if(uart6_rx_buf[0] == 0xee) { if(uart6_rx_buf[1] == 0x01) { for(i = 2;i < 7;i++) { addr_array[i] = uart6_rx_buf[i]; } } } if(uart3_rx_buf[0] == 0xee) { if(uart3_rx_buf[1] == 0x01) { for(i = 2;i < 7;i++) { addr_array[i] = uart3_rx_buf[i]; } } } } /* USER CODE END 4 */ /** * @brief Period elapsed callback in non blocking mode * @note This function is called when TIM7 interrupt took place, inside * HAL_TIM_IRQHandler(). It makes a direct call to HAL_IncTick() to increment * a global variable "uwTick" used as application time base. * @param htim : TIM handle * @retval None */ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { /* USER CODE BEGIN Callback 0 */ /* USER CODE END Callback 0 */ if (htim->Instance == TIM7) { HAL_IncTick(); } /* USER CODE BEGIN Callback 1 */ if(htim == &htim1) { test_cnt++; it_5ms_cnt++; if(it_5ms_cnt > 4) { it_5ms_flag = 1; it_5ms_cnt = 0; } it_1000ms_cnt++; if(it_1000ms_cnt > 999) { it_1000ms_flag = 1; it_1000ms_cnt = 0; } send_cnt++; if(send_cnt > 4){ send_flag = 1; send_cnt = 0;} if(hart_send_flag) { hart_cnt++; if(hart_cnt > 499) { hart_cnt = 0; hart_flag = 0; hart_send_flag = 0; } } } if(htim == &MODBUS_HTIM) { __HAL_TIM_CLEAR_FLAG(&MODBUS_HTIM, TIM_FLAG_UPDATE);//产生中断证明超过1ms没有接收到数据了,一帧接收完成 HAL_TIM_Base_Stop_IT(&MODBUS_HTIM); //中断之后停止定时器,开启在下一次接收到数据开始 MODBUS_UART.rx_size = MODBUS_UART.rx_buf_cnt; //将接收到数据数量赋值 MODBUS_UART.rx_buf_cnt = 0; //清零 modbus_process_rtu(); if(MODBUS_UART.rx_buf[0] == 0xAA && MODBUS_UART.rx_buf[1] == 0x55)//HART指令 hart_flag = 1; } if(htim == &htim4) { __HAL_TIM_CLEAR_FLAG(&htim4, TIM_FLAG_UPDATE); //产生中断证明超过1ms没有接收到数据了,一帧接收完成 HAL_TIM_Base_Stop_IT(&htim4); //中断之后停止定时器,开启在下一次接收到数据开始 uart3_rx_size = uart3_rx_cnt; //将接收到数据数量赋值 uart3_rx_cnt = 0; //清零 modbus_process_host(); set_addr_cb(); if(uart3_rx_buf[0] == 0xFF && uart3_rx_buf[1] == 0xFF)//HART指令回应 hart_flag = 3; send_cnt = 100; } if(htim == &htim5) { __HAL_TIM_CLEAR_FLAG(&htim5, TIM_FLAG_UPDATE); //产生中断证明超过1ms没有接收到数据了,一帧接收完成 HAL_TIM_Base_Stop_IT(&htim5); //中断之后停止定时器,开启在下一次接收到数据开始 uart6_rx_size = uart6_rx_cnt; //将接收到数据数量赋值 uart6_rx_cnt = 0; //清零 modbus_process_host(); set_addr_cb(); if(uart6_rx_buf[0] == 0xFF && uart6_rx_buf[1] == 0xFF)//HART指令回应 hart_flag = 3; send_cnt = 100; } /* USER CODE END Callback 1 */ } /** * @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 */ } #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 */ 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 */ } #endif /* USE_FULL_ASSERT */