/* * FreeModbus Libary: BARE Port * Copyright (C) 2006 Christian Walter * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * File: $Id$ */ #include "port.h" /* ----------------------- Modbus includes ----------------------------------*/ #include "mb.h" #include "mbport.h" #include "main.h" #include "usart.h" #include "elog.h" /* ----------------------- static functions ---------------------------------*/ static void prvvUARTTxReadyISR(void); static void prvvUARTRxISR(void); /* ----------------------- variables ---------------------------------*/ #define Modbus_USE_485 1 #define Modbus_UART_IRQHandler USART2_IRQHandler UART_HandleTypeDef *pMobusHuart = &huart2; #if Modbus_USE_485 #define MODBUS_485_Receive_Enable() HAL_GPIO_WritePin( NULL, 0, RESET ); #define MODBUS_485_Send_Enable() HAL_GPIO_WritePin( NULL, 0, SET ); #endif volatile uint32_t it_num = 0; volatile uint32_t aa = 0; volatile uint32_t bb = 0; volatile uint32_t cc = 0; #ifndef FREERTOS_USED /* ----------------------- Start implementation -----------------------------*/ void vMBPortSerialEnable(BOOL xRxEnable, BOOL xTxEnable) { if (xRxEnable) { #if Modbus_USE_485 for (size_t i = 0; i < 22000; i++); // 485 拉低准备接收 延时以免漏掉发送的最后字节 MODBUS_485_Receive_Enable(); #endif __HAL_UART_ENABLE_IT(pMobusHuart, UART_IT_RXNE); } else { #if Modbus_USE_485 MODBUS_485_Send_Enable(); #endif __HAL_UART_DISABLE_IT(pMobusHuart, UART_IT_RXNE); } if (xTxEnable) { #if Modbus_USE_485 MODBUS_485_Send_Enable(); #endif __HAL_UART_ENABLE_IT(pMobusHuart, UART_IT_TXE); } else { #if Modbus_USE_485 MODBUS_485_Send_Enable(); #endif __HAL_UART_DISABLE_IT(pMobusHuart, UART_IT_TXE); } } BOOL xMBPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity) { // pMobusHuart->Instance = USART2; pMobusHuart->Init.BaudRate = ulBaudRate; pMobusHuart->Init.StopBits = UART_STOPBITS_1; pMobusHuart->Init.Mode = UART_MODE_TX_RX; pMobusHuart->Init.HwFlowCtl = UART_HWCONTROL_NONE; pMobusHuart->Init.OverSampling = UART_OVERSAMPLING_16; switch (eParity) { // 奇校验 case MB_PAR_ODD: pMobusHuart->Init.Parity = UART_PARITY_ODD; pMobusHuart->Init.WordLength = UART_WORDLENGTH_9B; // 带奇偶校验数据位为9bits break; // 偶校验 case MB_PAR_EVEN: pMobusHuart->Init.Parity = UART_PARITY_EVEN; pMobusHuart->Init.WordLength = UART_WORDLENGTH_9B; // 带奇偶校验数据位为9bits break; // 无校验 default: pMobusHuart->Init.Parity = UART_PARITY_NONE; pMobusHuart->Init.WordLength = UART_WORDLENGTH_8B; // 无奇偶校验数据位为8bits break; } /* 防止启用时进入中断*/ __HAL_UART_CLEAR_FLAG(pMobusHuart, UART_FLAG_RXNE); __HAL_UART_CLEAR_FLAG(pMobusHuart, UART_FLAG_TXE); __HAL_UART_DISABLE_IT(pMobusHuart, UART_IT_RXNE); __HAL_UART_DISABLE_IT(pMobusHuart, UART_IT_TXE); return HAL_UART_Init(pMobusHuart) == HAL_OK ? TRUE : FALSE; } BOOL xMBPortSerialPutByte(CHAR ucByte) { /* Put a byte in the UARTs transmit buffer. This function is called * by the protocol stack if pxMBFrameCBTransmitterEmpty( ) has been * called. */ pMobusHuart->Instance->DR = ucByte; return TRUE; // return (HAL_OK == HAL_UART_Transmit(pMobusHuart, (uint8_t *)&ucByte, 1, 10)); } BOOL xMBPortSerialGetByte(CHAR *pucByte) { /* Return the byte in the UARTs receive buffer. This function is called * by the protocol stack after pxMBFrameCBByteReceived( ) has been called. */ *pucByte = (uint8_t)(pMobusHuart->Instance->DR & (uint8_t)0x00FF); return TRUE; } /* Create an interrupt handler for the transmit buffer empty interrupt * (or an equivalent) for your target processor. This function should then * call pxMBFrameCBTransmitterEmpty( ) which tells the protocol stack that * a new character can be sent. The protocol stack will then call * xMBPortSerialPutByte( ) to send the character. */ static void prvvUARTTxReadyISR(void) { pxMBFrameCBTransmitterEmpty(); } /* Create an interrupt handler for the receive interrupt for your target * processor. This function should then call pxMBFrameCBByteReceived( ). The * protocol stack will then call xMBPortSerialGetByte( ) to retrieve the * character. */ static void prvvUARTRxISR(void) { // log_i( " modbus rcv one byte....... "); pxMBFrameCBByteReceived(); } void USART2_IRQHandler(void) { aa++; // if(__HAL_UART_GET_FLAG(&huart2, UART_FLAG_RXNE)) // 接收非空中断标记被置位 // { // bb++; // __HAL_UART_CLEAR_FLAG(pMobusHuart, UART_FLAG_RXNE); // 清除中断标记 // prvvUARTRxISR(); // 通知modbus有数据到达 // } // if(__HAL_UART_GET_FLAG(&huart2, UART_FLAG_TXE)) // 发送为空中断标记被置位 // { // cc++; // __HAL_UART_CLEAR_FLAG(pMobusHuart, UART_FLAG_TXE); // 清除中断标记 // prvvUARTTxReadyISR(); // 通知modbus数据可以发松 // } if (__HAL_UART_GET_IT_SOURCE(pMobusHuart, UART_IT_RXNE) != RESET && __HAL_UART_GET_FLAG(&huart2, UART_FLAG_RXNE) != RESET ) { bb++; __HAL_UART_CLEAR_FLAG(pMobusHuart, UART_FLAG_RXNE); // 清除中断标记 prvvUARTRxISR(); // 通知freemodbus有数据到达 } if (__HAL_UART_GET_IT_SOURCE(pMobusHuart, UART_IT_TXE) != RESET && __HAL_UART_GET_FLAG(&huart2, UART_FLAG_TXE) != RESET ) { cc++; __HAL_UART_CLEAR_FLAG(pMobusHuart, UART_FLAG_TXE); // 清除中断标记 prvvUARTTxReadyISR(); // 通知modbus数据可以发松 } if (__HAL_UART_GET_FLAG(pMobusHuart, UART_FLAG_ORE)) { /* deal with uart rcv buffer ORE*/ // uint16_t pucByte = (uint16_t)((pMobusHuart)->Instance->DR & (uint16_t)0x01FF); __HAL_UART_CLEAR_OREFLAG(pMobusHuart); } HAL_UART_IRQHandler(pMobusHuart); } #else /* ----------------------- System includes ----------------------------------*/ #include #include #include /* ----------------------- Static variables ---------------------------------*/ /* software simulation serial transmit IRQ handler thread */ static TaskHandle_t thread_serial_soft_trans_irq = NULL; /* serial event */ static EventGroupHandle_t event_serial; /* 消息队列取代 */ /* modbus slave serial device */ static UART_HandleTypeDef *serial; /* * Serial FIFO mode */ static volatile uint8_t rx_buff[FIFO_SIZE_MAX]; static Serial_fifo Slave_serial_rx_fifo; /* ----------------------- Defines ------------------------------------------*/ /* serial transmit event */ #define EVENT_SERIAL_TRANS_START (1 << 0) /* ----------------------- static functions ---------------------------------*/ static void prvvUARTTxReadyISR(void); static void prvvUARTRxISR(void); static void serial_soft_trans_irq(void *parameter); static void Slave_TxCpltCallback(struct __UART_HandleTypeDef *huart); static void Slave_RxCpltCallback(struct __UART_HandleTypeDef *huart); static int stm32_getc(void); static int stm32_putc(CHAR c); /* ----------------------- Start implementation -----------------------------*/ BOOL xMBPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity) { /** * set 485 mode receive and transmit control IO * @note MODBUS_SLAVE_RT_CONTROL_PIN_INDEX need be defined by user */ // rt_pin_mode(MODBUS_SLAVE_RT_CONTROL_PIN_INDEX, PIN_MODE_OUTPUT); /* set serial name */ if (ucPORT == 1) { #if defined(USING_UART1) extern UART_HandleTypeDef huart1; serial = &huart1; MODBUS_DEBUG("Slave using uart1!\r\n"); #endif } else if (ucPORT == 2) { #if defined(USING_UART2) extern UART_HandleTypeDef huart2; serial = &huart2; MODBUS_DEBUG("Slave using uart2!\r\n"); #endif } else if (ucPORT == 3) { #if defined(USING_UART3) extern UART_HandleTypeDef huart3; serial = &huart3; MODBUS_DEBUG("Slave using uart3!\r\n"); #endif } /* set serial configure */ serial->Init.StopBits = UART_STOPBITS_1; serial->Init.BaudRate = ulBaudRate; switch (eParity) { case MB_PAR_NONE: { serial->Init.WordLength = UART_WORDLENGTH_8B; serial->Init.Parity = UART_PARITY_NONE; break; } case MB_PAR_ODD: { serial->Init.WordLength = UART_WORDLENGTH_9B; serial->Init.Parity = UART_PARITY_ODD; break; } case MB_PAR_EVEN: { serial->Init.WordLength = UART_WORDLENGTH_9B; serial->Init.Parity = UART_PARITY_EVEN; break; } } if (HAL_UART_Init(serial) != HAL_OK) { Error_Handler(); } __HAL_UART_DISABLE_IT(serial, UART_IT_RXNE); __HAL_UART_DISABLE_IT(serial, UART_IT_TC); /*registe recieve callback*/ HAL_UART_RegisterCallback(serial, HAL_UART_RX_COMPLETE_CB_ID, Slave_RxCpltCallback); /* software initialize */ Slave_serial_rx_fifo.buffer = rx_buff; Slave_serial_rx_fifo.get_index = 0; Slave_serial_rx_fifo.put_index = 0; /* 创建串口发送线程*/ event_serial = xEventGroupCreate(); // 创建事件 if (NULL != event_serial) { MODBUS_DEBUG("Create Slave event_serial Event success!\r\n"); } else { MODBUS_DEBUG("Create Slave event_serial Event Faild!\r\n"); } BaseType_t xReturn = xTaskCreate((TaskFunction_t)serial_soft_trans_irq, /* 任务函数*/ (const char *)"slave trans", /* 任务名称*/ (uint16_t)128, /* 栈*/ (void *)NULL, /* 入口参数 */ (UBaseType_t)12, /* 优先级*/ (TaskHandle_t *)&thread_serial_soft_trans_irq); /*任务句柄*/ if (xReturn == pdPASS) { MODBUS_DEBUG("xTaskCreate slave trans success\r\n"); } return TRUE; } void vMBPortSerialEnable(BOOL xRxEnable, BOOL xTxEnable) { /*清除中断标志,这一步不要省略*/ __HAL_UART_CLEAR_FLAG(serial, UART_FLAG_RXNE); __HAL_UART_CLEAR_FLAG(serial, UART_FLAG_TC); if (xRxEnable) { /* enable RX interrupt */ __HAL_UART_ENABLE_IT(serial, UART_IT_RXNE); /* switch 485 to receive mode */ MODBUS_DEBUG("RS485_RX_MODE\r\n"); SLAVE_RS485_RX_MODE; } else { /* switch 485 to transmit mode */ MODBUS_DEBUG("RS485_TX_MODE\r\n"); SLAVE_RS485_TX_MODE; /* disable RX interrupt */ __HAL_UART_DISABLE_IT(serial, UART_IT_RXNE); } if (xTxEnable) { /* start serial transmit */ xEventGroupSetBits(event_serial, EVENT_SERIAL_TRANS_START); } else { /* stop serial transmit */ xEventGroupClearBits(event_serial, EVENT_SERIAL_TRANS_START); /*测试帧数*/ // printf("ms=%.2f,fps=%.2f\r\n", __HAL_TIM_GetCounter(&htim7) / 100.f, // 1000.f / (__HAL_TIM_GetCounter(&htim7) / 100.f)); } } void vMBPortClose(void) { __HAL_UART_DISABLE(serial); } /*Send a byte*/ BOOL xMBPortSerialPutByte(CHAR ucByte) { stm32_putc(ucByte); return TRUE; } /*Get a byte from fifo*/ BOOL xMBPortSerialGetByte(CHAR *pucByte) { Get_from_fifo(&Slave_serial_rx_fifo, (uint8_t *)pucByte, 1); return TRUE; } void prvvUARTTxReadyISR(void) { pxMBFrameCBTransmitterEmpty(); } void prvvUARTRxISR(void) { pxMBFrameCBByteReceived(); } /** * Software simulation serial transmit IRQ handler. * * @param parameter parameter */ static void serial_soft_trans_irq(void *parameter) { uint32_t recved_event; while (1) { /* waiting for serial transmit start */ xEventGroupWaitBits(event_serial, /* 事件对象句柄 */ EVENT_SERIAL_TRANS_START, /* 接收任务感兴趣的事件 */ pdFALSE, /* 退出时清除事件?? */ pdFALSE, /* 满足感兴趣的所有事?? */ portMAX_DELAY); /* 指定超时事件,无限等待 */ /* execute modbus callback */ prvvUARTTxReadyISR(); } } /** * @brief Rx Transfer completed callbacks. * @param huart Pointer to a UART_HandleTypeDef structure that contains * the configuration information for the specified UART module. * @retval None */ void Slave_RxCpltCallback(UART_HandleTypeDef *huart) { int ch = -1; while (1) { ch = stm32_getc(); if (ch == -1) break; Put_in_fifo(&Slave_serial_rx_fifo, (uint8_t *)&ch, 1); } prvvUARTRxISR(); } /*UART发送一个字节*/ static int stm32_putc(CHAR c) { serial->Instance->DR = c; while (!(serial->Instance->SR & UART_FLAG_TC)) ; return TRUE; } /*UART接收一个字节*/ static int stm32_getc(void) { int ch; ch = -1; if (serial->Instance->SR & UART_FLAG_RXNE) { ch = serial->Instance->DR & 0xff; } return ch; } /*put bytes in buff*/ void Put_in_fifo(Serial_fifo *buff, uint8_t *putdata, int length) { portDISABLE_INTERRUPTS(); while (length--) { buff->buffer[buff->put_index] = *putdata; buff->put_index += 1; if (buff->put_index >= MB_SIZE_MAX) buff->put_index = 0; /* if the next position is read index, discard this 'read char' */ if (buff->put_index == buff->get_index) { buff->get_index += 1; if (buff->get_index >= MB_SIZE_MAX) buff->get_index = 0; } } portENABLE_INTERRUPTS(); } /*get bytes from buff*/ int Get_from_fifo(Serial_fifo *buff, uint8_t *getdata, int length) { int size = length; /* read from software FIFO */ while (length) { int ch; /* disable interrupt */ portDISABLE_INTERRUPTS(); if (buff->get_index != buff->put_index) { ch = buff->buffer[buff->get_index]; buff->get_index += 1; if (buff->get_index >= MB_SIZE_MAX) buff->get_index = 0; } else { /* no data, enable interrupt and break out */ portENABLE_INTERRUPTS(); break; } *getdata = ch & 0xff; getdata++; length--; /* enable interrupt */ portENABLE_INTERRUPTS(); } return size - length; } /** * @brief This function handles USART2 global interrupt. */ void USART2_IRQHandler(void) { /* USER CODE BEGIN USART2_IRQn 0 */ if (__HAL_UART_GET_FLAG(pMobusHuart, UART_FLAG_RXNE)) { huart2.RxCpltCallback(pMobusHuart); __HAL_UART_CLEAR_FLAG(pMobusHuart, UART_FLAG_RXNE); } if (__HAL_UART_GET_FLAG(pMobusHuart, UART_FLAG_ORE)) { uint16_t pucByte = (uint16_t)((pMobusHuart)->Instance->DR & (uint16_t)0x01FF); __HAL_UART_CLEAR_OREFLAG(pMobusHuart); } if (__HAL_UART_GET_FLAG(pMobusHuart, UART_FLAG_TC)) { __HAL_UART_CLEAR_FLAG(&huart2, UART_FLAG_TC); } /* USER CODE END USART2_IRQn 0 */ /* USER CODE BEGIN USART2_IRQn 1 */ /* USER CODE END USART2_IRQn 1 */ } #endif