FreeModbus学习笔记.docx

上传人:b****3 文档编号:4008691 上传时间:2022-11-27 格式:DOCX 页数:17 大小:49.61KB
下载 相关 举报
FreeModbus学习笔记.docx_第1页
第1页 / 共17页
FreeModbus学习笔记.docx_第2页
第2页 / 共17页
FreeModbus学习笔记.docx_第3页
第3页 / 共17页
FreeModbus学习笔记.docx_第4页
第4页 / 共17页
FreeModbus学习笔记.docx_第5页
第5页 / 共17页
点击查看更多>>
下载资源
资源描述

FreeModbus学习笔记.docx

《FreeModbus学习笔记.docx》由会员分享,可在线阅读,更多相关《FreeModbus学习笔记.docx(17页珍藏版)》请在冰豆网上搜索。

FreeModbus学习笔记.docx

FreeModbus学习笔记

FreeModbus学习笔记

一、FreeModbus简介

FreeMODBUS一个奥地利人写的Modbus协议。

它是一个针对嵌入式应用的一个免费(自由)的通用MODBUS协议的移植。

Modbus是一个工业制造环境中应用的一个通用协议。

Modbus通信协议栈包括两层:

Modbus应用层协议,该层定义了数据模式和功能;另外一层是网络层。

FreeMODBUS提供了RTU/ASCII传输模式及TCP协议支持。

FreeModbus遵循BSD许可证,这意味着用户可以将FreeModbus应用于商业环境中。

目前版本FreeModbus-V1.5提供如下的功能支持:

表1FreeModbus-V1.5功能支持

代码

描述

是否支持

备注

Master

主机

Slave

从机

MB_RTU

RTU模式

MB_ASCII

ASCII模式

MB_TCP

TCP模式

0x01

读线圈

0x02

读离散输入

0x03

读保持寄存器

0x04

读输入寄存器

0x05

写单个线圈

0x06

写单个寄存器

0x07

读异常状态

0x08

诊断

0x0B

获取事件计数器

0x0C

获取事件记录

0x0F

写多个线圈

0x10

写多个寄存器

0x11

报告从机ID

协议与文档不一致

0x14

读文件记录

0x15

写文件记录

0x16

屏蔽写寄存器

0x17

读/写多个寄存器

0x18

写FIFO

0x2B

封装接口传输

0x2B/0x0D

CANopen参考请求与应答

0x2B/0x0E

读设备身份表示

二、FreeModbus对硬件的需求

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

◆一个异步串行接口,能够支持接收缓冲区满和发送缓存区空中断。

◆一个能够产生RTU传输所需要的t3.5字符超时定时器的时钟。

对于软件部分,仅仅需要一个简单的事件队列。

在使用操作系统的处理器上,可通过单独定义一个任务完成Modbus时间的查询。

小点的微控制器往往不允许使用操作系统,在那种情况下,可以使用一个全局变量来实现该事件队列(AtmelAVR移植使用这种方式实现)。

实际的存储器需求决定于所使用的Modbus模块的多少。

下表列出了所支持的功能编译后所需要的存储器。

ARM是使用GNUARM编译器3.4.4使用-O1选项得到的。

AVR项数值是使用WinAVR编译器3.4.5使用-Os选项编译得到的。

表2FreeModbus对硬件的需求

Module

ARMCode

ARMRAM

(static)

AVRCode

AVRRAM

(static)

ModbusRTU(Required)

1132Byte

272Byte

1456Byte

266Byte

ModbusASCII(Optional)

1612Byte

28Byte

1222Byte

16Byte

ModbusFunctions[1]

1180Byte

34Byte

1602Byte

34Byte

ModbusCore(Required)

924Byte

180Byte

608Byte

75Byte

PortingLayer(Required[2])

1756Byte

16Byte

704Byte

7Byte

Totals

7304Byte

530Byte

5592Byte

398Byte

[1]实际大小决定于可支持的Modbus功能码的多少。

功能码可以在头文件mbconfig.h中进行配置。

[2]决定于硬件。

三、FreeModbus的移植

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

在物理层,用户只需完成串行口及超时定时器的配置即可。

具体应修改接口文件portserial.c及porttimer.c。

◆portserial.c中函数的修改:

1)voidvMBPortSerialEnable(BOOLxRxEnable,BOOLxTxEnable)

此函数的功能为设置串口状态。

有两个参数:

xRxEnable及xTxEnable。

当xRxEnable为真时,应使能串口接收及接收中断。

在RS485通讯系统中,还要注意将RS485接口芯片设为接收使能状态;当xTxEnable为真时,应使能串口发送及发送中断。

在RS485通讯系统中,还要注意将RS485接口芯片设为发送使能状态。

2)voidvMBPortClose(void)

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

3)BOOLxMBPortSerialInit(UCHARucPORT,ULONGulBaudRate,UCHARucDataBits,eMBParityeParity)

此函数的功能是初始化串行通讯端口。

有四个参数:

ucPORT、ulBaudRate、ucDataBits及eParity。

参数ucPORT可以忽略;参数ulBaudRate是通讯端口的波特率,应根据此数值设置所使用硬件端口的波特率;参数ucDataBits为通讯时所使用的数据位宽,注意,若使用RTU模式,则有ucDataBits=8,若使用ASCII模式,则有ucDataBits=7,应根据此参数设置所使用硬件端口的数据位宽;eParity为校验方式,eParity=MB_PAR_NONE为无校验,此时硬件端口应设置为无校验方式及两个停止位,eParity=MB_PAR_ODD为奇校验,此时硬件端口应设置为奇校验方式及一个停止位,eParity=MB_PAR_EVEN为偶校验,此时硬件端口应设置为偶校验方式及一个停止位。

函数返回值务必为TRUE。

4)BOOLxMBPortSerialPutByte(CHARucByte)

此函数的功能为通讯端口发送一字节数据。

参数为:

ucByte,待发送的数据。

应在此函数中编写发送一字节数据的函数。

注意,由于使用的是中断发送,故只需将数据放到发送寄存器即可。

函数返回值务必为TRUE。

5)BOOLxMBPortSerialGetByte(CHAR*pucByte)

此函数的功能为通讯端口接收一字节数据。

参数为:

*pucByte,接收到的数据。

应在此函数中编写接收的函数。

注意,由于使用的是中断接收,故只需将接收寄存器的值放到*pucByte即可。

函数返回值务必为TRUE。

6)voidprvvUARTTxReadyISR(void)

发送中断函数。

此函数无需修改。

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

7)voidprvvUARTRxISR(void)

发送中断函数。

此函数无需修改。

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

◆portserial.c中函数的修改:

1)BOOLxMBPortTimersInit(USHORTusTim1Timerout50us)

此函数的功能为初始化超时定时器。

参数为:

usTim1Timerout50us,50us的个数。

用户应根据所使用的硬件初始化超时定时器,使之能产生中断时间为usTim1Timerout50us*50us的中断。

函数返回值务必为TRUE。

2)voidvMBPortTimersEnable()

此函数的功能为使能超时定时器。

用户需在此函数中清除中断标志位、清零定时器计数值,并重新使能定时器中断。

3)voidvMBPortTimersDisable()

此函数的功能为关闭超时定时器。

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

4)voidTIMERExpiredISR(void)

定时器中断函数。

此函数无需修改。

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

2、应用层回函数的修改

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

回函数有如下几个:

1)eMBErrorCodeeMBRegInputCB(UCHAR*pucRegBuffer,USHORTusAddress,USHORTusNRegs)

输入寄存器回函数。

*pucRegBuffer为要添加到协议中的数据,usAddress为输入寄存器地址,usNRegs为要读取寄存器的个数。

用户应根据要访问的寄存器地址usAddress将相应输入寄存器的值按顺序添加到pucRegBuffer中。

2)eMBErrorCodeeMBRegHoldingCB(UCHAR*pucRegBuffer,USHORTusAddress,USHORTusNRegs,eMBRegisterModeeMode)

保持寄存器回函数。

*pucRegBuffer为要协议中的数据,usAddress为输入寄存器地址,usNRegs为访问寄存器的个数,eMode为访问类型(MB_REG_READ为读保持寄存器,MB_REG_WRITE为写保持寄存器)。

用户应根据要访问的寄存器地址usAddress将相应输入寄存器的值按顺序添加到pucRegBuffer中,或将协议中的数据根据要访问的寄存器地址usAddress放到相应保持寄存器中。

3)eMBErrorCodeeMBRegCoilsCB(UCHAR*pucRegBuffer,USHORTusAddress,USHORTusNCoils,eMBRegisterModeeMode)

读写线圈回函数。

*pucRegBuffer为要添加到协议中的数据,usAddress为线圈地址,usNCoils为要访问线圈的个数,eMode为访问类型(MB_REG_READ为读线圈状态,MB_REG_WRITE为写线圈)。

用户应根据要访问的线圈地址usAddress将相应线圈的值按顺序添加到pucRegBuffer中,或将协议中的数据根据要访问的线圈地址usAddress放到相应线圈中。

4)eMBErrorCodeeMBRegDiscreteCB(UCHAR*pucRegBuffer,USHORTusAddress,USHORTusNDiscrete)

读离散线圈回函数。

*pucRegBuffer为要添加到协议中的数据,usAddress为线圈地址,usNDiscrete为要访问线圈的个数。

用户应根据要访问的线圈地址usAddress将相应线圈的值按顺序添加到pucRegBuffer中。

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

用户只需在主函数中调用协议初始化代码,及消息处理函数即可。

需用户调用的函数有如下几个:

1)eMBErrorCodeeMBInit(eMBModeeMode,UCHARucSlaveAddress,UCHARucPort,ULONGulBaudRate,eMBParityeParity)

协议初始化函数。

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

2)eMBErrorCodeeMBSetSlaveID(UCHARucSlaveID,BOOLxIsRunning,UCHARconst*pucAdditional,USHORTusAdditionalLen)

从机ID设置函数。

注意,ID表示的是设备的类型,不同于ucSlaveAddress(从机地址)。

对同一通讯系统中,可以有相同的ucSlaveID,但不可以有相同的ucSlaveAddress。

ucSlaveID为一字节的设备ID号;xIsRunning为设备的运行状态,0xFF为运行,0x00为停止;*pucAdditional为设备的附加描述,根据需要添加;usAdditionalLen为附加描述的长度(按字节计算)。

此函数不是必须调用的。

但当一个Modbus通讯系统中有不同种设备时,应调用此函数添加对应设备的描述。

3)eMBErrorCodeeMBPoll(void)

轮询事件查询处理函数。

用户需在主循环中调用此函数。

对于使用操作系统的程序,应单独创建一个任务,使操作系统能周期调用此函数。

四、FreeModbus初始化及运行流程

FreeModbus是基于消息队列的协议。

协议通过检测相应的消息来完成对应功能。

协议栈的初始化及运行流程如下:

1)首先调用eMBErrorCodeeMBInit(eMBModeeMode,UCHARucSlaveAddress,UCHARucPort,ULONGulBaudRate,eMBParityeParity)完成物理层设备的初始化,主要包括:

BOOLxMBPortSerialInit(UCHARucPORT,ULONGulBaudRate,UCHARucDataBits,eMBParityeParity)串口初始化,设定波特率、数据位数、校验方式;BOOLxMBPortTimersInit(USHORTusTim1Timerout50us)定时器初始化,设定T35定时所需要的定时器常数。

2)调用(此处非必需)eMBErrorCodeeMBSetSlaveID(UCHARucSlaveID,BOOLxIsRunning,UCHARconst*pucAdditional,USHORTusAdditionalLen)指定设备ID。

3)调用eMBErrorCodeeMBEnable(void)使能协议栈,主要包括:

staticpvMBFrameStartpvMBFrameStartCur(函数指针)协议栈开始,将eRcvState设为STATE_RX_INIT状态,调用voidvMBPortSerialEnable(BOOLxRxEnable,BOOLxTxEnable)使能接收,调用voidvMBPortTimersEnable()使能超时定时器。

4)在3中使能了超时定时器,故经过T35时间后,发生第一次超时中断,在中断中,向协议栈发送消息EV_READY(Startupfinished),并调用voidvMBPortTimersDisable()关闭超时定时器,同时将eRcvState设为STATE_RX_IDLE。

此时,协议栈可以接收串口数据。

注意,此处首先启用一次超时定时器是因为初始化完成时,串口有可能已经有数据,因为无法判断第一个数据是请求的开始,故等待T35,接收下一帧请求。

5)此时,主函数调用eMBErrorCodeeMBPoll(void)检测事件。

6)若发生串口接收中断,且eRcvState为STATE_RX_IDLE(4中已将eRcvState设为STATE_RX_IDLE),则向接收缓存中存入接收到的字符,同时将eRcvState设为STATE_RX_RCV状态,并清零超时定时器。

在下一个数据来到时,不断将数据存入接收缓存,并清零超时定时器。

7)如果没有接收完成,则不可能发生超时中断。

发生超时中断,说明T35时间内未收到新的串口数据,根据Modbus协议的规定,这指示着一帧请求数据接收完成。

在中断中,向协议栈发送消息EV_FRAME_RECEIVED(Framereceived),等待协议栈处理此消息。

8)主函数调用eMBErrorCodeeMBPoll(void)检测到事件EV_FRAME_RECEIVED后,调用staticpeMBFrameReceivepeMBFrameReceiveCur简单判断请求帧数据,并向协议栈发送消息EV_EXECUTE(Executefunction)。

9)主函数调用eMBErrorCodeeMBPoll(void)检测到事件EV_EXECUTE后,根据相应的请求代码查找处理该功能的函数指针来处理该功能。

若不是广播消息,则调用staticpeMBFrameSendpeMBFrameSendCur发送回复消息,在此函数中,只把要回复的数据复制到了串口缓存中,同时将eSndState设为STATE_TX_XMIT(Transmitterisintransferstate),并通过调用voidvMBPortSerialEnable(BOOLxRxEnable,BOOLxTxEnable)使能发送中断。

注意,发送中断使能后,由于串口发送寄存器本来就是空的,故在使能后将进入发送中断中。

10)发送中断中,且eSndState为STATE_TX_XMIT(9中已将eSndState设为STATE_TX_XMIT),则将串口缓存中的数据发送出去,同时不断对发送字符个数统计,当发送完成后,向协议栈发送消息EV_FRAME_SENT(Framesent)。

11)主函数调用eMBErrorCodeeMBPoll(void)检测到事件EV_FRAME_SENT后,不处理此消息。

12)当串口接收到数据后,协议栈将重复6-11处理消息。

五、一些理解

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

◆宏定义与变量

mbrtu.c文件中定义了RTU模式下的宏定义、全局变量与功能函数。

所包含的宏定义与全局变量定义如下:

/*-----------------------Defines------------------------------------------*/

#defineMB_SER_PDU_SIZE_MIN4/*!

#defineMB_SER_PDU_SIZE_MAX256/*!

#defineMB_SER_PDU_SIZE_CRC2/*!

#defineMB_SER_PDU_ADDR_OFF0/*!

#defineMB_SER_PDU_PDU_OFF1/*!

/*-----------------------Typedefinitions---------------------------------*/

typedefenum

{

STATE_RX_INIT,/*!

STATE_RX_IDLE,/*!

STATE_RX_RCV,/*!

STATE_RX_ERROR/*!

}eMBRcvState;

typedefenum

{

STATE_TX_IDLE,/*!

STATE_TX_XMIT/*!

}eMBSndState;

/*-----------------------Staticvariables---------------------------------*/

staticvolatileeMBSndStateeSndState;

staticvolatileeMBRcvStateeRcvState;

volatileUCHARucRTUBuf[MB_SER_PDU_SIZE_MAX];

staticvolatileUCHAR*pucSndBufferCur;

staticvolatileUSHORTusSndBufferCount;

staticvolatileUSHORTusRcvBufferPos;

首先在宏定义中,指明了该模式下所支持的最小请求帧长度为4(1字节地址+1字节命令+2字节校验),最大请求帧长度为256,CRC为两字节,地址为第一字节,PDU开始于第二字节。

在全局变量中,只定义了一个串口缓存数组ucRTUBuf[MB_SER_PDU_SIZE_MAX]。

由于发送与接收不是同步的,故可采用该缓存数组实现Modbus协议。

在接收过程中,将所接收到的数据直接存放于缓存ucRTUBuf中,在发送过程中,通过指针*pucSndBufferCur来访问该数组。

◆eMBErrorCodeeMBRTUInit(UCHARucSlaveAddress,UCHARucPort,ULONGulBaudRate,eMBParityeParity)

此函数为RTU模式的初始化函数。

此函数中判断串行口初始化是否成功(通过判断串行口初始化函数的返回值实现。

当然,查看返回值必然先调用该函数,从而完成端口初始化),如果成功,则根据波特率计算T35,初始化超时定时器。

◆voideMBRTUStart(void)

此函数为RTU模式开始函数。

函数主要功能是,将接收状态eRcvState设为STATE_RX_INIT(Receiverisininitialstate),使能接收同时关闭发送,使能超时定时器。

◆voideMBRTUStop(void)

此函数为RTU模式终止函数。

函数主要功能是,关闭接收与发送,关闭超时定时器。

◆eMBErrorCodeeMBRTUReceive(UCHAR*pucRcvAddress,UCHAR**pucFrame,USHORT*pusLength)

此函数为RTU接收数据帧信息提取函数。

函数主要功能是,将接收帧(存放于缓存)的地址指针赋给指针变量pucRcvAddress,将PDU编码首地址赋给指针*pucFrame,将PDU长度地址赋给指针变量pusLength。

使用指针访问缓存数组,而不是额外开辟缓存存放帧信息,大大减少了内存的开支。

◆eMBErrorCodeeMBRTUSend(UCHARucSlaveAddress,constUCHAR*pucFrame,USHORTusLength)

此函数为RTU回复帧信息组织函数。

函数的功能是,此函数

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 工程科技 > 能源化工

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1