No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.
 
 
 
 
 

741 líneas
20 KiB

  1. /**
  2. * @file main.c
  3. * @brief 基于 uC/OS-II 的 Modbus RTU 从站主程序。
  4. * @version 2.0
  5. * @author zengbingjie
  6. * @date 2026-07-29
  7. * @copyright 版权所有 (c) 2026 Xinje Electric。
  8. * @note 修改记录:2.0 增加帧隔离、连接状态和可靠收发处理。
  9. */
  10. #include "main.h"
  11. #include "modbus.h"
  12. #define APP_MODBUS_STATUS_REGISTER_COUNT (8U)
  13. #define APP_MODBUS_FUNCTION_INDEX (1U)
  14. static OS_STK AppTaskStartStk[APP_TASK_START_STK_SIZE];
  15. static OS_STK AppTaskModbusStk[APP_TASK_MODBUS_STK_SIZE];
  16. static OS_STK AppTaskT35Stk[APP_TASK_T35_STK_SIZE];
  17. UART_HandleTypeDef Uart1Handle;
  18. static MODBUS_SLAVE ModbusSlave;
  19. static OS_EVENT *ModbusFrameSem;
  20. static OS_EVENT *ModbusTxSem;
  21. static uint8_t ModbusRxBuffer[MODBUS_RX_BUF_SIZE];
  22. static uint8_t ModbusTxBuffer[MODBUS_TX_BUF_SIZE];
  23. static volatile uint16_t ModbusRxLength;
  24. static volatile uint16_t ModbusFrameLength;
  25. static volatile uint32_t ModbusLastRxTick;
  26. static volatile uint8_t ModbusFrameReady;
  27. static volatile uint8_t ModbusRxOverflow;
  28. static volatile uint32_t ModbusReceiveErrorCount;
  29. static volatile uint32_t ModbusSemaphoreErrorCount;
  30. static uint32_t ModbusLastActivityTick;
  31. static uint32_t ModbusOperationRxCount;
  32. static uint32_t ModbusOperationTxCount;
  33. static uint32_t ModbusProtocolErrorCount;
  34. static uint8_t ModbusHasActivity;
  35. static MODBUS_STATUS ModbusLastStatus;
  36. static GPIO_TypeDef *const AppOutputPorts[APP_MODBUS_OUTPUT_COIL_COUNT] = {
  37. PLC_Q0_PORT,
  38. PLC_Q1_PORT,
  39. PLC_Q2_PORT,
  40. PLC_Q3_PORT,
  41. PLC_Q4_PORT,
  42. PLC_Q5_PORT,
  43. PLC_Q6_PORT,
  44. PLC_Q7_PORT
  45. };
  46. static const uint16_t AppOutputPins[APP_MODBUS_OUTPUT_COIL_COUNT] = {
  47. PLC_Q0_PIN,
  48. PLC_Q1_PIN,
  49. PLC_Q2_PIN,
  50. PLC_Q3_PIN,
  51. PLC_Q4_PIN,
  52. PLC_Q5_PIN,
  53. PLC_Q6_PIN,
  54. PLC_Q7_PIN
  55. };
  56. void SystemClock_Config(void);
  57. static void AppTaskStart(void *argument);
  58. static void AppTaskModbus(void *argument);
  59. static void AppTaskT35(void *argument);
  60. static void AppInitGpio(void);
  61. static void AppInitUart1(void);
  62. static INT8U AppCreateTasks(void);
  63. static HAL_StatusTypeDef AppStartUartReception(void);
  64. static HAL_StatusTypeDef AppTransmitResponse(uint16_t txLength);
  65. static uint8_t AppSealReceivedFrame(void);
  66. static uint16_t AppGetReadyFrameLength(void);
  67. static INT8U AppPostModbusFrameSem(void);
  68. static uint8_t AppIsModbusStatusAccepted(MODBUS_STATUS status);
  69. static uint8_t AppIsModbusWriteFunction(uint8_t functionCode);
  70. static MODBUS_STATUS AppUpdateStatusRegisters(void);
  71. static MODBUS_STATUS AppSyncCoilsToGpio(void);
  72. static void AppProcessFrame(uint16_t rxLength);
  73. static void AppRecordIsrError(void);
  74. /**
  75. * @brief 应用程序入口。
  76. * @return 该函数不返回。
  77. */
  78. int main(void)
  79. {
  80. INT8U osError;
  81. HAL_Init();
  82. SystemClock_Config();
  83. AppInitGpio();
  84. AppInitUart1();
  85. OSInit();
  86. osError = OSTaskCreateExt(
  87. AppTaskStart, NULL,
  88. &AppTaskStartStk[APP_TASK_START_STK_SIZE - 1U],
  89. APP_TASK_START_PRIO, APP_TASK_START_PRIO, &AppTaskStartStk[0],
  90. APP_TASK_START_STK_SIZE, NULL,
  91. OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);
  92. if (osError != OS_ERR_NONE) {
  93. Error_Handler();
  94. }
  95. OSStart();
  96. while (1) {
  97. }
  98. }
  99. /**
  100. * @brief 配置 STM32F407 的 168 MHz 系统时钟。
  101. * @note 使用板载 12 MHz 外部晶振作为 PLL 时钟源。
  102. */
  103. void SystemClock_Config(void)
  104. {
  105. RCC_OscInitTypeDef oscillatorConfig = {0};
  106. RCC_ClkInitTypeDef clockConfig = {0};
  107. __HAL_RCC_PWR_CLK_ENABLE();
  108. __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
  109. oscillatorConfig.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  110. oscillatorConfig.HSEState = RCC_HSE_ON;
  111. oscillatorConfig.PLL.PLLState = RCC_PLL_ON;
  112. oscillatorConfig.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  113. oscillatorConfig.PLL.PLLM = 12U;
  114. oscillatorConfig.PLL.PLLN = 336U;
  115. oscillatorConfig.PLL.PLLP = RCC_PLLP_DIV2;
  116. oscillatorConfig.PLL.PLLQ = 7U;
  117. if (HAL_RCC_OscConfig(&oscillatorConfig) != HAL_OK) {
  118. Error_Handler();
  119. }
  120. clockConfig.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
  121. | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
  122. clockConfig.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  123. clockConfig.AHBCLKDivider = RCC_SYSCLK_DIV1;
  124. clockConfig.APB1CLKDivider = RCC_HCLK_DIV4;
  125. clockConfig.APB2CLKDivider = RCC_HCLK_DIV2;
  126. if (HAL_RCC_ClockConfig(&clockConfig, FLASH_LATENCY_5) != HAL_OK) {
  127. Error_Handler();
  128. }
  129. }
  130. /**
  131. * @brief 初始化 XDM-60T4-E 的 Q0 至 Q7 输出引脚。
  132. * @note 板卡输出为低电平有效,初始状态全部关闭。
  133. */
  134. static void AppInitGpio(void)
  135. {
  136. GPIO_InitTypeDef gpioConfig = {0};
  137. __HAL_RCC_GPIOE_CLK_ENABLE();
  138. __HAL_RCC_GPIOF_CLK_ENABLE();
  139. __HAL_RCC_GPIOI_CLK_ENABLE();
  140. gpioConfig.Mode = GPIO_MODE_OUTPUT_PP;
  141. gpioConfig.Pull = GPIO_PULLUP;
  142. gpioConfig.Speed = GPIO_SPEED_FREQ_LOW;
  143. gpioConfig.Pin = PLC_Q0_PIN | PLC_Q1_PIN | PLC_Q2_PIN | PLC_Q3_PIN;
  144. HAL_GPIO_Init(GPIOF, &gpioConfig);
  145. gpioConfig.Pin = PLC_Q4_PIN;
  146. HAL_GPIO_Init(GPIOI, &gpioConfig);
  147. gpioConfig.Pin = PLC_Q5_PIN | PLC_Q6_PIN | PLC_Q7_PIN;
  148. HAL_GPIO_Init(GPIOE, &gpioConfig);
  149. HAL_GPIO_WritePin(GPIOF, PLC_Q0_PIN | PLC_Q1_PIN | PLC_Q2_PIN
  150. | PLC_Q3_PIN, GPIO_PIN_SET);
  151. HAL_GPIO_WritePin(GPIOI, PLC_Q4_PIN, GPIO_PIN_SET);
  152. HAL_GPIO_WritePin(GPIOE, PLC_Q5_PIN | PLC_Q6_PIN | PLC_Q7_PIN,
  153. GPIO_PIN_SET);
  154. }
  155. /**
  156. * @brief 初始化 Modbus RTU 使用的 USART1。
  157. */
  158. static void AppInitUart1(void)
  159. {
  160. Uart1Handle.Instance = USART1;
  161. Uart1Handle.Init.BaudRate = APP_MODBUS_BAUD_RATE;
  162. Uart1Handle.Init.WordLength = UART_WORDLENGTH_8B;
  163. Uart1Handle.Init.StopBits = UART_STOPBITS_1;
  164. Uart1Handle.Init.Parity = UART_PARITY_NONE;
  165. Uart1Handle.Init.Mode = UART_MODE_TX_RX;
  166. Uart1Handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  167. Uart1Handle.Init.OverSampling = UART_OVERSAMPLING_16;
  168. if (HAL_UART_Init(&Uart1Handle) != HAL_OK) {
  169. Error_Handler();
  170. }
  171. }
  172. /**
  173. * @brief 创建 Modbus 工作任务与帧间隔检测任务。
  174. * @return uC/OS-II 错误码。
  175. */
  176. static INT8U AppCreateTasks(void)
  177. {
  178. INT8U osError;
  179. osError = OSTaskCreateExt(
  180. AppTaskModbus, NULL,
  181. &AppTaskModbusStk[APP_TASK_MODBUS_STK_SIZE - 1U],
  182. APP_TASK_MODBUS_PRIO, APP_TASK_MODBUS_PRIO,
  183. &AppTaskModbusStk[0], APP_TASK_MODBUS_STK_SIZE, NULL,
  184. OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);
  185. if (osError != OS_ERR_NONE) {
  186. return osError;
  187. }
  188. osError = OSTaskCreateExt(
  189. AppTaskT35, NULL, &AppTaskT35Stk[APP_TASK_T35_STK_SIZE - 1U],
  190. APP_TASK_T35_PRIO, APP_TASK_T35_PRIO, &AppTaskT35Stk[0],
  191. APP_TASK_T35_STK_SIZE, NULL,
  192. OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);
  193. return osError;
  194. }
  195. /**
  196. * @brief 启动任务,创建同步对象并启动应用任务。
  197. * @param[in] argument 未使用。
  198. */
  199. static void AppTaskStart(void *argument)
  200. {
  201. INT8U osError;
  202. (void)argument;
  203. ModbusFrameSem = OSSemCreate(0U);
  204. ModbusTxSem = OSSemCreate(0U);
  205. if ((ModbusFrameSem == NULL) || (ModbusTxSem == NULL)) {
  206. Error_Handler();
  207. }
  208. osError = AppCreateTasks();
  209. if (osError != OS_ERR_NONE) {
  210. Error_Handler();
  211. }
  212. OSTaskSuspend(OS_PRIO_SELF);
  213. while (1) {
  214. }
  215. }
  216. /**
  217. * @brief 清空接收状态并启动 USART1 单字节中断接收。
  218. * @return HAL 状态码。
  219. */
  220. static HAL_StatusTypeDef AppStartUartReception(void)
  221. {
  222. OS_CPU_SR cpu_sr = 0U;
  223. HAL_StatusTypeDef halStatus;
  224. OS_ENTER_CRITICAL();
  225. ModbusRxLength = 0U;
  226. ModbusFrameLength = 0U;
  227. ModbusFrameReady = 0U;
  228. ModbusRxOverflow = 0U;
  229. ModbusLastRxTick = OSTimeGet();
  230. OS_EXIT_CRITICAL();
  231. halStatus = HAL_UART_Receive_IT(&Uart1Handle, &ModbusRxBuffer[0], 1U);
  232. return halStatus;
  233. }
  234. /**
  235. * @brief 通过 USART1 发送 Modbus 从站响应帧。
  236. * @param[in] txLength 响应帧长度。
  237. * @return HAL 状态码。
  238. */
  239. static HAL_StatusTypeDef AppTransmitResponse(uint16_t txLength)
  240. {
  241. HAL_StatusTypeDef halStatus;
  242. INT8U osError;
  243. if ((txLength == 0U) || (txLength > MODBUS_TX_BUF_SIZE)) {
  244. return HAL_ERROR;
  245. }
  246. halStatus = HAL_UART_Transmit_IT(&Uart1Handle, ModbusTxBuffer, txLength);
  247. if (halStatus != HAL_OK) {
  248. return halStatus;
  249. }
  250. OSSemPend(ModbusTxSem, APP_MODBUS_TX_TIMEOUT_TICKS, &osError);
  251. if (osError != OS_ERR_NONE) {
  252. (void)HAL_UART_AbortTransmit_IT(&Uart1Handle);
  253. return HAL_TIMEOUT;
  254. }
  255. return HAL_OK;
  256. }
  257. /**
  258. * @brief 根据 T3.5 静默时间将接收缓冲区封存为完整帧。
  259. * @return 1 表示已封存完整帧;0 表示未满足封帧条件。
  260. */
  261. static uint8_t AppSealReceivedFrame(void)
  262. {
  263. OS_CPU_SR cpu_sr = 0U;
  264. HAL_StatusTypeDef halStatus;
  265. uint32_t currentTick;
  266. uint32_t elapsedTicks;
  267. uint8_t frameSealed;
  268. frameSealed = 0U;
  269. currentTick = OSTimeGet();
  270. OS_ENTER_CRITICAL();
  271. elapsedTicks = currentTick - ModbusLastRxTick;
  272. if ((ModbusRxLength > 0U) && (ModbusFrameReady == 0U)
  273. && (elapsedTicks >= APP_MODBUS_T35_TICKS)) {
  274. ModbusFrameLength = ModbusRxLength;
  275. ModbusFrameReady = 1U;
  276. frameSealed = 1U;
  277. }
  278. OS_EXIT_CRITICAL();
  279. if (frameSealed == 0U) {
  280. return 0U;
  281. }
  282. halStatus = HAL_UART_AbortReceive_IT(&Uart1Handle);
  283. if (halStatus != HAL_OK) {
  284. AppRecordIsrError();
  285. }
  286. if (AppPostModbusFrameSem() != OS_ERR_NONE) {
  287. AppRecordIsrError();
  288. }
  289. return 1U;
  290. }
  291. /**
  292. * @brief 原子读取已封存 Modbus 帧的长度。
  293. * @return 完整帧长度;无完整帧时返回 0。
  294. */
  295. static uint16_t AppGetReadyFrameLength(void)
  296. {
  297. OS_CPU_SR cpu_sr = 0U;
  298. uint16_t frameLength;
  299. frameLength = 0U;
  300. OS_ENTER_CRITICAL();
  301. if (ModbusFrameReady != 0U) {
  302. frameLength = ModbusFrameLength;
  303. }
  304. OS_EXIT_CRITICAL();
  305. return frameLength;
  306. }
  307. /**
  308. * @brief 通知 Modbus 任务处理完整帧或刷新通信状态。
  309. * @return uC/OS-II 错误码。
  310. */
  311. static INT8U AppPostModbusFrameSem(void)
  312. {
  313. INT8U osError;
  314. osError = OSSemPost(ModbusFrameSem);
  315. return osError;
  316. }
  317. /**
  318. * @brief 判断协议处理结果是否代表已寻址的有效通信。
  319. * @param[in] status Modbus 协议处理结果。
  320. * @return 1 表示有效通信;0 表示无效通信。
  321. */
  322. static uint8_t AppIsModbusStatusAccepted(MODBUS_STATUS status)
  323. {
  324. if ((status == MODBUS_STATUS_OK) || (status == MODBUS_STATUS_BROADCAST)
  325. || (status == MODBUS_STATUS_EXCEPTION)) {
  326. return 1U;
  327. }
  328. return 0U;
  329. }
  330. /**
  331. * @brief 判断功能码是否为触摸屏的写操作。
  332. * @param[in] functionCode Modbus 功能码。
  333. * @return 写操作返回 1,否则返回 0。
  334. */
  335. static uint8_t AppIsModbusWriteFunction(uint8_t functionCode)
  336. {
  337. switch (functionCode) {
  338. case MODBUS_FC_WRITE_SINGLE_COIL:
  339. case MODBUS_FC_WRITE_SINGLE_REG:
  340. case MODBUS_FC_WRITE_MULTIPLE_COILS:
  341. case MODBUS_FC_WRITE_MULTIPLE_REGS:
  342. return 1U;
  343. default:
  344. return 0U;
  345. }
  346. }
  347. /**
  348. * @brief 更新供触摸屏读取的通信状态寄存器。
  349. * @return 成功返回 MODBUS_STATUS_OK;失败返回错误状态。
  350. */
  351. static MODBUS_STATUS AppUpdateStatusRegisters(void)
  352. {
  353. MODBUS_STATUS status;
  354. uint32_t currentTick;
  355. uint8_t linkState;
  356. uint16_t registerValue;
  357. currentTick = OSTimeGet();
  358. linkState = APP_MODBUS_LINK_DISCONNECTED;
  359. if ((ModbusHasActivity != 0U)
  360. && ((currentTick - ModbusLastActivityTick)
  361. < APP_MODBUS_LINK_TIMEOUT_TICKS)) {
  362. linkState = APP_MODBUS_LINK_CONNECTED;
  363. }
  364. status = ModbusSetHoldingRegister(&ModbusSlave,
  365. APP_MODBUS_REG_LINK_STATE, linkState);
  366. if (status != MODBUS_STATUS_OK) {
  367. return status;
  368. }
  369. registerValue = (uint16_t)(ModbusOperationRxCount & 0xFFFFU);
  370. status = ModbusSetHoldingRegister(&ModbusSlave,
  371. APP_MODBUS_REG_OPERATION_RX_COUNT,
  372. registerValue);
  373. if (status != MODBUS_STATUS_OK) {
  374. return status;
  375. }
  376. registerValue = (uint16_t)(ModbusOperationTxCount & 0xFFFFU);
  377. status = ModbusSetHoldingRegister(&ModbusSlave,
  378. APP_MODBUS_REG_OPERATION_TX_COUNT,
  379. registerValue);
  380. if (status != MODBUS_STATUS_OK) {
  381. return status;
  382. }
  383. registerValue = (uint16_t)((ModbusProtocolErrorCount
  384. + ModbusReceiveErrorCount + ModbusSemaphoreErrorCount) & 0xFFFFU);
  385. status = ModbusSetHoldingRegister(&ModbusSlave,
  386. APP_MODBUS_REG_ERROR_COUNT,
  387. registerValue);
  388. if (status != MODBUS_STATUS_OK) {
  389. return status;
  390. }
  391. status = ModbusSetHoldingRegister(&ModbusSlave,
  392. APP_MODBUS_REG_SYSTEM_TICK_LOW,
  393. (uint16_t)(currentTick & 0xFFFFU));
  394. if (status != MODBUS_STATUS_OK) {
  395. return status;
  396. }
  397. status = ModbusSetHoldingRegister(&ModbusSlave,
  398. APP_MODBUS_REG_SYSTEM_TICK_HIGH,
  399. (uint16_t)(currentTick >> 16U));
  400. if (status != MODBUS_STATUS_OK) {
  401. return status;
  402. }
  403. status = ModbusSetHoldingRegister(&ModbusSlave,
  404. APP_MODBUS_REG_LAST_STATUS,
  405. (uint16_t)ModbusLastStatus);
  406. if (status != MODBUS_STATUS_OK) {
  407. return status;
  408. }
  409. status = ModbusSetHoldingRegister(&ModbusSlave,
  410. APP_MODBUS_REG_LAST_FRAME_LENGTH,
  411. ModbusFrameLength);
  412. return status;
  413. }
  414. /**
  415. * @brief 将线圈 0 至 7 的状态同步到 PLC Q0 至 Q7 输出。
  416. * @return 成功返回 MODBUS_STATUS_OK;失败返回错误状态。
  417. */
  418. static MODBUS_STATUS AppSyncCoilsToGpio(void)
  419. {
  420. MODBUS_STATUS status;
  421. uint16_t coilAddress;
  422. uint8_t coilValue;
  423. GPIO_PinState pinState;
  424. for (coilAddress = 0U; coilAddress < APP_MODBUS_OUTPUT_COIL_COUNT;
  425. coilAddress++) {
  426. status = ModbusGetCoil(&ModbusSlave, coilAddress, &coilValue);
  427. if (status != MODBUS_STATUS_OK) {
  428. return status;
  429. }
  430. pinState = (coilValue != 0U) ? GPIO_PIN_RESET : GPIO_PIN_SET;
  431. HAL_GPIO_WritePin(AppOutputPorts[coilAddress],
  432. AppOutputPins[coilAddress], pinState);
  433. }
  434. return MODBUS_STATUS_OK;
  435. }
  436. /**
  437. * @brief 处理已封存的 Modbus RTU 请求帧。
  438. * @param[in] rxLength 请求帧长度。
  439. */
  440. static void AppProcessFrame(uint16_t rxLength)
  441. {
  442. HAL_StatusTypeDef halStatus;
  443. MODBUS_STATUS status;
  444. uint16_t txLength;
  445. uint8_t isWriteOperation;
  446. isWriteOperation = 0U;
  447. if ((rxLength == 0U) || (rxLength > MODBUS_RX_BUF_SIZE)) {
  448. ModbusLastStatus = MODBUS_STATUS_FRAME_ERROR;
  449. ModbusProtocolErrorCount++;
  450. return;
  451. }
  452. if (ModbusRxOverflow != 0U) {
  453. ModbusLastStatus = MODBUS_STATUS_FRAME_ERROR;
  454. ModbusProtocolErrorCount++;
  455. return;
  456. }
  457. status = ModbusProcessFrame(&ModbusSlave, ModbusRxBuffer, rxLength,
  458. ModbusTxBuffer, MODBUS_TX_BUF_SIZE,
  459. &txLength);
  460. ModbusLastStatus = status;
  461. if (AppIsModbusStatusAccepted(status) != 0U) {
  462. ModbusLastActivityTick = OSTimeGet();
  463. ModbusHasActivity = 1U;
  464. if (AppIsModbusWriteFunction(
  465. ModbusRxBuffer[APP_MODBUS_FUNCTION_INDEX]) != 0U) {
  466. ModbusOperationRxCount++;
  467. isWriteOperation = 1U;
  468. }
  469. }
  470. else if (status != MODBUS_STATUS_IGNORED) {
  471. ModbusProtocolErrorCount++;
  472. }
  473. if ((status == MODBUS_STATUS_OK) || (status == MODBUS_STATUS_BROADCAST)) {
  474. status = AppSyncCoilsToGpio();
  475. if (status != MODBUS_STATUS_OK) {
  476. ModbusProtocolErrorCount++;
  477. }
  478. }
  479. status = AppUpdateStatusRegisters();
  480. if (status != MODBUS_STATUS_OK) {
  481. ModbusProtocolErrorCount++;
  482. }
  483. if (txLength > 0U) {
  484. halStatus = AppTransmitResponse(txLength);
  485. if (halStatus != HAL_OK) {
  486. ModbusProtocolErrorCount++;
  487. }
  488. else if (isWriteOperation != 0U) {
  489. ModbusOperationTxCount++;
  490. }
  491. }
  492. }
  493. /**
  494. * @brief 记录中断上下文中无法立即恢复的通信错误。
  495. */
  496. static void AppRecordIsrError(void)
  497. {
  498. ModbusReceiveErrorCount++;
  499. }
  500. /**
  501. * @brief Modbus 协议处理任务。
  502. * @param[in] argument 未使用。
  503. */
  504. static void AppTaskModbus(void *argument)
  505. {
  506. HAL_StatusTypeDef halStatus;
  507. INT8U osError;
  508. uint16_t rxLength;
  509. (void)argument;
  510. if (ModbusSlaveInit(&ModbusSlave, MODBUS_SLAVE_ADDR_DEFAULT)
  511. != MODBUS_STATUS_OK) {
  512. Error_Handler();
  513. }
  514. if (AppSyncCoilsToGpio() != MODBUS_STATUS_OK) {
  515. Error_Handler();
  516. }
  517. if (AppUpdateStatusRegisters() != MODBUS_STATUS_OK) {
  518. Error_Handler();
  519. }
  520. halStatus = AppStartUartReception();
  521. if (halStatus != HAL_OK) {
  522. Error_Handler();
  523. }
  524. while (1) {
  525. OSSemPend(ModbusFrameSem, 0U, &osError);
  526. if (osError != OS_ERR_NONE) {
  527. ModbusSemaphoreErrorCount++;
  528. continue;
  529. }
  530. rxLength = AppGetReadyFrameLength();
  531. if (rxLength > 0U) {
  532. AppProcessFrame(rxLength);
  533. halStatus = AppStartUartReception();
  534. if (halStatus != HAL_OK) {
  535. ModbusReceiveErrorCount++;
  536. }
  537. }
  538. else if (AppUpdateStatusRegisters() != MODBUS_STATUS_OK) {
  539. ModbusProtocolErrorCount++;
  540. }
  541. }
  542. }
  543. /**
  544. * @brief 定期检测接收静默时间并判断 Modbus RTU 帧结束。
  545. * @param[in] argument 未使用。
  546. */
  547. static void AppTaskT35(void *argument)
  548. {
  549. INT8U osError;
  550. uint16_t updateElapsedTicks;
  551. (void)argument;
  552. updateElapsedTicks = 0U;
  553. while (1) {
  554. OSTimeDly(APP_MODBUS_T35_CHECK_TICKS);
  555. (void)AppSealReceivedFrame();
  556. updateElapsedTicks += APP_MODBUS_T35_CHECK_TICKS;
  557. if (updateElapsedTicks >= APP_MODBUS_STATUS_UPDATE_TICKS) {
  558. updateElapsedTicks = 0U;
  559. osError = AppPostModbusFrameSem();
  560. if (osError != OS_ERR_NONE) {
  561. ModbusSemaphoreErrorCount++;
  562. }
  563. }
  564. }
  565. }
  566. /**
  567. * @brief USART1 单字节接收完成回调。
  568. * @param[in] uartHandle 触发回调的串口句柄。
  569. */
  570. void HAL_UART_RxCpltCallback(UART_HandleTypeDef *uartHandle)
  571. {
  572. HAL_StatusTypeDef halStatus;
  573. if ((uartHandle == NULL) || (uartHandle->Instance != USART1)) {
  574. return;
  575. }
  576. if (ModbusFrameReady != 0U) {
  577. return;
  578. }
  579. if (ModbusRxLength >= MODBUS_RX_BUF_SIZE) {
  580. ModbusRxOverflow = 1U;
  581. return;
  582. }
  583. ModbusRxLength++;
  584. ModbusLastRxTick = OSTimeGet();
  585. if (ModbusRxLength >= MODBUS_RX_BUF_SIZE) {
  586. ModbusRxOverflow = 1U;
  587. return;
  588. }
  589. halStatus = HAL_UART_Receive_IT(&Uart1Handle,
  590. &ModbusRxBuffer[ModbusRxLength], 1U);
  591. if (halStatus != HAL_OK) {
  592. AppRecordIsrError();
  593. }
  594. }
  595. /**
  596. * @brief USART1 通信错误回调。
  597. * @param[in] uartHandle 触发回调的串口句柄。
  598. */
  599. void HAL_UART_ErrorCallback(UART_HandleTypeDef *uartHandle)
  600. {
  601. if ((uartHandle == NULL) || (uartHandle->Instance != USART1)) {
  602. return;
  603. }
  604. ModbusRxOverflow = 1U;
  605. ModbusLastRxTick = OSTimeGet();
  606. AppRecordIsrError();
  607. }
  608. /**
  609. * @brief USART1 中断发送完成回调。
  610. * @param[in] uartHandle 触发回调的串口句柄。
  611. */
  612. void HAL_UART_TxCpltCallback(UART_HandleTypeDef *uartHandle)
  613. {
  614. INT8U osError;
  615. if ((uartHandle == NULL) || (uartHandle->Instance != USART1)) {
  616. return;
  617. }
  618. osError = OSSemPost(ModbusTxSem);
  619. if (osError != OS_ERR_NONE) {
  620. ModbusSemaphoreErrorCount++;
  621. }
  622. }
  623. /**
  624. * @brief 进入不可恢复错误状态。
  625. */
  626. void Error_Handler(void)
  627. {
  628. __disable_irq();
  629. while (1) {
  630. }
  631. }