modbus协议是一种应用层的报文传输协议; RTU,ASCII,TCP
以下内容以modbus RTU通信协议为例说明;
01-存储区
存储区:输出线圈,输入线圈,输出寄存器,输入寄存器 (其实就只有输入,输出,线圈,寄存器)
输入:就是只读(read only),不能写的,一般用来保存结果或者保存状态; 输出: 那线圈和寄存器怎么理解? ? ? 可以说我这个存储区的最小单位是寄存器, ? ? 或者说我这个存储区的最小单位是线圈;
? ??至于为啥叫线圈,这个可能跟物理上有关系,做硬件的那些人应该懂; ? ? 线圈:就表示一个boolean量,要么得电,要么失电;
? ??所以我们用线圈来表示boolean 量;
? ??如果我的存储区用线圈存储区,就表示我的最小单位是布尔;
怎么理解存储区? ?? ?就是我们电脑里面会有内存, ?? ?这种控制器最底层也是有cpu,或者存储的一个东西, ?? ?
? ? 如果是输入存储区: ?? ?或者说输入线圈,或者输出线圈,这里的最小单位是一个bool;就是存一个1或者0;? ??
? ? 那如果是寄存器存储区呢?这一个内存就会占16位,因为它的最小单位是寄存器, ?? ??? ?一个寄存器等于16个位;
?? ?那么就容易理解了: ?? ??? ?线圈和寄存器表示的就是最小单位;
其中线圈=布尔(bit),寄存器=16位=16个bit(2个字节) 或者说你要存布尔,你就用线圈存储区, 你要存数据,就用寄存器存储区; 这样可以做一个区分;
1字节(byte) = 8位(bit) 1个字节是8位,就是二进制8位
02-存储区范围
存储区范围:5位和6位,也叫标准地址和扩展地址
任何一个存储区都是有范围的,不存在无限的;
5位还不能全部来表示地址, 比如说: ?? ?Y XXXX: ?? ?其中第一位 Y 表示哪个存储区;
?? ?就是它会给每个存储区来个代号; ?? ?比如说输入线圈存储区是0,你可以通过这个代号知道是哪个存储区;
输出线圈 0
输入线圈 1
输出寄存器 4
输入寄存器 3
?? ?那除了这个代号,后面还有四个XXXX, ?? ?那这个最大就是9999
也就是说输出线圈的最大为09999,输入线圈的最大为19999,这样 那最小值呢?
也就是存储区的范围: 输出线圈 0 00001-09999
输入线圈 1 10001-19999
输出寄存器 4 40001-49999
输入寄存器 3 30001-39999
这样的话,给我这个地址,我就知道第一位是哪个存储区,通过后面四个位数就能知道是第多少个寄存器或者第多少个线圈;
地址:Y XXXX
但是上面这个是5位,也叫标准地址;
有些设备支持6位,也就是 Y XXXXXX, 也就是可以按照5位的规律? ?? ?输出线圈 0 ?? ?00001-09999 ?? ?000001-099999
?? ?输入线圈 1 ?? ?10001-19999 ?? ?100001-199999
?? ?输出寄存器 4 ?? ?40001-49999 ?? ?400001-499999
?? ?输入寄存器 3 ?? ?30001-39999 ?? ?300001-399999
但是其实不是这样算的, 6位最大是: ?? ?输出线圈 0 ?? ?00001-09999 ?? ?000001-065536
?? ?输入线圈 1 ?? ?10001-19999 ?? ?100001-165536
?? ?输出寄存器 4 ?? ?40001-49999 ?? ?400001-465536
?? ?输入寄存器 3 ?? ?30001-39999 ?? ?300001-365536
现在随便给一个地址就知道是什么了?????比如: 36543,03321,10894
03-通信
现在有上面那么多的存储区,我想跟他们通信,那就有很多操作;
操作其实就是 ?? ?读和写;
但是我存储区有这么四个: ?? ?输出线圈 ?? ?输入线圈 ?? ?输出寄存器 ?? ?输入寄存器 那么总共可以组合为多少种操作呢?
读的话: ? ? 读输出线圈 ? ? 读输入线圈 ? ? 读输出寄存器 ? ? 读输入寄存器
写: ? ? 写输出线圈 ? ? 写输出寄存器 ?
那就至少有6种动作,也叫功能; 但是可以给每个功能来一个代号,叫做功能码。 (存储区有代码,每个功能也有代号-叫功能码)
读输出线圈 01 读输入线圈 02 读输出寄存器 03 读输入寄存器 04
写输出线圈 05 写输出寄存器 06
(为啥要用代号呢?因为我不能做每个功能是一串汉语或者英文) (就是在计算机里面都会把它简化)
其实协议里面并不是这么简单,会把它进行区分, 比如它写入的时候会进行一个功能性的区分叫: ?? ?写单 或者 写多
写单个输出线圈 05 写单个输出寄存器 06
写多个输出线圈 15 写多个输出寄存器 16
这里的数字都是10进制,可能其他人的笔记这里是16进制,都行。 16进制:(前缀是0x) ?? ?对于小于10的,跟10进制都是一样的 ?? ?大于10的,比如15就是0x0f;
上面就是modubs的功能码;
04-协议
协议就是规定了一种格式, modbus RTU/ASCII
报文格式:从站地址(设备编号)+ 功能码(就是上面那个东西)+ 数据 + 校验
对于读取来说: ?? ?从站地址(设备编号):是为了区分设备(找谁?) ?? ?功能码:是为了做什么功能,干什么(干嘛?) ?? ?数据:具体做什么细节(具体干嘛的细节?) ?? ?校验:验证(验证)
对于写入来说: ?? ?从站地址(设备编号):找谁? ?? ?功能码:干嘛? ?? ?数据:具体干嘛的细节(比读取更多,多了个写入的具体数值) ?? ?校验:验证
从站地址(设备编号):1byte 功能码:1byte 数据:n个byte 校验:2个byte
1字节(byte) = 8位(bit) 1个字节是8位,二进制8位
比如:请求的一个报文如下(16进制的) ?? ?01 03 00 00 00 02 C4 0B
?? ?01 站地址 ?? ?03 读输出寄存器 ?? ?00 00 起始寄存器? ?? ?00 02 寄存器长度 ?? ?C4 0B CRC校验
?? ?这个报文的意思就是要去读站地址1,的输出寄存器,从0开始去读,读两个;
那相应报文如过是这个: ?? ?01 03 04 01 46 01 3B 5A 59
?? ?01 站地址 ?? ?03 读输出寄存器 ?? ?04 字节计数(就是返回了多少个字节)? ?? ?01 46 01 3B 具体的4个字节 ?? ?5A 59 CRC校验
注意: ?? ?如过写不进去怎么办? ?? ?或者说我发了东西它不回?
?? ?那肯定就是我发的不对,它没法回;
其他问题---
问题1: 地址说明:
一般业务方给的或者说明书的modbus地址如下: ?? ?400001 ?? ?400002
这个地址是唯一的,绝对的;
但是我协议的地址是:就是通信报文中的地址都是相对地址, ?? ?相对地址就是从0开始的; ?? ?所以就有一种说法是: ?? ??? ?对于输出寄存器来说:0对应的是400001,0-400001 ?? ??? ?那对于输入寄存器来说:1对应的是300001,0-300001
?? ??? ?对于输出线圈来说,0对应的是000001 ?? ??? ?对于输入线圈来说,0对应的是100001
?? ??? ??? ?输出线圈 0
?? ??? ??? ?输入线圈 1
?? ??? ??? ?输出寄存器 4
?? ??? ??? ?输入寄存器 3
?? ??? ??? ?怎么快速记这个呢? ?? ??? ??? ??? ?偶数都是输出,0,4 ?? ??? ??? ??? ?奇数都是输入,1,3 ?? ??? ??? ??? ?线圈是0和1(线圈是小一点的数 <= 1) ?? ??? ??? ??? ?寄存器是3和4
? ? ? ? ? ? ? ? (这里没有2)
?? ??? ??? ??? ?输入==只读==read only ?? ??? ??? ??? ?输出==读写
一般对接客户的时候说的都是绝对地址; 但是在协议里面都是相对地址,因为协议里面的功能码,从站地址这些都告诉我操作哪个存储区了,因此不需要再告诉我操作哪个存储区了;
所以: ?? ?每个存储区都会有0这个相对地址的, ?? ?每个存储区都是从0这个相对地址开始的;
问题2:?通讯都是16进制的?
这句活不对; 通讯底层都是二进制的,只是我写的时候可以写成10进制的,也可以写成16进制的; 一些博客中写的是0x03,或者0x6B,其实都是可以改的,只是他写的是16进制, 我对应写成10进制也是可以的,效果是一样的,等同的;
代码中, 代码前面加0x那就是16进制的写法, 代码前面不加0x,那就是10进制的写法; ?
问题3: 基础整理
字? ? ?word? 字节? byte? 位? ? ?bit? 字长是指字的长度
1字节=8位(1 byte = 8bit) 1字=2字节(1 word = 2 byte)??
一个字节的字长是8 一个字的字长为16
|