modbus rtu通信协议串口通讯.docx
《modbus rtu通信协议串口通讯.docx》由会员分享,可在线阅读,更多相关《modbus rtu通信协议串口通讯.docx(32页珍藏版)》请在冰豆网上搜索。
modbusrtu通信协议串口通讯
modbus rtu通信协议串口通讯动态链接库DLL(以下简称DLL),是为满足工业通信需要,
针对工业领域要求上位机对PLC、工业仪表通讯实时采集与控制的组态编程而设计。
本DLL是采用Delphi语言开发的标准串口通讯库,具有以下特点:
1)、遵循modbus rtu串口通讯协议(施耐德、西门子、台达、永宏等品牌PLC及各类工业仪表等支持本协议);
2)、实时性、可靠性好,通用性强;
3)、适用于多PLC联网和上位机通信,满足多方面的需要(联网时可采用485总线式);
4)、函数接口功能全,操作简单,支持modbus的大部分读写功能函数;
5)、附加实用转换与读取函数,易于快速开发(VC等非RAD开发环境的开发);
6)、支持USB、PC扩展卡等扩展串口号;
7)、支持多种操作系统win9x/win2000/winXP(标注Win32 DLL);
8)、可在多种编程环境下使用,例如VB、VC、Delphi等开发环境。
9)、支持modbus rtu标准的功能代码01、02、03、04、05、06、15、16且对相关功能代码的读取和写如做了一些扩充更加符合工业自动化领域的工控软件的开发,是广大工控工程师的必备工具软件。
二、modbus rtu通讯协议简介
Modbus 协议是应用于电子控制器上的一种通用语言。
通过此协议,控制器相互之间、控制器经由网络(例如以太网)
和其它设备之间可以通信。
它已经成为一通用工业标准。
有了它,不同厂商生产的控制设备可以连成工业网络,进行集
中监控。
此协议定义了一个控制器能认识使用的消息结构,而不管它们是经过何种网络进行通信的。
它描述了一控制器请
求访问其它设备的过程,如果回应来自其它设备的请求,以及怎样侦测错误并记录。
它制定了消息域格局和内容的公共
格式。
当在一Modbus网络上通信时,此协议决定了每个控制器须要知道它们的设备地址,识别按地址发来的消息,决定
要产生何种行动。
如果需要回应,控制器将生成反馈信息并用Modbus协议发出。
在其它网络上,包含了Modbus协议的消
息转换为在此网络上使用的帧或包结构。
这种转换也扩展了根据具体的网络解决节地址、路由路径及错误检测的方法。
1、在Modbus网络上转输
标准的Modbus口是使用一RS-232C兼容串行接口,它定义了连接口的针脚、电缆、信号位、传输波特率、奇偶校验。
控制
器能直接或经由Modem组网。
控制器通信使用主—从技术,即仅一设备(主设备)能初始化传输(查询)。
其它设备(从设备)
根据主设备查询提供的数据作出相应反应。
典型的主设备:
主机和可编程仪表。
典型的从设备:
可编程控制器。
主设备
可单独和从设备通信,也能以广播方式和所有从设备通信。
如果单独通信,从设备返回一消息作为回应,如果是以广播
方式查询的,则不作任何回应。
Modbus协议建立了主设备查询的格式:
设备(或广播)地址、功能代码、所有要发送的数
据、一错误检测域。
从设备回应消息也由Modbus协议构成,包括确认要行动的域、任何要返回的数据、和一错误检测域。
如果在消息接收过程中发生一错误,或从设备不能执行其命令,从设备将建立一错误消息并把它作为回应发送出去。
2、在其它类型网络上转输
在其它网络上,控制器使用对等技术通信,故任何控制都能初始和其它控制器的通信。
这样在单独的通信过程中,控制
器既可作为主设备也可作为从设备。
提供的多个内部通道可允许同时发生的传输进程。
在消息位,Modbus协议仍提供了
主—从原则,尽管网络通信方法是“对等”。
如果一控制器发送一消息,它只是作为主设备,并期望从从设备得到回应。
同样,当控制器接收到一消息,它将建立一从设备回应格式并返回给发送的控制器。
3、查询—回应周期
(1)、查询
查询消息中的功能代码告之被选中的从设备要执行何种功能。
数据段包含了从设备要执行功能的任何附加信息。
例
如功能代码03是要求从设备读保持寄存器并返回它们的内容。
数据段必须包含要告之从设备的信息:
从何寄存器开始读
及要读的寄存器数量。
错误检测域为从设备提供了一种验证消息内容是否正确的方法。
(2)、回应
如果从设备产生一正常的回应,在回应消息中的功能代码是在查询消息中的功能代码的回应。
数据段包括了从设备
收集的数据:
象寄存器值或状态。
如果有错误发生,功能代码将被修改以用于指出回应消息是错误的,同时数据段包含
了描述此错误信息的代码。
错误检测域允许主设备确认消息内容是否可用。
3、两种传输方式
控制器能设置为两种传输模式(ASCII或RTU)中的任何一种在标准的Modbus网络通信。
用户选择想要的模式,包括串
口通信参数(波特率、校验方式等),在配置每个控制器的时候,在一个Modbus网络上的所有设备都必须选择相同的传输
模式和串口参数。
ASCII模式
-------------------------------------------
| 地址 | 功能代码 | 数据数量 | 数据1 ... 数据n | LRC高字节 | LRC低字节 | 回车 | 换行 |
-------------------------------------------
RTU模式
------------------------------------
| 地址 | 功能代码 | 数据数量 | 数据1 ... 数据n | CRC高字节 | CRC低字节 |
------------------------------------
所选的ASCII或RTU方式仅适用于标准的Modbus网络,它定义了在这些网络上连续传输的消息段的每一位,以及决定
怎样将信息打包成消息域和如何解码。
在其它网络上(象MAP和Modbus Plus)Modbus消息被转成与串行传输无关的帧。
因ASCII模式通讯效率较低一多采用RTU模式,这里只对RTU模式进行详细介绍。
4、Modbus RTU模式
当控制器设为在Modbus网络上以RTU(远程终端单元)模式通信,在消息中的每个8Bit字节包含两个4Bit的十六进制
字符。
这种方式的主要优点是:
在同样的波特率下,可比ASCII方式传送更多的数据。
代码系统
8位二进制,十六进制数0...9,A...F
消息中的每个8位域都是一个两个十六进制字符组成
每个字节的位
1个起始位
8个数据位,最小的有效位先发送
1个奇偶校验位,无校验则无
1个停止位(有校验时),2个Bit(无校验时)
错误检测域
CRC(循环冗长检测)
地址域
消息帧的地址域包含8Bit(RTU)。
可能的从设备地址是0...247(十进制)。
单个设备的地址范围是1...247。
主设备通过
将要联络的从设备的地址放入消息中的地址域来选通从设备。
当从设备发送回应消息时,它把自己的地址放入回应的地址域
中,以便主设备知道是哪一个设备作出回应。
地址0是用作广播地址,以使所有的从设备都能认识。
当Modbus协议用于更高
水准的网络,广播可能不允许或以其它方式代替。
如何处理功能域
数据域是由两个十六进制数集合构成的,范围00...FF。
根据网络传输模式,这可以是由一RTU字符组成。
从主设备发给
从设备消息的数据域包含附加的信息:
从设备必须用于进行执行由功能代码所定义的所为。
这包括了象不连续的寄存器地址,
要处理项的数目,域中实际数据字节数。
例如,如果主设备需要从设备读取一组保持寄存器(功能代码03),数据域指定了起
始寄存器以及要读的寄存器数量。
如果主设备写一组从设备的寄存器(功能代码10十六进制),数据域则指明了要写的起始寄
存器以及要写的寄存器数量,数据域的数据字节数,要写入寄存器的数据。
如果没有错误发生,从从设备返回的数据域包含
请求的数据。
如果有错误发生,此域包含一异议代码,主设备应用程序可以用来判断采取下一步行动。
在某种消息中数据域
可以是不存在的(0长度)。
例如,主设备要求从设备回应通信事件记录(功能代码0B十六进制),从设备不需任何附加的信息。
三、DLL函数说明
modbus.DLL是王俊于2007年最新开发的基于施耐得modbus rtu 通讯协议的串口通讯链接库。
modbus.DLL专业版实现了对保持寄存器40001~4XXXX区数据读写(FCN03:
读、FCN16:
写,FCN06写单个数据);对逻辑线圈00001~0XXXX的 读写(FCN01:
读取一组线圈,FCN05:
强置单线圈,FCN15强置多线圈);对输入状态10001~1XXXX的读(FCN02);对输入寄存器30001~3XXXX的读(FCN04)。
DLL中的主要函数:
ComOpen:
打开串口
ComClose:
关闭串口
FCN01:
读取一组线圈(00001~0XXXX)
FCN02:
取得一组开关输入状态数据(10001~1XXXX)
FCN03:
读多个保持寄存器数据(40001~4XXXX)
FCN04:
读多个输入寄存器数据(30001~3XXXX)
FCN05S:
置位单线圈(00001~0XXXX)
FCN05R:
复位单线圈(00001~0XXXX)
FCN06:
预置单保持寄存器数据(40001~4XXXX)
FCN15:
强置多线圈的通断数据(00001~0XXXX)
FCN16:
写多个保持寄存器数据(40001~4XXXX)
FCN16_xSet:
单保持寄存器的0~15相应位的置位(40001.0-40001.15~4XXXX.0-4XXXX.15)
FCN16_xReset:
单保持寄存器的0~15相应位的复位(40001.0-40001.15~4XXXX.0-4XXXX.15)
FCN16_xSetReset:
单保持寄存器的0~15相应位的置复位(40001.0-40001.15~4XXXX.0-4XXXX.15),
指使相应的位短时间通断一次(约通60ms)
ComTrue:
读取DLL中的串口是否备有效打开
CinBin:
字中相应的位的状态抽取
1、打开串口
Function ComOpen(nport,BaudRate,DataBits,Parity,StopBits:
longint;User:
Pchar):
longint;stdcall;
参数:
nport:
打开串口号,取值为1~8,代表COM1~COM8;
BaudRate:
波特率,取值为:
1200、2400、4800、9600、19200、38400;
DataBits:
数据位,取值为5、6、7、8;
Parity:
校验位,取值1(代表Even)、取值2(代表Odd)、取值3(代表Mark)、取值4(代表Space)、取值5(代表None);
StopBits:
停止位,取值1(代表1位停止位)、取值2(代表2位停止位)、取值3(代表1.5位停止位);
User:
DLL授权用户名;
返回值:
长整型,操作成功返回“1”或“2”;1表示注册授权用户,2表示用户未注册;
操作不成功返回为“0”时的原因:
1)、串口不存在或被占用; 2)、DLL注册授权不正确。
注:
本DLL用户不注册除了下面说明的功能限制外没有其他限制,未注册用户请使用特定用户名:
wangjun。
注册用户功能上无任何限制,且将得到永久的软件使用和更新升级服务;
使用举例:
Delphi:
ComOpen(1,9600,8,1,1,Pchar('wangjun')) , 打开COM1口。
VB:
ComOpen(1,9600,8,1,1,"wangjun") , 打开COM1口。
(注:
下面的示例都以VB调用形式给出)
2、关闭串口
Function ComClose(nport:
longint):
longint;stdcall;
参数:
nport:
串口号,取值为1~8,代表COM1~COM8;
返回值:
长整型,操作成功返回“1”,否则返回“0”;
使用举例:
ComClose
(1) ,关闭打开的COM1口。
3、modbus相应功能码所对应的读取功能函数。
1)、01功能码位元件的读取(读取一组线圈)
Function FCN01(nport,node,address,Count:
longint):
Pchar;stdcall;
参数:
nport:
串口号,取值为1~8,代表COM1~COM8;
node:
modbus从站号,取值1~255;
address:
元件地址,取值范围从00001~0XXXX地址区(逻辑线圈)值(你要读标准modbus的00001地址这个值为0000,依次类推)
Count:
读取的位元件个数,一次最多读取1000个但不能超出寻址范围;
返回值:
16进制字符串数据,字符串数据的终止符为"@";
使用举例:
FCN01(1,1,19,37),由COM1读取modbus 1号从站00020~00056(标准modbus地址)的位状态值,返回值为“CD6BB20E1B@”
则表示27~20:
CD, 35~28:
6B, 43~36:
B2, 51~44:
0E, 56~52:
1B;
字节值与实际的位状态值对应参考(其他位功能函数的说明不再重复本内容):
位地址:
| 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 35 | 34 | 33 | 32 | 31 | 30 | 29 | 28 |
-----------------------------------------
各位赋值:
| 1 | 1 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | 1 | 1 | 0 | 1 | 0 | 1 | 1 |
-----------------------------------------
16进制串:
| C | D | 6 | B |
-----------------------------------------
不足8位的位组的状态值参考:
位地址:
| 56 | 55 | 54 | 53 | 52 |
-------------
各位赋值:
| 0 | 1 | 0 | 1 | 1 |
-------------
16进制串:
| 1 | B |
-------------
在读取错误或不能读取的情况下返回“Error@”
注:
没有注册的用户只能读取00001~00006范围的状态值;
2)、02功能码位元件的读取(取得一组开关输入状态数据)
Function FCN02(nport,node,address,Count:
longint):
Pchar;stdcall;
参数:
nport:
串口号,取值为1~8,代表COM1~COM8;
node:
modbus从站号,取值1~255;
address:
元件地址,取值范围从10001~1XXXX地址区(开关输入状态)值(你要读标准modbus的10001地址这个值为0000,依次类推)
Count:
读取的位元件个数,一次最多读取1000个但不能超出寻址范围;
返回值:
16进制字符串数据,字符串数据的终止符为"@";
使用举例:
FCN02(1,1,196,22),由COM1读取modbus 1号从站10197~10218(标准modbus地址)的位状态值,返回值为“ACDB35@”
则表示10204~10197:
AC, 10212~10205:
DB, 10218~10213:
35;
在读取错误或不能读取的情况下返回“Error@”
注:
没有注册的用户只能读取10001~10006范围的状态值;
3)、03功能码字元件的读取(读多个保持寄存器数据)
Function FCN03(nport,node,address,Count:
longint):
Pchar;stdcall;
参数:
nport:
串口号,取值为1~8,代表COM1~COM8;
node:
modbus从站号,取值1~255;
address:
元件地址,取值范围从40001~4XXXX地址区(保持寄存器数据)值(你要读标准modbus的40001地址这个值为0000,依次类推)
Count:
读取的位元件个数,一次最多读取60个但不能超出寻址范围;
返回值:
16进制字符串数据,字符串数据的终止符为"@";
使用举例:
FCN03(1,1,107,3),由COM1读取modbus 1号从站40108~40110(标准modbus地址)的字状态值,返回值为“022B00000064@”
则表示40108:
022B, 40109:
0000, 40110:
0064;
在读取错误或不能读取的情况下返回“Error@”
注:
没有注册的用户只能读取40001~40003范围的状态值;
4)、04功能码字元件的读取(读多个输入寄存器数据)
Function FCN04(nport,node,address,Count:
longint):
Pchar;stdcall;
参数:
nport:
串口号,取值为1~8,代表COM1~COM8;
node:
modbus从站号,取值1~255;
address:
元件地址,取值范围从30001~3XXXX地址区(输入寄存器数据)值(你要读标准modbus的30001地址这个值为0000,依次类推)
Count:
读取的位元件个数,一次最多读取60个但不能超出寻址范围;
返回值:
16进制字符串数据,字符串数据的终止符为"@";
使用举例:
FCN04(1,17,8,1),由COM1读取modbus 17号从站30009(标准modbus地址)的字状态值,返回值为“000A@”
则表示30009:
000A;
在读取错误或不能读取的情况下返回“Error@”
注:
没有注册的用户只能读取30001~30003范围的状态值;
4、modbus相应功能码所对应的写入功能函数
1)、05功能码线圈的置复位功能函数
1、线圈置位
Function FCN05S(nport,node,address:
longint):
longint;stdcall;
参数:
nport:
串口号,取值为1~8,代表COM1~COM8;
node:
modbus从站号,取值1~255;
address:
元件地址,取值范围从00001~0XXXX地址区(逻辑线圈)值(你要写标准modbus的00001地址这个值为0000,依次类推)
返回值:
长整数,操作成功返回1,不能写入或操作错误返回0;
使用举例:
FCN05S(1,12,15),由COM1将modbus 12号从站00013(标准modbus地址)的位状态值置1,返回值为1表示成功
注:
没有注册的用户只能写入00001~00006范围的状态值;
2、线圈复位
Function FCN05R(nport,node,address:
longint):
longint;stdcall;
参数:
nport:
串口号,取值为1~8,代表COM1~COM8;
node:
modbus从站号,取值1~255;
address:
元件地址,取值范围从00001~0XXXX地址区(逻辑线圈)值(你要写标准modbus的00001地址这个值为0000,依次类推)
返回值:
长整数,操作成功返回1,不能写入或操作错误返回0;
使用举例:
FCN05R(1,12,15),由COM1将modbus 12号从站00013(标准modbus地址)的位状态值置0,返回值为1表示成功
注:
没有注册的用户只能写入00001~00006范围的状态值;
2)、06功能码预置单保持寄存器数据功能函数
Function FCN06(nport,node,address:
longint;Sendstr:
pchar):
longint;stdcall;
参数:
nport:
串口号,取值为1~8,代表COM1~COM8;
node:
modbus从站号,取值1~255;
address:
元件地址,取值范围从40001~4XXXX地址区(保持寄存器)值(你要写标准modbus的40001地址这个值为0000,依次类推)
Sendstr:
写入字值,该值为4个一组的16进制字符串组成其取值为0000~FFFF(整数值为0~65535);
返回值:
长整数,操作成功返回1,不能写入或操作错误返回0;
当要写入字值时依次排列即可。
如给40001写值1000,先将1000转成16进制字符串03E8,则sendstr=03E8;
使用举例:
FCN06(1,2,2,"03E8"),由COM1给modbus 2号从站40003(标准modbus地址)的字单元写入1000(16进制03E8),返回值为1表示成功
注:
没有注册的用户只能写入40001~40003范围的状态值;
(00001~0XXXX)
3)、15功能码强置多线圈的通断数据功能函数
Function FCN15(nport,node,address,Count:
longint;Sendstr:
pchar):
longint;stdcall;
参数:
nport:
串口号,取值为1~8,代表COM1~COM8;
node:
modbus从站号,取值1~255;
address:
元件地址,取值范围从00001~0XXXX地址区(逻辑线圈)值(你要写标准modbus的00001地址这个值为0000,依次类推)
Count:
写入位元件个数,一次最多1000个但不能超出寻址范围;
Sendstr:
给位元件写入的值按8个为一组和成字节值在写入,该值为2个一组的16进制字符串组其取值为00~FF(整数值为0~255);
返回值:
长整数,操作成功返回1,不能写入或操作错误返回0;
---------- - ~ - ------
写字符串序列如:
| 00 | FF | 10 | 64 | ~ | 08 | 04 |
---------- - ~ - ------
实际字符串与位地址的数值应如下表:
位地址:
| 40 | 39 | 38 | 36 | 35 | 34 | 33 | 32 | 48 | 47 | 46 | 45 | 44 | 43 | 42 | 41 |
-----------------------------------------
各