You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
535 lines
16 KiB
535 lines
16 KiB
/*
|
|
* FreeModbus Libary: BARE Port
|
|
* Copyright (C) 2006 Christian Walter <wolti@sil.at>
|
|
*
|
|
* 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 <FreeRTOS.h>
|
|
#include <task.h>
|
|
#include <queue.h>
|
|
|
|
/* ----------------------- 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 |