打印

准备做一个Freemodbus移植到PSoC4上,想盖个楼

[复制链接]
楼主: zb0830
手机看帖
扫描二维码
随时随地手机跟帖
21
zb0830|  楼主 | 2015-4-20 14:22 | 只看该作者 回帖奖励 |倒序浏览
一些理解
编辑

1. 关于mbrtu.c文件的理解
u 宏定义与变量
mbrtu.c文件中定义了RTU模式下的宏定义、全局变量与功能函数。所包含的宏定义与全局变量定义如下:
/* ----------------------- 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. */
/* ----------------------- Type definitions ---------------------------------*/
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;
/* ----------------------- 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;

使用特权

评论回复
22
zb0830|  楼主 | 2015-4-20 14:22 | 只看该作者
首先在宏定义中,指明了该模式下所支持的最小请求帧长度为4(1字节地址+1字节命令+2字节校验),最大请求帧长度为256,CRC为两字节,地址为第一字节,PDU开始于第二字节。
在全局变量中,只定义了一个串口缓存数组ucRTUBuf[MB_SER_PDU_SIZE_MAX]。由于发送与接收不是同步的,故可采用该缓存数组实现Modbus协议。在接收过程中,将所接收到的数据直接存放于缓存ucRTUBuf中,在发送过程中,通过指针*pucSndBufferCur来访问该数组。
u eMBErrorCode eMBRTUInit( UCHAR ucSlaveAddress, UCHAR ucPort, ULONG ulBaudRate, eMBParity eParity )
此函数为RTU模式的初始化函数。此函数中判断串行口初始化是否成功(通过判断串行口初始化函数的返回值实现。当然,查看返回值必然先调用该函数,从而完成端口初始化),如果成功,则根据波特率计算T35,初始化超时定时器。

使用特权

评论回复
23
zb0830|  楼主 | 2015-4-20 14:23 | 只看该作者
u void eMBRTUStart( void )
此函数为RTU模式开始函数。函数主要功能是,将接收状态eRcvState设为STATE_RX_INIT(Receiver is in initial state),使能接收同时关闭发送,使能超时定时器。
u void eMBRTUStop( void )
此函数为RTU模式终止函数。函数主要功能是,关闭接收与发送,关闭超时定时器。
u eMBErrorCode eMBRTUReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame, USHORT * pusLength )
此函数为RTU接收数据帧信息提取函数。函数主要功能是,将接收帧(存放于缓存)的地址指针赋给指针变量pucRcvAddress,将PDU编码首地址赋给指针* pucFrame,将PDU长度地址赋给指针变量pusLength。使用指针访问缓存数组,而不是额外开辟缓存存放帧信息,大大减少了内存的开支。
u eMBErrorCode eMBRTUSend( UCHAR ucSlaveAddress, const UCHAR * pucFrame, USHORT usLength )
此函数为RTU回复帧信息组织函数。函数的功能是,此函数首先使发送内容指针pucSndBufferCur指向pucFrame之前的一个地址,并将该地址内容填充为ucSlaveAddress,并使用直接访问方式向缓存数组ucRTUBuf的相应地址内存入CRC校验值。注意,此函数中,对ucRTUBuf的访问既有间接方式(指针pucSndBufferCur与pucFrame),又有直接方式(直接向相应地址内写值),比较难理解。
回复帧组织完后,将发送状态eSndState设为STATE_TX_XMIT(Transmitter is in transfer state),并禁止接收使能发送。发送一旦使能,就会进入发送中断,完成相应字符的发送。

使用特权

评论回复
24
zb0830|  楼主 | 2015-4-20 14:23 | 只看该作者
u 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)中,发生超时中断,指示着一帧数据接收完成。

使用特权

评论回复
25
zb0830|  楼主 | 2015-4-20 14:24 | 只看该作者
u BOOL xMBRTUTransmitFSM( void )
此函数描述了一个接收状态机,供发送中断调用。状态机中,判断相应发送状态eSndState,实现发送。在STATE_TX_IDLE状态,使能接收关闭发送;在STATE_TX_XMIT状态,调用底层串口发送函数将缓存中的字符发送出去,并使发送指针加1,待发送字符数减1,待发送数为0时,将向系统发送事件EV_FRAME_SENT(Frame sent),同时使能接收关闭发送,并转向STATE_TX_IDLE状态。

使用特权

评论回复
26
zb0830|  楼主 | 2015-4-20 14:24 | 只看该作者
u 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的输出逻辑。

使用特权

评论回复
27
zb0830|  楼主 | 2015-4-20 14:24 | 只看该作者
2. 关于mb.c文件的理解
u 宏定义与变量
mb.c文件中定义了一系列的宏定义、函数指针及全局变量,并使用优先编译指令预编译一些程序代码。定义与优先编译部分如下:
#if MB_RTU_ENABLED == 1
#include "mbrtu.h"
#endif
#if MB_ASCII_ENABLED == 1
#include "mbascii.h"
#endif
#if MB_TCP_ENABLED == 1
#include "mbtcp.h"
#endif
#ifndef MB_PORT_HAS_CLOSE
#define MB_PORT_HAS_CLOSE 0
#endif
/* ----------------------- Static variables ---------------------------------*/
static UCHAR ucMBAddress;
static eMBMode eMBCurrentMode;
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
{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
};

使用特权

评论回复
28
zb0830|  楼主 | 2015-4-20 14:24 | 只看该作者
头文件使用优先编译指令,根据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中定义)。

使用特权

评论回复
29
zb0830|  楼主 | 2015-4-20 14:25 | 只看该作者
u 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 ucSlaveAddress, const UCHAR * pucFrame, USHORT usLength );peMBFrameReceiveCur将指向接收帧信息提取函数eMBErrorCode eMBRTUReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame, USHORT * pusLength );pvMBFrameCloseCur将指向端口关闭函数void vMBPortClose( void )(portserial.c中定义);pxMBFrameCBByteReceived将指向接收中断状态机函数BOOL xMBRTUReceiveFSM( void );pxMBFrameCBTransmitterEmpty将指向发送中断状态机函数BOOL xMBRTUTransmitFSM( void );pxMBPortCBTimerExpired将指向超时中断函数BOOL xMBRTUTimerT35Expired( void )。
完成相应函数指针的初始化之后,会调用该模式的初始化函数完成相应从机地址ucMBAddress、从机端口ucPort、从机通信速率ulBaudRate、从机校验方式eParity的初始化。

使用特权

评论回复
30
zb0830|  楼主 | 2015-4-20 14:25 | 只看该作者
u eMBErrorCode eMBTCPInit( USHORT ucTCPPort )
Modbus TCP模式初始化函数。只有当配置文件使能对应的宏开关MB_TCP_ENABLED时,才会编译该函数。该函数会初始化所使用的TCP/IP端口号,并初始化相应的函数指针。
u eMBErrorCode eMBRegisterCB( UCHAR ucFunctionCode, pxMBFunctionHandler pxHandler )
Modbus功能注册函数。通过该函数,可以定义FreeModbus协议外的功能代码,并注册相应的功能函数。具体如何实现还没具体看。
u eMBErrorCode eMBClose( void )
Modbus端口关闭函数。该函数通过函数指针pvMBFrameCloseCur(指向通讯端口关闭函数)来停止止Modbus端口上的通讯。
u eMBErrorCode eMBEnable( void )
Modbus协议开始函数。该函数通过函数指针pvMBFrameStartCur(指向相应模式下的使能函数)来使能Modbus通讯。
u eMBErrorCode eMBDisable( void )
Modbus协议终止函数。该函数通过函数指针pvMBFrameStopCur(指向相应模式下的终止函数)来终止Modbus协议。
u eMBErrorCode eMBPoll( void )
Modbus事件轮询处理函数。该函数通过查询底层返回来的事件eEvent来决定当前该处理的事务。

使用特权

评论回复
31
zb0830|  楼主 | 2015-4-20 14:25 | 只看该作者
处理过程为:若事件为EV_READY(Startup finished),则跳出,等待下一次查询;若事件为EV_FRAME_RECEIVED(Frame received),则通过函数指针peMBFrameReceiveCur(指向接收帧信息提取函数)来完成帧信息的提取,并向系统发送EV_EXECUTE(Execute function)事件;若事件为EV_EXECUTE,则根据已经从帧信息中提取到的功能码在xFuncHandlers中查询对应的功能函数指针,查找到后通过函数指针调用相应的功能处理函数来完成帧信息的处理(向缓存数组中存放回复PDU),完成处理后,通过函数指针peMBFrameSendCur调用帧发送函数完成回复帧的发送;若事件为EV_FRAME_SENT(Frame sent),则跳出,等待下一次查询。

使用特权

评论回复
32
zb0830|  楼主 | 2015-4-20 14:26 | 只看该作者
3. 关于mbconfig.h文件的理解
此文件为Modbus协议的配置文件。在移植时,应根据所选用的目标处理器灵活修改此文件,使之满足需要而代码最小。当然,若果你的处理器处理能力足够强,可以保持默认配置,或是根据需要,增加相应的功能的配置宏。文件内容及相应解释如下:
#ifndef _MB_CONFIG_H
#define _MB_CONFIG_H
//外部C编译器宏开关
#ifdef __cplusplus
PR_BEGIN_EXTERN_C
#endif
/* ----------------------- Defines ------------------------------------------*/
/*! \brief If Modbus ASCII support is enabled. */
#define MB_ASCII_ENABLED ( 1 )
/*! \brief If Modbus RTU support is enabled. */
#define MB_RTU_ENABLED ( 1 )
/*! \brief If Modbus TCP support is enabled. */
#define MB_TCP_ENABLED ( 0 )
/*! \brief The character timeout value for Modbus ASCII. */
#define MB_ASCII_TIMEOUT_SEC ( 1 )
/*! \brief Timeout to wait in ASCII prior to enabling transmitter. */
#ifndef MB_ASCII_TIMEOUT_WAIT_BEFORE_SEND_MS
#define MB_ASCII_TIMEOUT_WAIT_BEFORE_SEND_MS ( 0 )
#endif
/*! \brief Maximum number of Modbus functions codes the protocol stack */
#define MB_FUNC_HANDLERS_MAX ( 16 )
/*! \brief Number of bytes which should be allocated for the <em>Report Slave ID */
#define MB_FUNC_OTHER_REP_SLAVEID_BUF ( 32 )
/*! \brief If the <em>Report Slave ID</em> function should be enabled. */
#define MB_FUNC_OTHER_REP_SLAVEID_ENABLED ( 1 )
/*! \brief If the <em>Read Input Registers</em> function should be enabled. */
#define MB_FUNC_READ_INPUT_ENABLED ( 1 )
/*! \brief If the <em>Read Holding Registers</em> function should be enabled. */
#define MB_FUNC_READ_HOLDING_ENABLED ( 1 )
/*! \brief If the <em>Write Single Register</em> function should be enabled. */
#define MB_FUNC_WRITE_HOLDING_ENABLED ( 1 )
/*! \brief If the <em>Write Multiple registers</em> function should be enabled. */
#define MB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED ( 1 )
/*! \brief If the <em>Read Coils</em> function should be enabled. */
#define MB_FUNC_READ_COILS_ENABLED ( 1 )
/*! \brief If the <em>Write Coils</em> function should be enabled. */
#define MB_FUNC_WRITE_COIL_ENABLED ( 1 )
/*! \brief If the <em>Write Multiple Coils</em> function should be enabled. */
#define MB_FUNC_WRITE_MULTIPLE_COILS_ENABLED ( 1 )
/*! \brief If the <em>Read Discrete Inputs</em> function should be enabled. */
#define MB_FUNC_READ_DISCRETE_INPUTS_ENABLED ( 1 )
/*! \brief If the <em>Read/Write Multiple Registers</em> function should be enabled. */
#define MB_FUNC_READWRITE_HOLDING_ENABLED ( 1 )
/*! @} */
#ifdef __cplusplus
PR_END_EXTERN_C
#endif
#endif

使用特权

评论回复
33
hnkf118| | 2015-4-20 16:00 | 只看该作者
哦。看你研究吧。

使用特权

评论回复
34
zb0830|  楼主 | 2015-4-20 17:33 | 只看该作者
今天才开始研究,上传一个可以用的STM32的例程

使用特权

评论回复
35
zb0830|  楼主 | 2015-4-20 17:37 | 只看该作者
还无法上传大于5MB的文件

STM32-Freemodbus.part01.rar

2 MB

使用特权

评论回复
36
zb0830|  楼主 | 2015-4-20 17:37 | 只看该作者
再来一个

STM32-Freemodbus.part02.rar

2 MB

使用特权

评论回复
37
zb0830|  楼主 | 2015-4-20 17:38 | 只看该作者
再来一个

STM32-Freemodbus.part03.rar

2 MB

使用特权

评论回复
38
zb0830|  楼主 | 2015-4-20 17:38 | 只看该作者
再来一个

STM32-Freemodbus.part04.rar

459.42 KB

使用特权

评论回复
39
zheng522| | 2015-4-23 23:54 | 只看该作者
顶一下,什么时候开始呢?

使用特权

评论回复
40
波越| | 2015-4-24 00:11 | 只看该作者
等你的楼

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则