MODBUS文件包含 callback、modbus、port。
#include "mb.h"
#include "includes.h"
/* ----------------------- Defines ------------------------------------------*/
#define REG_INPUT_START 1000
#define REG_INPUT_NREGS 4
/* ----------------------- Static variables ---------------------------------*/
static USHORT usRegInputStart = REG_INPUT_START;
static USHORT usRegInputBuf[REG_INPUT_NREGS];
/* ----------------------- Defines --自保持寄存器-------------------------------*/
#define REG_HOLDING_START ( 0x3000 ) //起始地址,16位字宽,对应VB区
#define REG_HOLDING_NREGS ( 20 )
/* ----------------------- Static variables ---自保持寄存器---------------------*/
static USHORT usRegHoldingBuf[REG_HOLDING_NREGS];
//*!
extern HOLD_REG_t Hold_Reg; //保持寄存器
eMBErrorCode
eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
{
eMBErrorCode eStatus = MB_ENOERR;
int iRegIndex;
if( ( usAddress >= REG_INPUT_START )
&& ( usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS ) )
{
iRegIndex = ( int )( usAddress - usRegInputStart );
while( usNRegs > 0 )
{
*pucRegBuffer++ = ( unsigned char )( usRegInputBuf[iRegIndex] >> 8 );
*pucRegBuffer++ = ( unsigned char )( usRegInputBuf[iRegIndex] & 0xFF );
iRegIndex++;
usNRegs--;
}
}
else
{
eStatus = MB_ENOREG;
}
return eStatus;
}
eMBErrorCode
eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode )
{
eMBErrorCode eStatus = MB_ENOERR;
int iRegIndex;
/* Number of reception */
u16 MultiWriteNum = usNRegs;
/* 是否更新数据 holdreg 或者 */
USHORT *StartAddr;
// if(eMode == MB_REG_READ)
// {
// UpdataHoldReg();
// StartAddr = (USHORT *)&Hold_Reg;
// }
//
// if(eMode == MB_REG_WRITE)
// {
// StartAddr = (USHORT *)&Hold_Reg;
// }
if( ( usAddress >= REG_HOLDING_START )
&& ( usAddress + usNRegs <= REG_HOLDING_START + REG_HOLDING_NREGS ) )
{
iRegIndex = ( int )( usAddress - REG_HOLDING_START );
while( usNRegs > 0 )
{
if(MB_REG_READ == eMode){
*pucRegBuffer++ = ( unsigned char )( usRegHoldingBuf[iRegIndex] >> 8 );
*pucRegBuffer++ = ( unsigned char )( usRegHoldingBuf[iRegIndex] & 0xFF );
// *pucRegBuffer++ = ( unsigned char )( StartAddr[iRegIndex] >> 8 );
// *pucRegBuffer++ = ( unsigned char )( StartAddr[iRegIndex] & 0xFF );
iRegIndex++;
usNRegs--;
}
else
{
usRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8;
usRegHoldingBuf[iRegIndex] |= *pucRegBuffer++;
// StartAddr[iRegIndex] = *pucRegBuffer++ << 8;
// StartAddr[iRegIndex] |= *pucRegBuffer++;
iRegIndex++;
usNRegs--;
}
}
/* if(MB_REG_WRITE == eMode)
eStatus = Set_num(usAddress);*/
if(MB_REG_WRITE == eMode)
{
}
// eStatus = Set_num(usAddress - 1,MultiWriteNum);
}
else
{
eStatus = MB_ENOREG;
}
return eStatus;
}
eMBErrorCode
eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode )
{
( void )pucRegBuffer;
( void )usAddress;
( void )usNCoils;
( void )eMode;
return MB_ENOREG;
}
eMBErrorCode
eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
{
( void )pucRegBuffer;
( void )usAddress;
( void )usNDiscrete;
return MB_ENOREG;
}
/* ----------------------- Platform includes --------------------------------*/
#include "port.h"
/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mbrtu.h"
#include "mbframe.h"
#include "mbport.h"
#include "mbcrc.h"
#include
/* !!! 满足RTU 多从机 2018/9/20 15:59:14 */
void xMBPortEventInit_new(MB_RTU_DCB *const pMBRTU)
{
pMBRTU->xEventInQueue = FALSE;
}
void xMBPortEventPost_new(MB_RTU_DCB *const pMBRTU,eMBEventType eEvent )
{
pMBRTU->xEventInQueue = TRUE;
pMBRTU->eQueuedEvent = eEvent;
}
BOOL xMBPortEventGet_new(MB_RTU_DCB *const pMBRTU,eMBEventType * eEvent)
{
if(pMBRTU->xEventInQueue){
*eEvent = pMBRTU->eQueuedEvent;
pMBRTU->xEventInQueue = FALSE;
return TRUE;
}
else
return FALSE;
}
void xMBRTUReceiveFSM(MB_RTU_DCB *const pMBRTU)
{
UCHAR ucByte;
/* Always read the character. */
pMBRTU->ucPort->pvMBPortSerialGetByte( ( UCHAR * ) & ucByte );
switch ( pMBRTU->eRcvState )
{
/* If we have received a character in the init state we have to
* wait until the frame is finished.
*/
case STATE_RX_INIT:
pMBRTU->ucPort->pvMBPortTimersEnable(T3_5);
break;
/* In the error state we wait until all characters in the
* damaged frame are transmitted.
*/
case STATE_RX_ERROR:
pMBRTU->ucPort->pvMBPortTimersEnable(T3_5);
break;
/* In the idle state we wait for a new character. If a character
* is received the t1.5 and t3.5 timers are started and the
* receiver is in the state STATE_RX_RECEIVCE.
*/
case STATE_RX_IDLE:
pMBRTU->ucBufferCount = 0;
pMBRTU->ucBuffer[pMBRTU->ucBufferCount++] = ucByte;
pMBRTU->eRcvState = STATE_RX_RCV;
/* Enable t3.5 timers. */
pMBRTU->ucPort->pvMBPortTimersEnable(T3_5);
break;
/* We are currently receiving a frame. Reset the timer after
* every character received. If more than the maximum possible
* number of bytes in a modbus frame is received the frame is
* ignored.
*/
case STATE_RX_RCV:
if( pMBRTU->ucBufferCount < MB_SER_PDU_SIZE_MAX )
{
pMBRTU->ucBuffer[pMBRTU->ucBufferCount++] = ucByte;
}
else
{
pMBRTU->eRcvState = STATE_RX_ERROR;
}
pMBRTU->ucPort->pvMBPortTimersEnable(T3_5);
break;
}
}
void xMBRTUTransmitFSM(MB_RTU_DCB *const pMBRTU)
{
switch ( pMBRTU->eSndState )
{
/* We should not get a transmitter event if the transmitter is in
* idle state. */
case STATE_TX_IDLE:
/* enable receiver/disable transmitter. */
pMBRTU->ucPort->pvMBPortSerialEnable( TRUE, FALSE );
break;
case STATE_TX_XMIT:
/* check if we are finished. */
if( pMBRTU->ucBufferCount != 0 )
{
pMBRTU->ucPort->pvMBPortSerialPutByte( ( CHAR )*pMBRTU->pucBuffer );
pMBRTU->pucBuffer++; /* next byte in sendbuffer. */
pMBRTU->ucBufferCount--;
}
else
{
xMBPortEventPost_new(pMBRTU,EV_FRAME_SENT );
/* Disable transmitter. This prevents another transmit buffer
* empty interrupt. */
pMBRTU->ucPort->pvMBPortSerialEnable( TRUE, FALSE );
pMBRTU->eSndState = STATE_TX_IDLE;
}
break;
}
}
eMBErrorCode
eMBRTUReceive(MB_RTU_DCB *const pMBRTU, UCHAR * pucRcvAddress, UCHAR ** pucFrame, USHORT * pusLength )
{
eMBErrorCode eStatus= MB_ENOERR;
pMBRTU->ucPort->pvMBEnterCriticalSection();
/* Length and CRC check */
if( ( pMBRTU->ucBufferCount >= MB_SER_PDU_SIZE_MIN )
&& ( usMBCRC16( ( UCHAR * )pMBRTU->ucBuffer, pMBRTU->ucBufferCount ) == 0 ) )
{
/* Save the address field. All frames are passed to the upper layed
* and the decision if a frame is used is done there.
*/
*pucRcvAddress = pMBRTU->ucBuffer[MB_SER_PDU_ADDR_OFF];
// /* Total length of Modbus-PDU is Modbus-Serial-Line-PDU minus
// * size of address field and CRC checksum.
// */
// *pusLength = ( USHORT )( pMBRTU->ucBufferCount - MB_SER_PDU_PDU_OFF - MB_SER_PDU_SIZE_CRC );
// /* Return the start of the Modbus PDU to the caller. */
// *pucFrame = ( UCHAR * ) & pMBRTU->ucBuffer[MB_SER_PDU_PDU_OFF];
}
else
{
eStatus = MB_EIO;
}
pMBRTU->ucPort->pvMBExitCriticalSection();
return eStatus;
}
eMBErrorCode
eMBRTUSend(MB_RTU_DCB *const pMBRTU,const UCHAR * pucFrame, USHORT usLength )
{
eMBErrorCode eStatus = MB_ENOERR;
USHORT usCRC16;
pMBRTU->ucPort->pvMBEnterCriticalSection();
/* Check if the receiver is still in idle state. If not we where to
* slow with processing the received frame and the master sent another
* frame on the network. We have to abort sending the frame.
*/
if( pMBRTU->eRcvState == STATE_RX_IDLE )
{
/* First byte before the Modbus-PDU is the slave address. */
pMBRTU->pucBuffer = ( UCHAR * ) pucFrame - 1;
pMBRTU->ucBufferCount = 1;
/* Now copy the Modbus-PDU into the Modbus-Serial-Line-PDU. */
pMBRTU->pucBuffer[MB_SER_PDU_ADDR_OFF] = pMBRTU->ucMBAddress;
pMBRTU->ucBufferCount += usLength;
/* Calculate CRC16 checksum for Modbus-Serial-Line-PDU. */
usCRC16 = usMBCRC16( ( UCHAR * ) pMBRTU->pucBuffer, pMBRTU->ucBufferCount );
pMBRTU->ucBuffer[pMBRTU->ucBufferCount++] = ( UCHAR )( usCRC16 & 0xFF );
pMBRTU->ucBuffer[pMBRTU->ucBufferCount++] = ( UCHAR )( usCRC16 >> 8 );
/* Activate the transmitter. */
pMBRTU->eSndState = STATE_TX_XMIT;
pMBRTU->ucPort->pvMBPortSerialEnable( FALSE, TRUE );
}
else
{
eStatus = MB_EIO;
}
pMBRTU->ucPort->pvMBExitCriticalSection();
return eStatus;
}
void eMBRTUInit(MB_RTU_DCB *const pMBRTU,const MB_RTU_PORT *pMBRTUPort)
{
pMBRTU->ucPort = pMBRTUPort;
pMBRTU->ucPort->pvMBEnterCriticalSection();
pMBRTU->ucPort->pvMBPortSerialInit();
pMBRTU->ucPort->pvMBPortTimersInit();
xMBPortEventInit_new(pMBRTU);
pMBRTU->ucPort->pvMBExitCriticalSection();
}
void eMBRTUPoll(MB_RTU_DCB *const pMBRTU)
{
int i;
USHORT usLength;
UCHAR *ucMBFrame;
UCHAR ucRcvAddress;
UCHAR ucFunctionCode;
eMBEventType eEvent;
eMBErrorCode eStatus = MB_ENOERR;
eMBException eException;
/* Check if there is a event available. If not return control to caller.
* Otherwise we will handle the event. */
if( xMBPortEventGet_new(pMBRTU,&eEvent) == TRUE )
{
switch (eEvent)
{
case EV_READY:
break;
case EV_FRAME_RECEIVED:
eStatus = eMBRTUReceive(pMBRTU, &ucRcvAddress, &ucMBFrame, &usLength );
if( eStatus == MB_ENOERR )
{
/* Check if the frame is for us. If not ignore the frame. */
if( ( ucRcvAddress == pMBRTU->ucMBAddress ) || ( ucRcvAddress == MB_ADDRESS_BROADCAST ) )
{
xMBPortEventPost_new( pMBRTU,EV_EXECUTE );
}
else
{/*接收到的不是自己的地址,接收使能,切换到EV_READY状态*/
xMBPortEventPost_new( pMBRTU,EV_READY );
pMBRTU->ucPort->pvMBPortSerialEnable( TRUE, FALSE );
}
}
else
{/*CRC检验错误或请求的数据长度超过MB_SER_PDU_SIZE_MIN*/
xMBPortEventPost_new( pMBRTU,EV_READY );
pMBRTU->ucPort->pvMBPortSerialEnable( TRUE, FALSE );
}
break;
case EV_EXECUTE:
eException = MB_EX_ILLEGAL_FUNCTION;
/*因为是局部变量,所以必须重新计算,否则变量值未知*/
ucRcvAddress = pMBRTU->ucBuffer[MB_SER_PDU_ADDR_OFF];
usLength = ( USHORT )( pMBRTU->ucBufferCount - MB_SER_PDU_PDU_OFF - MB_SER_PDU_SIZE_CRC );
ucMBFrame = ( UCHAR * ) & pMBRTU->ucBuffer[MB_SER_PDU_PDU_OFF];
ucFunctionCode = ucMBFrame[MB_PDU_FUNC_OFF];
for( i = 0; i < MB_FUNC_HANDLERS_MAX; i++ )
{
/* No more function handlers registered. Abort. */
if( xFuncHandlers[i].ucFunctionCode == 0 )
{
break;
}
else if( xFuncHandlers[i].ucFunctionCode == ucFunctionCode )
{
eException = xFuncHandlers[i].pxHandler( ucMBFrame, &usLength );
break;
}
}
/* If the request was not sent to the broadcast address we
* return a reply. */
if( ucRcvAddress != MB_ADDRESS_BROADCAST )
{
if( eException != MB_EX_NONE )
{
/* An exception occured. Build an error frame. */
usLength = 0;
ucMBFrame[usLength++] = ( UCHAR )( ucFunctionCode | MB_FUNC_ERROR );
ucMBFrame[usLength++] = eException;
}
eStatus = eMBRTUSend( pMBRTU,ucMBFrame, usLength );
}
break;
case EV_FRAME_SENT:
break;
}
}
}
void xMBRTUTimerT35Expired(MB_RTU_DCB *const pMBRTU)
{
switch ( pMBRTU->eRcvState )
{
/* Timer t35 expired. Startup phase is finished. */
case STATE_RX_INIT:
xMBPortEventPost_new(pMBRTU,EV_READY);
break;
/* A frame was received and t35 expired. Notify the listener that
* a new frame was received. */
case STATE_RX_RCV:
xMBPortEventPost_new(pMBRTU,EV_FRAME_RECEIVED);
// pMBRTU->ucPort->pvMBPortSerialEnable( FALSE, FALSE );
break;
/* An error occured while receiving the frame. */
case STATE_RX_ERROR:
break;
/* Function called in an illegal state. */
default:
break;
}
pMBRTU->ucPort->pvMBPortTimersDisable( );
pMBRTU->eRcvState = STATE_RX_IDLE;
}
void eMBRTUStart( MB_RTU_DCB *const pMBRTU )
{
pMBRTU->ucPort->pvMBEnterCriticalSection();
pMBRTU->eRcvState = STATE_RX_INIT;
pMBRTU->ucPort->pvMBPortSerialEnable(TRUE,FALSE);
pMBRTU->ucPort->pvMBPortTimersEnable(T3_5);
pMBRTU->ucPort->pvMBExitCriticalSection();
}
#ifndef __MBRTU__H
#define __MBRTU__H
#include "mbconfig.h"
//#include "mbdatatype.h"
#define BaudRate 9600
#define T3_5 ( ( 7UL * 220000UL ) / ( 2UL * BaudRate ) )//(35)
/*11*3.5*10^6/50/9600*/
// 1个起始位(低电平),8个数据位,1个校验位,1个停止位(高电平,表示数据帧结束)
/* ----------------------- Type definitions ---------------------------------*/
/* ----------------------- Defines ------------------------------------------*/
#define MB_SER_PDU_SIZE_MIN 4 /*!< Minimum size of a Modbus RTU frame. */
#define MB_SER_PDU_SIZE_MAX 256 /*!< Maximum size of a Modbus RTU frame. */
#define MB_SER_PDU_SIZE_CRC 2 /*!< Size of CRC field in PDU. */
#define MB_SER_PDU_ADDR_OFF 0 /*!< Offset of slave address in Ser-PDU. */
#define MB_SER_PDU_PDU_OFF 1 /*!< Offset of Modbus-PDU in Ser-PDU. */
// *! 添加 多个从机 2018/9/20 15:38:34
typedef enum
{
STATE_RX_INIT, /*!< Receiver is in initial state. */
STATE_RX_IDLE, /*!< Receiver is in idle state. */
STATE_RX_RCV, /*!< Frame is beeing received. */
STATE_RX_ERROR /*!< If the frame is invalid. */
} eMBRcvState;
typedef enum
{
STATE_TX_IDLE, /*!< Transmitter is in idle state. */
STATE_TX_XMIT /*!< Transmitter is in transfer state. */
} eMBSndState;
typedef struct {
void (*pvMBPortSerialInit)(void);
void (*pvMBPortTimersInit)(void);
void (*pvMBPortSerialGetByte)(UCHAR *pucByte);
void (*pvMBPortSerialPutByte)(UCHAR ucByte);
void (*pvMBPortTimersEnable)(USHORT Timerout50us);
void (*pvMBPortTimersDisable)(void);
void (*pvMBPortSerialEnable)(BOOL xRxEnable,BOOL xTxEnable);
void (*pvMBEnterCriticalSection)(void);
void (*pvMBExitCriticalSection)(void);
}MB_RTU_PORT;
typedef struct _MB_RTU_DCB{
UCHAR ucMBAddress;
eMBRcvState eRcvState;
eMBSndState eSndState;
eMBEventType eQueuedEvent;
BOOL xEventInQueue;
USHORT ucBufferCount;
volatile UCHAR ucBuffer[MB_SER_PDU_SIZE_MAX];
volatile UCHAR *pucBuffer;
const MB_RTU_PORT *ucPort;
}MB_RTU_DCB;
void eMBRTUPoll(MB_RTU_DCB *const pMBRTU);
void eMBRTUInit(MB_RTU_DCB *const pMBRTU,const MB_RTU_PORT *port);
void xMBRTUTimerT35Expired(MB_RTU_DCB *const pMBRTU);
void eMBRTUStart( MB_RTU_DCB *const pMBRTU );
eMBErrorCode
eMBRTUSend(MB_RTU_DCB *const pMBRTU,const UCHAR * pucFrame, USHORT usLength );
eMBErrorCode
eMBRTUReceive(MB_RTU_DCB *const pMBRTU, UCHAR * pucRcvAddress, UCHAR ** pucFrame, USHORT * pusLength );
void xMBRTUReceiveFSM(MB_RTU_DCB *const pMBRTU);
void xMBRTUTransmitFSM(MB_RTU_DCB *const pMBRTU);
#endif
/*
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
* Copyright (c) 2006 Christian Walter
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* File: $Id: mb.h,v 1.17 2006/12/07 22:10:34 wolti Exp $
*/
#ifndef _MB_H
#define _MB_H
#include "port.h"
#ifdef __cplusplus
PR_BEGIN_EXTERN_C
#endif
#include "mbport.h"
#include "mbproto.h"
/*! \defgroup modbus Modbus
* \code #include "mb.h" \endcode
*
* This module defines the interface for the application. It contains
* the basic functions and types required to use the Modbus protocol stack.
* A typical application will want to call eMBInit() first. If the device
* is ready to answer network requests it must then call eMBEnable() to activate
* the protocol stack. In the main loop the function eMBPoll() must be called
* periodically. The time interval between pooling depends on the configured
* Modbus timeout. If an RTOS is available a separate task should be created
* and the task should always call the function eMBPoll().
*
* \code
* // Initialize protocol stack in RTU mode for a slave with address 10 = 0x0A
* eMBInit( MB_RTU, 0x0A, 38400, MB_PAR_EVEN );
* // Enable the Modbus Protocol Stack.
* eMBEnable( );
* for( ;; )
* {
* // Call the main polling loop of the Modbus protocol stack.
* eMBPoll( );
* ...
* }
* \endcode
*/
/* ----------------------- Defines ------------------------------------------*/
/*! \ingroup modbus
* \brief Use the default Modbus TCP port (502)
*/
#define MB_TCP_PORT_USE_DEFAULT 0
/* ----------------------- Type definitions ---------------------------------*/
/*! \ingroup modbus
* \brief Modbus serial transmission modes (RTU/ASCII).
*
* Modbus serial supports two transmission modes. Either ASCII or RTU. RTU
* is faster but has more hardware requirements and requires a network with
* a low jitter. ASCII is slower and more reliable on slower links (E.g. modems)
*/
typedef enum
{
MB_RTU, /*!< RTU transmission mode. */
MB_ASCII, /*!< ASCII transmission mode. */
MB_TCP /*!< TCP mode. */
} eMBMode;
/*! \ingroup modbus
* \brief If register should be written or read.
*
* This value is passed to the callback functions which support either
* reading or writing register values. Writing means that the application
* registers should be updated and reading means that the modbus protocol
* stack needs to know the current register values.
*
* \see eMBRegHoldingCB( ), eMBRegCoilsCB( ), eMBRegDiscreteCB( ) and
* eMBRegInputCB( ).
*/
typedef enum
{
MB_REG_READ, /*!< Read register values and pass to protocol stack. */
MB_REG_WRITE /*!< Update register values. */
} eMBRegisterMode;
/*! \ingroup modbus
* \brief Errorcodes used by all function in the protocol stack.
*/
typedef enum
{
MB_ENOERR, /*!< no error. */
MB_ENOREG, /*!< illegal register address. */
MB_EINVAL, /*!< illegal argument. */
MB_EPORTERR, /*!< porting layer error. */
MB_ENORES, /*!< insufficient resources. */
MB_EIO, /*!< I/O error. */
MB_EILLSTATE, /*!< protocol stack in illegal state. */
MB_ETIMEDOUT /*!< timeout error occurred. */
} eMBErrorCode;
/* !!! 满足RTU 多从机 2018/9/20 15:59:14 */
extern xMBFunctionHandler xFuncHandlers[];
/* ----------------------- Function prototypes ------------------------------*/
/*! \ingroup modbus
* \brief Initialize the Modbus protocol stack.
*
* This functions initializes the ASCII or RTU module and calls the
* init functions of the porting layer to prepare the hardware. Please
* note that the receiver is still disabled and no Modbus frames are
* processed until eMBEnable( ) has been called.
*
* \param eMode If ASCII or RTU mode should be used.
* \param ucSlaveAddress The slave address. Only frames sent to this
* address or to the broadcast address are processed.
* \param ucPort The port to use. E.g. 1 for COM1 on windows. This value
* is platform dependent and some ports simply choose to ignore it.
* \param ulBaudRate The baudrate. E.g. 19200. Supported baudrates depend
* on the porting layer.
* \param eParity Parity used for serial transmission.
*
* \return If no error occurs the function returns eMBErrorCode::MB_ENOERR.
* The protocol is then in the disabled state and ready for activation
* by calling eMBEnable( ). Otherwise one of the following error codes
* is returned:
* - eMBErrorCode::MB_EINVAL If the slave address was not valid. Valid
* slave addresses are in the range 1 - 247.
* - eMBErrorCode::MB_EPORTERR IF the porting layer returned an error.
*/
eMBErrorCode eMBInit( eMBMode eMode, UCHAR ucSlaveAddress,
UCHAR ucPort, ULONG ulBaudRate, eMBParity eParity );
/*! \ingroup modbus
* \brief Initialize the Modbus protocol stack for Modbus TCP.
*
* This function initializes the Modbus TCP Module. Please note that
* frame processing is still disabled until eMBEnable( ) is called.
*
* \param usTCPPort The TCP port to listen on.
* \return If the protocol stack has been initialized correctly the function
* returns eMBErrorCode::MB_ENOERR. Otherwise one of the following error
* codes is returned:
* - eMBErrorCode::MB_EINVAL If the slave address was not valid. Valid
* slave addresses are in the range 1 - 247.
* - eMBErrorCode::MB_EPORTERR IF the porting layer returned an error.
*/
eMBErrorCode eMBTCPInit( USHORT usTCPPort );
/*! \ingroup modbus
* \brief Release resources used by the protocol stack.
*
* This function disables the Modbus protocol stack and release all
* hardware resources. It must only be called when the protocol stack
* is disabled.
*
* \note Note all ports implement this function. A port which wants to
* get an callback must define the macro MB_PORT_HAS_CLOSE to 1.
*
* \return If the resources where released it return eMBErrorCode::MB_ENOERR.
* If the protocol stack is not in the disabled state it returns
* eMBErrorCode::MB_EILLSTATE.
*/
eMBErrorCode eMBClose( void );
/*! \ingroup modbus
* \brief Enable the Modbus protocol stack.
*
* This function enables processing of Modbus frames. Enabling the protocol
* stack is only possible if it is in the disabled state.
*
* \return If the protocol stack is now in the state enabled it returns
* eMBErrorCode::MB_ENOERR. If it was not in the disabled state it
* return eMBErrorCode::MB_EILLSTATE.
*/
eMBErrorCode eMBEnable( void );
/*! \ingroup modbus
* \brief Disable the Modbus protocol stack.
*
* This function disables processing of Modbus frames.
*
* \return If the protocol stack has been disabled it returns
* eMBErrorCode::MB_ENOERR. If it was not in the enabled state it returns
* eMBErrorCode::MB_EILLSTATE.
*/
eMBErrorCode eMBDisable( void );
/*! \ingroup modbus
* \brief The main pooling loop of the Modbus protocol stack.
*
* This function must be called periodically. The timer interval required
* is given by the application dependent Modbus slave timeout. Internally the
* function calls xMBPortEventGet() and waits for an event from the receiver or
* transmitter state machines.
*
* \return If the protocol stack is not in the enabled state the function
* returns eMBErrorCode::MB_EILLSTATE. Otherwise it returns
* eMBErrorCode::MB_ENOERR.
*/
eMBErrorCode eMBPoll( void );
/*! \ingroup modbus
* \brief Configure the slave id of the device.
*
* This function should be called when the Modbus function Report Slave ID
* is enabled ( By defining MB_FUNC_OTHER_REP_SLAVEID_ENABLED in mbconfig.h ).
*
* \param ucSlaveID Values is returned in the Slave ID byte of the
* Report Slave ID response.
* \param xIsRunning If TRUE the Run Indicator Status byte is set to 0xFF.
* otherwise the Run Indicator Status is 0x00.
* \param pucAdditional Values which should be returned in the Additional
* bytes of the Report Slave ID response.
* \param usAdditionalLen Length of the buffer pucAdditonal
.
*
* \return If the static buffer defined by MB_FUNC_OTHER_REP_SLAVEID_BUF in
* mbconfig.h is to small it returns eMBErrorCode::MB_ENORES. Otherwise
* it returns eMBErrorCode::MB_ENOERR.
*/
eMBErrorCode eMBSetSlaveID( UCHAR ucSlaveID, BOOL xIsRunning,
UCHAR const *pucAdditional,
USHORT usAdditionalLen );
/*! \ingroup modbus
* \brief Registers a callback handler for a given function code.
*
* This function registers a new callback handler for a given function code.
* The callback handler supplied is responsible for interpreting the Modbus PDU and
* the creation of an appropriate response. In case of an error it should return
* one of the possible Modbus exceptions which results in a Modbus exception frame
* sent by the protocol stack.
*
* \param ucFunctionCode The Modbus function code for which this handler should
* be registers. Valid function codes are in the range 1 to 127.
* \param pxHandler The function handler which should be called in case
* such a frame is received. If \c NULL a previously registered function handler
* for this function code is removed.
*
* \return eMBErrorCode::MB_ENOERR if the handler has been installed. If no
* more resources are available it returns eMBErrorCode::MB_ENORES. In this
* case the values in mbconfig.h should be adjusted. If the argument was not
* valid it returns eMBErrorCode::MB_EINVAL.
*/
eMBErrorCode eMBRegisterCB( UCHAR ucFunctionCode,
pxMBFunctionHandler pxHandler );
/* ----------------------- Callback -----------------------------------------*/
/*! \defgroup modbus_registers Modbus Registers
* \code #include "mb.h" \endcode
* The protocol stack does not internally allocate any memory for the
* registers. This makes the protocol stack very small and also usable on
* low end targets. In addition the values don't have to be in the memory
* and could for example be stored in a flash.
* Whenever the protocol stack requires a value it calls one of the callback
* function with the register address and the number of registers to read
* as an argument. The application should then read the actual register values
* (for example the ADC voltage) and should store the result in the supplied
* buffer.
* If the protocol stack wants to update a register value because a write
* register function was received a buffer with the new register values is
* passed to the callback function. The function should then use these values
* to update the application register values.
*/
/*! \ingroup modbus_registers
* \brief Callback function used if the value of a Input Register
* is required by the protocol stack. The starting register address is given
* by \c usAddress and the last register is given by usAddress +
* usNRegs - 1.
*
* \param pucRegBuffer A buffer where the callback function should write
* the current value of the modbus registers to.
* \param usAddress The starting address of the register. Input registers
* are in the range 1 - 65535.
* \param usNRegs Number of registers the callback function must supply.
*
* \return The function must return one of the following error codes:
* - eMBErrorCode::MB_ENOERR If no error occurred. In this case a normal
* Modbus response is sent.
* - eMBErrorCode::MB_ENOREG If the application can not supply values
* for registers within this range. In this case a
* ILLEGAL DATA ADDRESS exception frame is sent as a response.
* - eMBErrorCode::MB_ETIMEDOUT If the requested register block is
* currently not available and the application dependent response
* timeout would be violated. In this case a SLAVE DEVICE BUSY
* exception is sent as a response.
* - eMBErrorCode::MB_EIO If an unrecoverable error occurred. In this case
* a SLAVE DEVICE FAILURE exception is sent as a response.
*/
eMBErrorCode eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress,
USHORT usNRegs );
/*! \ingroup modbus_registers
* \brief Callback function used if a Holding Register value is
* read or written by the protocol stack. The starting register address
* is given by \c usAddress and the last register is given by
* usAddress + usNRegs - 1.
*
* \param pucRegBuffer If the application registers values should be updated the
* buffer points to the new registers values. If the protocol stack needs
* to now the current values the callback function should write them into
* this buffer.
* \param usAddress The starting address of the register.
* \param usNRegs Number of registers to read or write.
* \param eMode If eMBRegisterMode::MB_REG_WRITE the application register
* values should be updated from the values in the buffer. For example
* this would be the case when the Modbus master has issued an
* WRITE SINGLE REGISTER command.
* If the value eMBRegisterMode::MB_REG_READ the application should copy
* the current values into the buffer \c pucRegBuffer.
*
* \return The function must return one of the following error codes:
* - eMBErrorCode::MB_ENOERR If no error occurred. In this case a normal
* Modbus response is sent.
* - eMBErrorCode::MB_ENOREG If the application can not supply values
* for registers within this range. In this case a
* ILLEGAL DATA ADDRESS exception frame is sent as a response.
* - eMBErrorCode::MB_ETIMEDOUT If the requested register block is
* currently not available and the application dependent response
* timeout would be violated. In this case a SLAVE DEVICE BUSY
* exception is sent as a response.
* - eMBErrorCode::MB_EIO If an unrecoverable error occurred. In this case
* a SLAVE DEVICE FAILURE exception is sent as a response.
*/
eMBErrorCode eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress,
USHORT usNRegs, eMBRegisterMode eMode );
/*! \ingroup modbus_registers
* \brief Callback function used if a Coil Register value is
* read or written by the protocol stack. If you are going to use
* this function you might use the functions xMBUtilSetBits( ) and
* xMBUtilGetBits( ) for working with bitfields.
*
* \param pucRegBuffer The bits are packed in bytes where the first coil
* starting at address \c usAddress is stored in the LSB of the
* first byte in the buffer pucRegBuffer
.
* If the buffer should be written by the callback function unused
* coil values (I.e. if not a multiple of eight coils is used) should be set
* to zero.
* \param usAddress The first coil number.
* \param usNCoils Number of coil values requested.
* \param eMode If eMBRegisterMode::MB_REG_WRITE the application values should
* be updated from the values supplied in the buffer \c pucRegBuffer.
* If eMBRegisterMode::MB_REG_READ the application should store the current
* values in the buffer \c pucRegBuffer.
*
* \return The function must return one of the following error codes:
* - eMBErrorCode::MB_ENOERR If no error occurred. In this case a normal
* Modbus response is sent.
* - eMBErrorCode::MB_ENOREG If the application does not map an coils
* within the requested address range. In this case a
* ILLEGAL DATA ADDRESS is sent as a response.
* - eMBErrorCode::MB_ETIMEDOUT If the requested register block is
* currently not available and the application dependent response
* timeout would be violated. In this case a SLAVE DEVICE BUSY
* exception is sent as a response.
* - eMBErrorCode::MB_EIO If an unrecoverable error occurred. In this case
* a SLAVE DEVICE FAILURE exception is sent as a response.
*/
eMBErrorCode eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress,
USHORT usNCoils, eMBRegisterMode eMode );
/*! \ingroup modbus_registers
* \brief Callback function used if a Input Discrete Register value is
* read by the protocol stack.
*
* If you are going to use his function you might use the functions
* xMBUtilSetBits( ) and xMBUtilGetBits( ) for working with bitfields.
*
* \param pucRegBuffer The buffer should be updated with the current
* coil values. The first discrete input starting at \c usAddress must be
* stored at the LSB of the first byte in the buffer. If the requested number
* is not a multiple of eight the remaining bits should be set to zero.
* \param usAddress The starting address of the first discrete input.
* \param usNDiscrete Number of discrete input values.
* \return The function must return one of the following error codes:
* - eMBErrorCode::MB_ENOERR If no error occurred. In this case a normal
* Modbus response is sent.
* - eMBErrorCode::MB_ENOREG If no such discrete inputs exists.
* In this case a ILLEGAL DATA ADDRESS exception frame is sent
* as a response.
* - eMBErrorCode::MB_ETIMEDOUT If the requested register block is
* currently not available and the application dependent response
* timeout would be violated. In this case a SLAVE DEVICE BUSY
* exception is sent as a response.
* - eMBErrorCode::MB_EIO If an unrecoverable error occurred. In this case
* a SLAVE DEVICE FAILURE exception is sent as a response.
*/
eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress,
USHORT usNDiscrete );
#ifdef __cplusplus
PR_END_EXTERN_C
#endif
#endif
/*
* 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: port.h,v 1.1 2006/08/22 21:35:13 wolti Exp $
*/
#ifndef _PORT_H
#define _PORT_H
#include
#include
/* ----------------------- stm32 ------------------------------------------*/
#include "stm32f10x.h"
/* ----------------------- modbus ------------------------------------------*/
#define INLINE inline
#define PR_BEGIN_EXTERN_C extern "C" {
#define PR_END_EXTERN_C }
#define ENTER_CRITICAL_SECTION( )
#define EXIT_CRITICAL_SECTION( )
typedef uint8_t BOOL;
typedef unsigned char UCHAR;
typedef char CHAR;
typedef uint16_t USHORT;
typedef int16_t SHORT;
typedef uint32_t ULONG;
typedef int32_t LONG;
#define TRUE 1
#define FALSE 0
//#ifndef TRUE
//#define TRUE 1
//#endif
//#ifndef FALSE
//#define FALSE 0
//#endif
#endif
/*
* 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: portevent.c,v 1.1 2006/08/22 21:35:13 wolti Exp $
*/
/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mbport.h"
/* ----------------------- Variables ----------------------------------------*/
static eMBEventType eQueuedEvent;
static BOOL xEventInQueue;
/* ----------------------- Start implementation -----------------------------*/
BOOL
xMBPortEventInit( void )
{
xEventInQueue = FALSE;
return TRUE;
}
BOOL
xMBPortEventPost( eMBEventType eEvent )
{
xEventInQueue = TRUE;
eQueuedEvent = eEvent;
return TRUE;
}
BOOL
xMBPortEventGet( eMBEventType * eEvent )
{
BOOL xEventHappened = FALSE;
if( xEventInQueue )
{
*eEvent = eQueuedEvent;
xEventInQueue = FALSE;
xEventHappened = TRUE;
}
return xEventHappened;
}
当需要添加串口时,自行添加。
#include
#define ucSerialPortNr USART2
#define ucSerialPortNr_PORT GPIOD
#define MBAddress 8
static void MBPortSerialInit(void);
static void MBPortTimersInit(void);
static void MBPortSerialGetByte(UCHAR *pucByte);
static void MBPortSerialPutByte(UCHAR ucByte);
static void MBPortTimersEnable(USHORT Timerout50us);
static void MBPortTimersDisable(void);
static void MBPortSerialEnable(BOOL xRxEnable,BOOL xTxEnable);
static void EnterCriticalSection(void);
static void ExitCriticalSection(void);
MB_RTU_DCB mbrtu2;
#define ucRTU_DCB (mbrtu2)
const MB_RTU_PORT mbrtuport2 = {
MBPortSerialInit,
MBPortTimersInit,
MBPortSerialGetByte,
MBPortSerialPutByte,
MBPortTimersEnable,
MBPortTimersDisable,
MBPortSerialEnable,
EnterCriticalSection,
ExitCriticalSection,
};
#if UART2_FIFO_EN == 0
void USART2_IRQHandler(void)
{
//接收中断
if (USART_GetITStatus(ucSerialPortNr, USART_IT_RXNE) == SET){
USART_ClearITPendingBit(ucSerialPortNr, USART_IT_RXNE);
xMBRTUReceiveFSM(&ucRTU_DCB);
}
//发送中断
if (USART_GetITStatus(ucSerialPortNr, USART_IT_TC) == SET){
xMBRTUTransmitFSM(&ucRTU_DCB);
}
}
#endif
static void Usart2_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
if(ucSerialPortNr_PORT == GPIOA)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
//----------------------------------------------------------
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //tx
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
else
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD | RCC_APB2Periph_AFIO, ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_USART2, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOD, &GPIO_InitStructure);
}
//------------RS485_en_Pin----------------
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//----------------------------------------------------------
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART2, &USART_InitStructure);
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
USART_ITConfig(USART2, USART_IT_TXE, DISABLE);
//Enable USART4 Receive interrupts
USART_Cmd(USART2, ENABLE);
USART2_DIR_IN;
}
static void MBPortSerialInit(void)
{
ucRTU_DCB.ucMBAddress = MBAddress;
USART_ClearITPendingBit(ucSerialPortNr, USART_IT_TC);
Usart2_Init();
// USART_ClearITPendingBit(ucSerialPortNr, USART_IT_TC);
}
static void MBPortTimersInit(void)
{
TIM_ITConfig(TIM2, TIM_IT_CC2, DISABLE);
// TIM_ClearITPendingBit(TIM2,TIM_IT_CC2);
}
static void MBPortSerialGetByte(UCHAR *pucByte)
{
*pucByte = USART_ReceiveData(ucSerialPortNr);
}
static void MBPortSerialPutByte(UCHAR ucByte)
{
USART_SendData(ucSerialPortNr, ucByte);
}
/* If baudrate > 19200 then we should use the fixed timer values
* t35 = 1750us. Otherwise t35 must be 3.5 times the character time. */
static void MBPortTimersEnable(USHORT Timerout50us)
{
USHORT cnt;
// TIM_Cmd(TIM2, DISABLE);
cnt = TIM_GetCounter(TIM2);
cnt += Timerout50us;
TIM_SetCompare2(TIM2,cnt); // 注意 TIM_SetCompare2 ===> TIM_IT_CC2
TIM_ClearITPendingBit(TIM2, TIM_IT_CC2);
TIM_ITConfig(TIM2, TIM_IT_CC2,ENABLE);
// TIM_Cmd(TIM2, ENABLE);
}
static void MBPortTimersDisable(void)
{
TIM_ITConfig(TIM2, TIM_IT_CC2,DISABLE);
}
static void MBPortSerialEnable(BOOL xRxEnable,BOOL xTxEnable)
{
if (xRxEnable){
USART2_DIR_IN;//*! 2018/9/25 10:39:59 添加端口控制 LongFei
USART_ClearITPendingBit(ucSerialPortNr, USART_IT_RXNE);
USART_ITConfig(ucSerialPortNr, USART_IT_RXNE, ENABLE);
}
else{
USART2_DIR_OUT;//*! 2018/9/25 10:39:59 添加端口控制 LongFei
USART_ITConfig(ucSerialPortNr, USART_IT_RXNE, DISABLE);
}
if (xTxEnable){
// USART_ClearITPendingBit(ucSerialPortNr, USART_IT_TC);
USART_ITConfig(ucSerialPortNr, USART_IT_TC, ENABLE);
}
else{
USART_ITConfig(ucSerialPortNr, USART_IT_TC, DISABLE);
}
}
static void EnterCriticalSection(void)
{
// __disable_irq();
}
static void ExitCriticalSection(void)
{
// __enable_irq();
}
利用定时器通道的输出比较模式,共用一个定时器,一个定时有4个通道,TIM定时周期50us。
/*
* 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: porttimer.c,v 1.1 2006/08/22 21:35:13 wolti Exp $
*/
/* ----------------------- Platform includes --------------------------------*/
#include "port.h"
/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mbport.h"
/* ----------------------- User includes ----------------------------------*/
#include
/* ----------------------- static functions ---------------------------------*/
static void prvvTIMERExpiredISR( void );
USHORT usTimerout50us;//*! 2018/9/20 11:18:05 T3.5的时间
/* ----------------------- Start implementation -----------------------------*/
BOOL
xMBPortTimersInit( USHORT usTim1Timerout50us )
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
usTimerout50us = usTim1Timerout50us;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_DeInit(TIM2);
TIM_TimeBaseStructure.TIM_Period = 65535;
TIM_TimeBaseStructure.TIM_Prescaler = 3600 - 1;
TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
//使能 TIMx 在 ARR 上的预装载寄存器
TIM_ARRPreloadConfig(TIM2, ENABLE);
/* Channel 1, 2,3 and 4 Configuration in PWM mode */
// TIM 输出比较时间模式
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Timing;
TIM_OC1Init(TIM2, &TIM_OCInitStructure);
TIM_OC2Init(TIM2, &TIM_OCInitStructure);
TIM_OC3Init(TIM2, &TIM_OCInitStructure);
TIM_OC4Init(TIM2, &TIM_OCInitStructure);
// TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); //允许更新中断
TIM_Cmd(TIM2, ENABLE);
return TRUE;
}
u16 ModbusExternalSignalTimeOut;//modbus 超时时间
void TIM2_IRQHandler(void)//50us
{
/*! 2018/9/29 10:37:40 longfei */
// TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); //允许更新中断
if(TIM_GetITStatus(TIM2,TIM_IT_Update) != RESET)// 3.2768 s
{
TIM_ClearFlag(TIM2, TIM_IT_Update); //清除TIM2待处理标志位
}
if(TIM_GetITStatus(TIM2,TIM_IT_CC1) != RESET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_CC1); //清除TIM2的中断待处理位
TIM_ClearFlag(TIM2, TIM_FLAG_CC1); //清除TIM2待处理标志位
}else if(TIM_GetITStatus(TIM2,TIM_IT_CC2) != RESET)
{
// /*! 2018/9/29 10:37:40 longfei: clean timeout */
// ModbusExternalSignalTimeOut = 0;
xMBRTUTimerT35Expired(&mbrtu2);//*! 2018/9/25 10:42:48 usart2 --> modbus2时间处理
TIM_ClearITPendingBit(TIM2, TIM_IT_CC2); //清除TIM2的中断待处理位
TIM_ClearFlag(TIM2, TIM_FLAG_Update); //清除TIM2待处理标志位
}else if(TIM_GetITStatus(TIM2,TIM_FLAG_CC3) != RESET)
{
// /*! 2018/9/29 10:37:40 longfei: clean timeout */
// LastExternalSignal = 0;
// ModbusExternalSignalTimeOut = 0;
// prvvTIMERExpiredISR();
xMBRTUTimerT35Expired(&mbrtu3);
TIM_ClearITPendingBit(TIM2, TIM_IT_CC3); //清除TIM2的中断待处理位
TIM_ClearFlag(TIM2, TIM_FLAG_CC3); //清除TIM2待处理标志位
}else if(TIM_GetITStatus(TIM2,TIM_IT_CC4) != RESET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_CC4); //清除TIM2的中断待处理位
TIM_ClearFlag(TIM2, TIM_FLAG_CC4); //清除TIM2待处理标志位
}
}
主函数调用:
xMBPortTimersInit(0);//*! modbus定时器初始化
/* usart2 串口号*/
eMBRTUInit(&mbrtu2,&mbrtuport2);
eMBRTUStart(&mbrtu2);
任务函数调用:
eMBRTUPoll(&mbrtu2);