49 /* ----------------------- MBAP Header --------------------------------------*/
50 /*
51 *
52 * <------------------------ MODBUS TCP/IP ADU(1) ------------------------->
53 * <----------- MODBUS PDU (1') ---------------->
54 * +-----------+---------------+------------------------------------------+
55 * | TID | PID | Length | UID |Code | Data |
56 * +-----------+---------------+------------------------------------------+
57 * | | | | |
58 * (2) (3) (4) (5) (6)
59 *
60 * (2) ... MB_TCP_TID = 0 (Transaction Identifier - 2 Byte)
61 * (3) ... MB_TCP_PID = 2 (Protocol Identifier - 2 Byte)
62 * (4) ... MB_TCP_LEN = 4 (Number of bytes - 2 Byte)
63 * (5) ... MB_TCP_UID = 6 (Unit Identifier - 1 Byte)
64 * (6) ... MB_TCP_FUNC = 7 (Modbus Function Code)
65 *
66 * (1) ... Modbus TCP/IP Application Data Unit
67 * (1') ... Modbus Protocol Data Unit
68 */
69
70 #define MB_TCP_TID 0
71 #define MB_TCP_PID 2
72 #define MB_TCP_LEN 4
73 #define MB_TCP_UID 6
74 #define MB_TCP_FUNC 7
75
76 #define MB_TCP_PROTOCOL_ID 0 /* 0 = Modbus Protocol */
表1 ModBus功能码
功能码 名称 作用
01 读取线圈状态 取得一组逻辑线圈的当前状态(ON/OFF)
02 读取输入状态 取得一组开关输入的当前状态(ON/OFF) only read
功能码01、02读到的位满8个组合成一个字节,可以用功能04读取
03 读取保持寄存器 在一个或多个保持寄存器中取得当前的二进制值 保持寄存器,设置的各种参数3xxxx
04 读取输入寄存器 在一个或多个输入寄存器中取得当前的二进制值 输入寄存器,实时数据 4xxxx only read
05 强置单线圈 强置一个逻辑线圈的通断状态
06 预置单寄存器 把具体二进值装入一个保持寄存器
07 读取异常状态 取得8个内部线圈的通断状态,这8个线圈的地址由控制器决定,用户逻辑可以将这些线圈定义,以说明从机状态,短报文适宜于迅速读取状态
08 回送诊断校验 把诊断校验报文送从机,以对通信处理进行评鉴
09 编程(只用于484) 使主机模拟编程器作用,修改PC从机逻辑
10 控询(只用于484) 可使主机与一台正在执行长程序任务从机通信,探询该从机是否已完成其操作任务,仅在含有功能码9的报文发送后,本功能码才发送
11 读取事件计数 可使主机发出单询问,并随即判定操作是否成功,尤其是该命令或其他应答产生通信错误时
12 读取通信事件记录 可是主机检索每台从机的ModBus事务处理通信事件记录。如果某项事务处理完成,记录会给出有关错误
13 编程(184/384 484 584) 可使主机模拟编程器功能修改PC从机逻辑
14 探询(184/384 484 584) 可使主机与正在执行任务的从机通信,定期控询该从机是否已完成其程序操作,仅在含有功能13的报文发送后,本功能码才得发送
15 强置多线圈 强置一串连续逻辑线圈的通断
16 预置多寄存器 把具体的二进制值装入一串连续的保持寄存器
17 报告从机标识 可使主机判断编址从机的类型及该从机运行指示灯的状态
18 (884和MICRO 84) 可使主机模拟编程功能,修改PC状态逻辑
19 重置通信链路 发生非可修改错误后,是从机复位于已知状态,可重置顺序字节
20 读取通用参数(584L) 显示扩展存储器文件中的数据信息
21 写入通用参数(584L) 把通用参数写入扩展存储文件,或修改之
22~64 保留作扩展功能备用
65~72 保留以备用户功能所用 留作用户功能的扩展编码
73~119 非法功能
120~127 保留 留作内部作用
128~255 保留 用于异常应答
表2 ModBus功能码与数据类型对应表
代码 功能 数据类型
01 读 位
02 读 位
03 读 word(16bit)
04 读 word(16bit)
05 写 位
06 写 整型、字符型、状态字、浮点型
08 N/A 重复“回路反馈”信息
15 写 位
16 写 整型、字符型、状态字、浮点型
常用Modbus寄存器有:线圈(Coil)、输入(Input)、保持寄存器(Holding Registers)和输入寄存器(Input Registers)。
从Modbus设备角度看,输入是上位机采集Modbus设备的信息,也就是这些寄存器是只读的,所以,Modbus协议没有写输入(Input)和输入寄存器(Input Registers)的命令。
线圈(Coil)是状态量,对应Modbus设备的开关量输出(DO),保持寄存器(Holding Registers)是模拟量,对应Modbus设备模拟量输出(AO),这些寄存器需要Modbus设备的上位机进行设置,也就是为可以写的寄存器。
在Modicon_Modbus协议 协议中,写线圈(Coil)和保持寄存器(Holding Registers)都有两种写命令:
1)、写单个寄存器:
置单线圈(Force Single Coil)功能码05(0x05)
写单个寄存器(Preset Single Holding Register)功能码06(0x06)
------------------------------------------------------------------------------
2)、写多个寄存器
写多线圈(Force Multiple Coils)功能码15(0x0F)
写多个寄存器(Preset Multiple Registers)功能码16(0x10)
MODbus数据帧格式:
modbus信息嵌入在LLC层数据帧,HDLC(数据链路控制层)进行CRC校验
MODBUS包含四种寄存器:
1.线圈
2.输入点
3.保持寄存器
4.输入寄存器
其中输入点和输入寄存器为只读
MODBUS常用功能码:
===========================================================================
---------------------------------------------------------------------------
0X线圈操作:01 05 15
01 读线圈状态
读从机离散量输出口的开关状态。
例:读从设备线圈地址为00020(modbus地址0x0013)的37个线圈,即00020-00056
查询:查询时需要指定起始线圈和线圈量,以最地位开始绕线圈,最高位不足补零。
[0 - 1][2 - 3][4 - 5] [6] [7] [8 - 9] [10 - 11]
TID PID 长度 ID func start_addr data
[00][04][00][00][00][06][FF][01][00][13][00][25]
注意:modbus协议和PLC之间,modbus线圈地址从0开始,设备地址从1开始,其他寄存器也是这种关系。
响应:
<00><04><00><00><00><08><FF><01><05><CD><6B><B2><0E><1B>
那么线圈00020-00056的状态为:
coils:
27-20: 1100 1101
35-28: 0110 1011
43-36: 1011 0010
51-44: 0000 1110
56-52: 0001 1011 (高位补零)
数据长度<05>= (线圈数 + 7)/8=5
在libmodbus测试代码中unit-test.h,定义了如下的地址信息:
31 const uint16_t UT_BITS_ADDRESS = 0x13;
32 const uint16_t UT_BITS_NB_POINTS = 0x25;
33 const uint8_t UT_BITS_TAB[] = { 0xCD, 0x6B, 0xB2, 0x0E, 0x1B };
在分析libmodbus时,看到这几个测试地址和值想不明白为什么是这几个数,看了modicon关于MODBUS协议的定义,原来这几个地址和值,是它协议(设备M84984...)上面的例子。
--------------------------------------------------------------------------
05强制单个线圈
强制单个线圈的状态的状态,可以广播地址,使所有从机同一线圈同为1或0
以请求数据的数据区规定请求线圈的开关状态
0xFF00 ON
0x0000 OFF
例:强制从机设备(广播)中00020(0x0013)线圈为ON
请求:
[00][01][00][00][00][06][FF][05][00][13][FF][00]
查询:
<00><01><00><00><00><06><FF><05><00><13><FF><00>
-------------------------------------------------------------------------
15强制多个线圈
按线圈的顺序把各线圈强制成ON/OFF,支持广播
例:强制将设备起始线圈位00020的37个线圈强制,数据中1位代表一个线圈状态,1为ON
查询:
[00][03][00][00][00][0C][FF][0F][00][13][00][25][05][CD][6B][B2][0E][1B]
响应:
<00><03><00><00><00><06><FF><0F><00><13><00><25>
以上是3种线圈操作,包括读单/多组线圈(1),强制单个线圈(5),强制多个线圈(15)
---------------------------------------------------------------------------
===========================================================================
===========================================================================
---------------------------------------------------------------------------
4X保持寄存器功能码:03 06 16
03 读保持寄存器:
保持寄存器一般做内存存储和模拟量输出,不支持广播,查询信息包含了寄存器起始地址和数量
例:读寄存器起始地址是40108(0x006B)的一个寄存器,40108寄存器对应MODBUS协议中0x006B地址
查询:
[00][07][00][00][00][06][FF][03][00][6B][00][01]
响应:
<00><07><00><00><00><05><FF><03><02><12><34>
以上表示寄存器40108的数据为0x1234两个byte。一个寄存器是16位(2B)。
-----------------------------------------------------------------------
06 置单个保持寄存器
把一个值预置到一个4X类型保持寄存器中,支持广播
查询:
查询信息包含寄存器起始地址。
例:请求把从机寄存器40108(0x406B)预置为0x1234
[00][06][00][00][00][06][FF][06][00][6B][12][34]
响应:寄存器内容被预置后返回正常响应,
<00><06><00><00><00><06><FF><06><00><6B><12><34>
----------------------------------------------------------------------
16 预置多个寄存器
把数据按顺序预制到4X类型保持寄存器,支持广播
例:请求预置40108(0x006B)寄存器为起始地址的3个寄存器依次置为0x0602,0x0b,0x0064.
查询:40108-40109-40110(每个寄存器2B)
[00][08][00][00][00][0D][FF][10][00][6B][00][03][06][02][2B][00][00][00][64]
字段说明:
FF --广播地址
10 --功能码
006B -- 寄存器地址
0003 -- 寄存器数量
06 -- 数据字节数
后面6个自己为数据
响应:
<00><08><00><00><00><06><FF><10><00><6B><00><03>
正常响应从机地址功能码,预置寄存器起始地址和数量
------------------------------------------------------------------------
========================================================================
=========================================================================
-------------------------------------------------------------------------
1X输入位状态操作 02 只读
02读输入状态
读从机离散量输入状态,不支持广播
例:请求读从机设备地址为10197(0x00C4)开始的22(0x16)个输入状态
请求:
[00][05][00][00][00][06][FF][02][00][C4][00][16]
响应:
<00><05><00><00><00><06><FF><02><03><AC><DB><35>
<03> -- 字节数=(输入量 + 7)/8 =29/8
响应数据位每位表示一个输入状态,从最低位开始,最高位填零
这个寄存器通常作为,开关量的输入寄存器,只可读不可写,输入对于主站而言。
-------------------------------------------------------------------------
=========================================================================
=========================================================================
-------------------------------------------------------------------------
3X输入寄存器操作 04 只读
04读输入寄存器,读取从机3X类型输入寄存器的而数据,不支持广播
例:请求读从机的30009寄存器
查询:查询信息规定了要读的寄存器起始地址和数量
[00][0D][00][00][00][06][FF][04][00][08][00][01]
响应:
<00><0D><00><00><00><05><FF><04><02><00><0A>
========================================================================
以上是MODBUS TCP中最最常用的功能码操作


6971

被折叠的 条评论
为什么被折叠?



