77范文网 - 专业文章范例文档资料分享平台

FreeModbus学习笔记

来源:网络收集 时间:2019-04-09 下载这篇文档 手机版
说明:文章内容仅供预览,部分内容可能不全,需要完整文档或者需要复制内容,请下载word后使用。下载word有问题请添加微信号:或QQ: 处理(尽可能给您提供完整文档),感谢您的支持与谅解。点击这里给我发消息

FreeModbus学习笔记

一、 FreeModbus简介

FreeMODBUS一个奥地利人写的Modbus协议。它是一个针对嵌入式应用的一个免费(自由)的通用MODBUS协议的移植。Modbus是一个工业制造环境中应用的一个通用协议。Modbus通信协议栈包括两层:Modbus应用层协议,该层定义了数据模式和功能;另外一层是网络层。

FreeMODBUS 提供了RTU/ASCII 传输模式及TCP协议支持。FreeModbus遵循BSD许可证,这意味着用户可以将FreeModbus应用于商业环境中。目前版本FreeModbus-V1.5提供如下的功能支持:

表1 FreeModbus-V1.5功能支持

代码 Master Slave MB_RTU MB_ASCII MB_TCP 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x0B 0x0C 0x0F 0x10 0x11 0x14 0x15 0x16 0x17 0x18 0x2B 0x2B/0x0D 0x2B/0x0E 主机 从机 RTU模式 ASCII模式 TCP模式 读线圈 读离散输入 读保持寄存器 读输入寄存器 写单个线圈 写单个寄存器 读异常状态 诊断 获取事件计数器 获取事件记录 写多个线圈 写多个寄存器 报告从机ID 读文件记录 写文件记录 屏蔽写寄存器 读/写多个寄存器 写FIFO 封装接口传输 CANopen参考请求与应答 读设备身份表示 描述 是否支持 否 是 是 是 是 是 是 是 是 是 是 否 否 否 否 是 是 是 否 否 否 是 否 否 否 否 协议与文档不一致 备注 二、 FreeModbus对硬件的需求

1

FreeModbus协议对硬件的需求非常少——基本上任何具有串行接口,并且有一些能够容纳modbus数据帧的RAM的微控制器都足够了。

? 一个异步串行接口,能够支持接收缓冲区满和发送缓存区空中断。 ? 一个能够产生RTU传输所需要的t3.5字符超时定时器的时钟。

对于软件部分,仅仅需要一个简单的事件队列。在使用操作系统的处理器上,可通过单独定义一个任务完成Modbus时间的查询。小点的微控制器往往不允许使用操作系统,在那种情况下,可以使用一个全局变量来实现该事件队列(Atmel AVR 移植使用这种方式实现)。 实际的存储器需求决定于所使用的Modbus模块的多少。下表列出了所支持的功能编译后所需要的存储器。ARM是使用GNUARM编译器3.4.4使用-O1选项得到的。AVR项数值是使用WinAVR编译器3.4.5使用-Os选项编译得到的。

表2 FreeModbus对硬件的需求

Module Modbus RTU (Required) Modbus ASCII (Optional) Modbus Functions [1] Modbus Core (Required) Porting Layer (Required [2]) Totals ARM Code 1132Byte 1612Byte 1180Byte 924Byte 1756Byte 7304Byte ARM RAM (static) 272Byte 28Byte 34Byte 180Byte 16Byte 530Byte AVR Code 1456Byte 1222Byte 1602Byte 608Byte 704Byte 5592Byte AVR RAM (static) 266Byte 16Byte 34Byte 75Byte 7Byte 398Byte [1] 实际大小决定于可支持的Modbus功能码的多少。功能码可以在头文件mbconfig.h中进

行配置。 [2] 决定于硬件。

三、 FreeModbus的移植

1、 物理层接口文件的修改

在物理层,用户只需完成串行口及超时定时器的配置即可。具体应修改接口文件portserial.c及porttimer.c。

? portserial.c中函数的修改:

1) void vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )

此函数的功能为设置串口状态。有两个参数:xRxEnable及xTxEnable。当xRxEnable为真时,应使能串口接收及接收中断。在RS485通讯系统中,还要注意将RS485接口芯片设为接收使能状态;当xTxEnable为真时,应使能串口发送及发送中断。在RS485通讯系统中,还要注意将RS485接口芯片设为发送使能状态。 2) void vMBPortClose( void )

此函数的功能是关闭Modbus通讯端口,具体的,应在此函数中关闭通讯端口的发送使能及接收使能。

3) BOOL xMBPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits,

eMBParity eParity) 此函数的功能是初始化串行通讯端口。有四个参数:ucPORT、ulBaudRate、ucDataBits及eParity。参数ucPORT可以忽略;参数ulBaudRate是通讯端口的波特率,应根据此数值设置所使用硬件端口的波特率;参数ucDataBits为通讯时所使用的数据位宽,注意,若使用RTU模式,则有ucDataBits=8,若使用ASCII模式,则有ucDataBits=7,应根据此参数设置所使用硬件端口的数据位宽;eParity为校验方式,eParity=MB_PAR_NONE为无校验,此时

2

硬件端口应设置为无校验方式及两个停止位,eParity=MB_PAR_ODD为奇校验,此时硬件端口应设置为奇校验方式及一个停止位,eParity= MB_PAR_EVEN为偶校验,此时硬件端口应设置为偶校验方式及一个停止位。函数返回值务必为TRUE。 4) BOOL xMBPortSerialPutByte(CHAR ucByte)

此函数的功能为通讯端口发送一字节数据。参数为:ucByte,待发送的数据。应在此函数中编写发送一字节数据的函数。注意,由于使用的是中断发送,故只需将数据放到发送寄存器即可。函数返回值务必为TRUE。

5) BOOL xMBPortSerialGetByte( CHAR * pucByte )

此函数的功能为通讯端口接收一字节数据。参数为:* pucByte,接收到的数据。应在此函数中编写接收的函数。注意,由于使用的是中断接收,故只需将接收寄存器的值放到* pucByte即可。函数返回值务必为TRUE。 6) void prvvUARTTxReadyISR(void)

发送中断函数。此函数无需修改。只需在用户的发送中断函数中调用此函数即可,同时,用户应在调用此函数后,清除发送中断标志位。 7) void prvvUARTRxISR(void)

发送中断函数。此函数无需修改。只需在用户的接收中断函数中调用此函数即可,同时,用户应在调用此函数后,清除接收中断标志位。

? portserial.c中函数的修改:

1) BOOL xMBPortTimersInit( USHORT usTim1Timerout50us )

此函数的功能为初始化超时定时器。参数为:usTim1Timerout50us,50us的个数。用户应根据所使用的硬件初始化超时定时器,使之能产生中断时间为usTim1Timerout50us*50us的中断。函数返回值务必为TRUE。 2) void vMBPortTimersEnable( )

此函数的功能为使能超时定时器。用户需在此函数中清除中断标志位、清零定时器计数值,并重新使能定时器中断。 3) void vMBPortTimersDisable( )

此函数的功能为关闭超时定时器。用户需在此函数中清零定时器计数值,并关闭定时器中断。

4) void TIMERExpiredISR( void )

定时器中断函数。此函数无需修改。只需在用户的定时器中断中调用此函数即可,同时,用户应在调用此函数后清除中断标志位。

2、 应用层回函数的修改

在应用层,用户需要定义所需要使用的寄存器,并修改对应的回函数。回函数有如下几个:

1) eMBErrorCode eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT

usNRegs ) 输入寄存器回函数。* pucRegBuffer为要添加到协议中的数据,usAddress为输入寄存器地址,usNRegs为要读取寄存器的个数。用户应根据要访问的寄存器地址usAddress将相应输入寄存器的值按顺序添加到pucRegBuffer中。

2) eMBErrorCode eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress,

USHORT usNRegs, eMBRegisterMode eMode ) 保持寄存器回函数。* pucRegBuffer为要协议中的数据,usAddress为输入寄存器地址,usNRegs为访问寄存器的个数,eMode为访问类型(MB_REG_READ为读保持寄存器,MB_REG_WRITE为写保持寄存器)。用户应根据要访问的寄存器地址usAddress将相应输入寄存器的值按顺序添加到pucRegBuffer中,或将协议中的数据根据要访问的寄存器地址usAddress放到相应保持寄存器中。

3) eMBErrorCode eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT

3

usNCoils, eMBRegisterMode eMode )

读写线圈回函数。* pucRegBuffer为要添加到协议中的数据,usAddress为线圈地址,usNCoils为要访问线圈的个数,eMode为访问类型(MB_REG_READ为读线圈状态,MB_REG_WRITE为写线圈)。用户应根据要访问的线圈地址usAddress将相应线圈的值按顺序添加到pucRegBuffer中,或将协议中的数据根据要访问的线圈地址usAddress放到相应线圈中。

4) eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress,

USHORT usNDiscrete ) 读离散线圈回函数。* pucRegBuffer为要添加到协议中的数据,usAddress为线圈地址,usNDiscrete为要访问线圈的个数。用户应根据要访问的线圈地址usAddress将相应线圈的值按顺序添加到pucRegBuffer中。

3、 应用层初始化及协议访问

用户只需在主函数中调用协议初始化代码,及消息处理函数即可。需用户调用的函数有如下几个:

1) eMBErrorCode eMBInit( eMBMode eMode, UCHAR ucSlaveAddress, UCHAR ucPort,

ULONG ulBaudRate, eMBParity eParity ) 协议初始化函数。eMode为所要使用的模式,用户可选MB_RTU(RTU模式)、MB_ASCII(ASCII模式)或MB_TCP(TCP模式);ucSlaveAddress为从机地址,用户根据需要,取值为1~247(0为广播地址,248~255协议保留);ulBaudRate为通信波特率,用户根据需要选用,但务必使主机能支持此波特率;eParity为校验方式,用户根据需要选用,但务必使主机能支持此校验方式。

2) eMBErrorCode eMBSetSlaveID( UCHAR ucSlaveID, BOOL xIsRunning, UCHAR const

*pucAdditional, USHORT usAdditionalLen ) 从机ID设置函数。注意,ID表示的是设备的类型,不同于ucSlaveAddress(从机地址)。对同一通讯系统中,可以有相同的ucSlaveID,但不可以有相同的ucSlaveAddress。ucSlaveID为一字节的设备ID号;xIsRunning为设备的运行状态,0xFF为运行,0x00为停止;* pucAdditional为设备的附加描述,根据需要添加;usAdditionalLen为附加描述的长度(按字节计算)。此函数不是必须调用的。但当一个Modbus通讯系统中有不同种设备时,应调用此函数添加对应设备的描述。 3) eMBErrorCode eMBPoll( void )

轮询事件查询处理函数。用户需在主循环中调用此函数。对于使用操作系统的程序,应单独创建一个任务,使操作系统能周期调用此函数。

四、 FreeModbus初始化及运行流程

FreeModbus是基于消息队列的协议。协议通过检测相应的消息来完成对应功能。协议栈的初始化及运行流程如下:

1) 首先调用eMBErrorCode eMBInit( eMBMode eMode, UCHAR ucSlaveAddress, UCHAR

ucPort, ULONG ulBaudRate, eMBParity eParity )完成物理层设备的初始化,主要包括: BOOL xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )串口初始化,设定波特率、数据位数、校验方式;BOOL xMBPortTimersInit( USHORT usTim1Timerout50us )定时器初始化,设定T35定时所需要的定时器常数。 2) 调用(此处非必需)eMBErrorCode eMBSetSlaveID( UCHAR ucSlaveID, BOOL

xIsRunning,UCHAR const *pucAdditional, USHORT usAdditionalLen )指定设备ID。 3) 调用eMBErrorCode eMBEnable(void)使能协议栈,主要包括:static pvMBFrameStart

pvMBFrameStartCur(函数指针)协议栈开始,将eRcvState设为STATE_RX_INIT状态,调用void vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )使能接收,调用void vMBPortTimersEnable( )使能超时定时器。

4

4) 在3中使能了超时定时器,故经过T35时间后,发生第一次超时中断,在中断中,向协

议栈发送消息EV_READY(Startup finished),并调用void vMBPortTimersDisable( )关闭超时定时器,同时将eRcvState设为STATE_RX_IDLE。此时,协议栈可以接收串口数据。注意,此处首先启用一次超时定时器是因为初始化完成时,串口有可能已经有数据,因为无法判断第一个数据是请求的开始,故等待T35,接收下一帧请求。 5) 此时,主函数调用eMBErrorCode eMBPoll( void )检测事件。

6) 若发生串口接收中断,且eRcvState为STATE_RX_IDLE(4中已将eRcvState设为

STATE_RX_IDLE),则向接收缓存中存入接收到的字符,同时将eRcvState设为STATE_RX_RCV状态,并清零超时定时器。在下一个数据来到时,不断将数据存入接收缓存,并清零超时定时器。 7) 如果没有接收完成,则不可能发生超时中断。发生超时中断,说明T35时间内未收到新

的串口数据,根据Modbus协议的规定,这指示着一帧请求数据接收完成。在中断中,向协议栈发送消息EV_FRAME_RECEIVED(Frame received),等待协议栈处理此消息。 8) 主函数调用eMBErrorCode eMBPoll( void )检测到事件EV_FRAME_RECEIVED后,调用static peMBFrameReceive peMBFrameReceiveCur简单判断请求帧数据,并向协议栈发送消息EV_EXECUTE(Execute function)。 9) 主函数调用eMBErrorCode eMBPoll( void )检测到事件EV_EXECUTE后,根据相应的请求代码查找处理该功能的函数指针来处理该功能。若不是广播消息,则调用static peMBFrameSend peMBFrameSendCur发送回复消息,在此函数中,只把要回复的数据复制到了串口缓存中,同时将eSndState设为STATE_TX_XMIT(Transmitter is in transfer state),并通过调用void vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )使能发送中断。注意,发送中断使能后,由于串口发送寄存器本来就是空的,故在使能后将进入发送中断中。 10) 发送中断中,且eSndState为STATE_TX_XMIT(9中已将eSndState设为

STATE_TX_XMIT),则将串口缓存中的数据发送出去,同时不断对发送字符个数统计,当发送完成后,向协议栈发送消息EV_FRAME_SENT(Frame sent)。 11) 主函数调用eMBErrorCode eMBPoll( void )检测到事件EV_FRAME_SENT后,不处理此消息。 12) 当串口接收到数据后,协议栈将重复6-11处理消息。

五、 一些理解

1. 关于mbrtu.c文件的理解

? 宏定义与变量

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. */

5

百度搜索“77cn”或“免费范文网”即可找到本站免费阅读全部范文。收藏本站方便下次阅读,免费范文网,提供经典小说综合文库FreeModbus学习笔记在线全文阅读。

FreeModbus学习笔记.doc 将本文的Word文档下载到电脑,方便复制、编辑、收藏和打印 下载失败或者文档不完整,请联系客服人员解决!
本文链接:https://www.77cn.com.cn/wenku/zonghe/581197.html(转载请注明文章来源)
Copyright © 2008-2022 免费范文网 版权所有
声明 :本网站尊重并保护知识产权,根据《信息网络传播权保护条例》,如果我们转载的作品侵犯了您的权利,请在一个月内通知我们,我们会及时删除。
客服QQ: 邮箱:tiandhx2@hotmail.com
苏ICP备16052595号-18
× 注册会员免费下载(下载后可以自由复制和排版)
注册会员下载
全站内容免费自由复制
注册会员下载
全站内容免费自由复制
注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: