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;
/* ----------------------- Static variables ---------------------------------*/ static volatile eMBSndState eSndState; static volatile eMBRcvState eRcvState;
volatile UCHAR ucRTUBuf[MB_SER_PDU_SIZE_MAX];
static volatile UCHAR *pucSndBufferCur; static volatile USHORT usSndBufferCount;
static volatile USHORT usRcvBufferPos;
首先在宏定义中,指明了该模式下所支持的最小请求帧长度为4(1字节地址+1字节命令+2字节校验),最大请求帧长度为256,CRC为两字节,地址为第一字节,PDU开始于第二字节。
在全局变量中,只定义了一个串口缓存数组ucRTUBuf[MB_SER_PDU_SIZE_MAX]。由于发送与接收不是同步的,故可采用该缓存数组实现Modbus协议。在接收过程中,将所接收到的数据直接存放于缓存ucRTUBuf中,在发送过程中,通过指针*pucSndBufferCur来访问该数组。
? eMBErrorCode eMBRTUInit( UCHAR ucSlaveAddress, UCHAR ucPort, ULONG
ulBaudRate, eMBParity eParity ) 此函数为RTU模式的初始化函数。此函数中判断串行口初始化是否成功(通过判断串行口初始化函数的返回值实现。当然,查看返回值必然先调用该函数,从而完成端口初始化),如果成功,则根据波特率计算T35,初始化超时定时器。 ? void eMBRTUStart( void )
此函数为RTU模式开始函数。函数主要功能是,将接收状态eRcvState设为STATE_RX_INIT(Receiver is in initial state),使能接收同时关闭发送,使能超时定时器。 ? void eMBRTUStop( void )
此函数为RTU模式终止函数。函数主要功能是,关闭接收与发送,关闭超时定时器。 ? eMBErrorCode eMBRTUReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame,
USHORT * pusLength ) 此函数为RTU接收数据帧信息提取函数。函数主要功能是,将接收帧(存放于缓存)的地址指针赋给指针变量pucRcvAddress,将PDU编码首地址赋给指针* pucFrame,将PDU长度地址赋给指针变量pusLength。使用指针访问缓存数组,而不是额外开辟缓存存放帧信息,大大减少了内存的开支。
? eMBErrorCode eMBRTUSend( UCHAR ucSlaveAddress, const UCHAR * pucFrame,
USHORT usLength )
此函数为RTU回复帧信息组织函数。函数的功能是,此函数首先使发送内容指针
6
pucSndBufferCur指向pucFrame之前的一个地址,并将该地址内容填充为ucSlaveAddress,并使用直接访问方式向缓存数组ucRTUBuf的相应地址内存入CRC校验值。注意,此函数中,对ucRTUBuf的访问既有间接方式(指针pucSndBufferCur与pucFrame),又有直接方式(直接向相应地址内写值),比较难理解。 回复帧组织完后,将发送状态eSndState设为STATE_TX_XMIT(Transmitter is in transfer state),并禁止接收使能发送。发送一旦使能,就会进入发送中断,完成相应字符的发送。 ? BOOL xMBRTUReceiveFSM( void )
此函数描述了一个接收状态机,供接收中断调用。状态机中,首先完成串口接收寄存器读取,然后判断相应接收状态eRcvState,实现接收。在STATE_RX_INIT状态,重置超时定时器,等待超时中断(超时中断会把eRcvState设为STATE_RX_IDLE);在STATE_RX_ERROR状态,同样会重置超时定时器等待超时中断;在STATE_RX_IDLE状态,会将接收字符个数置零,同时向缓存数组ucRTUBuf中存入接收到的字符,跳入状态STATE_RX_RCV,并使重置超时定时器;在STATE_RX_RCV状态,不断将接收到的字符存入缓存,并统计接收计数,重置超时定时器,接收计数大于帧最大长度时,会跳入STATE_RX_ERROR状态。
在任何一处发生超时中断,都会将状态eRcvState置为STATE_RX_IDLE。在接收过程(STATE_RX_RCV)中,发生超时中断,指示着一帧数据接收完成。
接收状态机如图1所示:
Power-on or RST Character received/start T35STATE_RX_INITT35 expiredSTATE_RX_IDLECharacter received/start T35 and stored the characterCharacter received and n_r
图1 接收状态机图
? BOOL xMBRTUTransmitFSM( void )
此函数描述了一个接收状态机,供发送中断调用。状态机中,判断相应发送状态eSndState,实现发送。在STATE_TX_IDLE状态,使能接收关闭发送;在STATE_TX_XMIT状态,调用底层串口发送函数将缓存中的字符发送出去,并使发送指针加1,待发送字符数
7
减1,待发送数为0时,将向系统发送事件EV_FRAME_SENT(Frame sent),同时使能接收关闭发送,并转向STATE_TX_IDLE状态。
发送状态机如图2所示:
Power-on or RST /Enable RX and disable TXSTATE_TX_IDLENeed sendn_t>0/Character sendSTATE_TX_XMITn_t=0/Post EV_FRAME_SENT and enable RX disable TX
图2 发送状态机图
? BOOL xMBRTUTimerT35Expired( void )
此函数描述了发生超时中断时应处理的事务,供超时中断调用。通过判读接收状态eRcvState来决定要处理的事务,思想上有点像摩尔类型的FSM的输出逻辑。若中断发生于STATE_RX_INIT,则向系统发送事件EV_READY(Startup finished);若中断发生于STATE_RX_RCV,则向系统发送事件EV_FRAME_RECEIVED(Frame received);若中断发生于STATE_RX_ERROR,则跳出,不执行。在每个执行分支结束后,均关闭超时定时器,并将eRcvState转为STATE_RX_IDLE。当然,这儿不像FSM的输出逻辑。
2. 关于mb.c文件的理解
? 宏定义与变量
mb.c文件中定义了一系列的宏定义、函数指针及全局变量,并使用优先编译指令预编译一些程序代码。定义与优先编译部分如下: #if MB_RTU_ENABLED == 1 #include \#endif
#if MB_ASCII_ENABLED == 1 #include \#endif
#if MB_TCP_ENABLED == 1 #include \#endif
#ifndef MB_PORT_HAS_CLOSE #define MB_PORT_HAS_CLOSE 0 #endif
/* ----------------------- Static variables ---------------------------------*/
static UCHAR ucMBAddress; static eMBMode eMBCurrentMode;
8
static enum {
STATE_ENABLED, STATE_DISABLED,
STATE_NOT_INITIALIZED
} eMBState = STATE_NOT_INITIALIZED;
/* Functions pointer which are initialized in eMBInit( ). Depending on the * mode (RTU or ASCII) the are set to the correct implementations. */
static peMBFrameSend peMBFrameSendCur; static pvMBFrameStart pvMBFrameStartCur; static pvMBFrameStop pvMBFrameStopCur;
static peMBFrameReceive peMBFrameReceiveCur; static pvMBFrameClose pvMBFrameCloseCur;
/* Callback functions required by the porting layer. They are called when * an external event has happend which includes a timeout or the reception * or transmission of a character. */
BOOL( *pxMBFrameCBByteReceived ) ( void ); BOOL( *pxMBFrameCBTransmitterEmpty ) ( void ); BOOL( *pxMBPortCBTimerExpired ) ( void );
BOOL( *pxMBFrameCBReceiveFSMCur ) ( void ); BOOL( *pxMBFrameCBTransmitFSMCur ) ( void );
/* An array of Modbus functions handlers which associates Modbus function * codes with implementing functions. */
static xMBFunctionHandler xFuncHandlers[MB_FUNC_HANDLERS_MAX] = { #if MB_FUNC_OTHER_REP_SLAVEID_ENABLED > 0
{MB_FUNC_OTHER_REPORT_SLAVEID, eMBFuncReportSlaveID}, #endif
#if MB_FUNC_READ_INPUT_ENABLED > 0
{MB_FUNC_READ_INPUT_REGISTER, eMBFuncReadInputRegister}, #endif
#if MB_FUNC_READ_HOLDING_ENABLED > 0
{MB_FUNC_READ_HOLDING_REGISTER, eMBFuncReadHoldingRegister}, #endif
#if MB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED > 0 {MB_FUNC_WRITE_MULTIPLE_REGISTERS, eMBFuncWriteMultipleHoldingRegister}, #endif
#if MB_FUNC_WRITE_HOLDING_ENABLED > 0
9
{MB_FUNC_WRITE_REGISTER, eMBFuncWriteHoldingRegister}, #endif
#if MB_FUNC_READWRITE_HOLDING_ENABLED > 0 {MB_FUNC_READWRITE_MULTIPLE_REGISTERS, eMBFuncReadWriteMultipleHoldingRegister}, #endif
#if MB_FUNC_READ_COILS_ENABLED > 0
{MB_FUNC_READ_COILS, eMBFuncReadCoils}, #endif
#if MB_FUNC_WRITE_COIL_ENABLED > 0
{MB_FUNC_WRITE_SINGLE_COIL, eMBFuncWriteCoil}, #endif
#if MB_FUNC_WRITE_MULTIPLE_COILS_ENABLED > 0
{MB_FUNC_WRITE_MULTIPLE_COILS, eMBFuncWriteMultipleCoils}, #endif
#if MB_FUNC_READ_DISCRETE_INPUTS_ENABLED > 0
{MB_FUNC_READ_DISCRETE_INPUTS, eMBFuncReadDiscreteInputs}, #endif };
头文件使用优先编译指令,根据Modbus的配置文件中的相应宏开关,预编译所需的头文件,村儿减小协议代码量。
全局变量ucMBAddress与eMBCurrentMode分别表示从机地址与当前所选用的Modbus模式。
接下来定义了一系列的函数指针。在初始化函数中,会根据当前所选用的Modbus模式使这些函数指针指向相应模式下的功能函数。
关于功能代码与功能函数,写的特别巧妙:首先定义xMBFunctionHandler类型的结构体数组xFuncHandlers,对于数组中的每一个元素,都可看成一个结构体。xMBFunctionHandler结构体类型在文件mbproto.h中定义如下: typedef struct {
UCHAR ucFunctionCode; pxMBFunctionHandler pxHandler; } xMBFunctionHandler;
pxMBFunctionHandler描述的是一种函数指针类型,在mbproto.h中定义如下:
typedef eMBException(*pxMBFunctionHandler) (UCHAR *pucFrame,USHORT *pusLength); 故xFuncHandlers中的每一个元素都具有两个成员:ucFunctionCode(功能码)与pxHandler(功能函数指针)。通过相应的宏开关,可选择预编译相应的功能函数(宏开关在文件mbconfig.h中定义)。 ? eMBErrorCode eMBInit( eMBMode eMode, UCHAR ucSlaveAddress, UCHAR ucPort,
ULONG ulBaudRate, eMBParity eParity ) 此函数为Modbus协议初始化函数。函数首先判断从机地址ucSlaveAddress,若为广播地址,或协议保留地址,或配置文件中未规定的地址,均会使该函数返回一个错误MB_EINVAL(illegal argument)。若地址合法,则会将该地址赋给全局变量ucMBAddress,同时根据所选用的模式eMode(MB_RTU、MB_ASCII或MB_TCP)初始化相应的函数指针。
以RTU模式为例,pvMBFrameStartCur将指向协议开始函数void eMBRTUStart( void );pvMBFrameStopCur将指向协议终止函数eMBErrorCode eMBRTUSend( UCHAR
10
百度搜索“77cn”或“免费范文网”即可找到本站免费阅读全部范文。收藏本站方便下次阅读,免费范文网,提供经典小说综合文库FreeModbus学习笔记(2)在线全文阅读。
相关推荐: