2021-07-05 17:20:37 +08:00
|
|
|
|
-define(DGIOT_MODBUS_TCP_DTU, dgiot_modbus_tcp_dtu_ets).
|
|
|
|
|
-record(state, {
|
|
|
|
|
id,
|
|
|
|
|
devaddr = <<>>,
|
|
|
|
|
heartcount = 0,
|
|
|
|
|
regtype = <<>>,
|
|
|
|
|
head = "xxxxxx0eee",
|
|
|
|
|
len = 0,
|
|
|
|
|
app = <<>>,
|
|
|
|
|
product = <<>>,
|
|
|
|
|
deviceId = <<>>,
|
|
|
|
|
scale = 10,
|
|
|
|
|
temperature = 0,
|
2021-07-19 16:21:40 +08:00
|
|
|
|
env = <<>>,
|
2022-02-10 17:38:31 +08:00
|
|
|
|
dtutype = <<>>,
|
2022-05-17 21:18:23 +08:00
|
|
|
|
hb = 60,
|
|
|
|
|
maxaddr = 0
|
2021-07-05 17:20:37 +08:00
|
|
|
|
}).
|
|
|
|
|
|
2021-06-30 09:57:07 +08:00
|
|
|
|
-define(READ_DISCRETE_INPUTS, 2).
|
|
|
|
|
-define(READ_COILS, 1).
|
|
|
|
|
-define(WRITE_SINGLE_COIL, 5).
|
|
|
|
|
-define(WRITE_MULTIPLE_COILS, 15).
|
|
|
|
|
-define(READ_INPUT_REGISTERS, 4).
|
|
|
|
|
-define(READ_HOLDING_REGISTERS, 3).
|
|
|
|
|
-define(WRITE_SINGLE_HOLDING_REGISTER, 6).
|
|
|
|
|
-define(WRITE_MULTIPLE_HOLDING_REGISTERS, 16).
|
|
|
|
|
|
|
|
|
|
-define(ILLEGAL_FUNCTION, 1).
|
|
|
|
|
-define(ILLEGAL_DATA_ADDRESS, 2).
|
|
|
|
|
-define(ILLEGAL_DATA_VALUE, 3).
|
|
|
|
|
-define(SLAVE_DEVICE_FAILURE, 4).
|
|
|
|
|
-define(ACKNOWLEDGE, 5).
|
|
|
|
|
-define(SLAVE_DEVICE_BUSY, 6).
|
|
|
|
|
-define(NEGATIVE_ACKNOWLEDGE, 7).
|
|
|
|
|
-define(MEMORY_PARITY_ERROR, 8).
|
|
|
|
|
-define(GATEWAY_PATH_UNAVAILABLE, 10).
|
|
|
|
|
-define(GATEWAY_TARGET_DEVICE_FAILED_TO_RESPOND, 11).
|
|
|
|
|
|
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
2021-08-27 16:58:39 +08:00
|
|
|
|
-define(FC_READ_COILS, 16#01). %读线圈寄存器
|
|
|
|
|
-define(FC_READ_INPUTS, 16#02). %读离散输入寄存器
|
|
|
|
|
-define(FC_READ_HREGS, 16#03). %读保持寄存器
|
|
|
|
|
-define(FC_READ_IREGS, 16#04). %读输入寄存器
|
2021-06-30 09:57:07 +08:00
|
|
|
|
|
2021-08-27 16:58:39 +08:00
|
|
|
|
-define(FC_WRITE_COIL, 16#05). %写单个线圈寄存器
|
|
|
|
|
-define(FC_WRITE_HREG, 16#06). %写单个保持寄存器
|
|
|
|
|
-define(FC_WRITE_COILS, 16#0f). %写多个线圈寄存器
|
|
|
|
|
-define(FC_WRITE_HREGS, 16#10). %写多个保持寄存器
|
2021-06-30 09:57:07 +08:00
|
|
|
|
|
|
|
|
|
%%_____________________________________________
|
|
|
|
|
%%表2 ModBus功能码与数据类型对应表 |
|
|
|
|
|
%%|代码 |功能 |数据类型 |
|
|
|
|
|
%%|01 |读 |位 |
|
|
|
|
|
%%|02 |读 |位 |
|
|
|
|
|
%%|03 |读 |整型、字符型、状态字、浮点型 |
|
|
|
|
|
%%|04 |读 |整型、状态字、浮点型 |
|
|
|
|
|
%%|05 |写 |位 |
|
|
|
|
|
%%|06 |写 |整型、字符型、状态字、浮点型 |
|
|
|
|
|
%%|08 |N/A |重复“回路反馈”信息 |
|
|
|
|
|
%%|15 |写 |位 |
|
|
|
|
|
%%|16 |写 |整型、字符型、状态字、浮点型 |
|
|
|
|
|
%%——————————————————————————————————————————————
|
|
|
|
|
|
2022-08-30 20:21:09 +08:00
|
|
|
|
-record(rtu_req, {slaveId, funcode, address, registersnumber, dataByteSize, quality, data}).
|
2021-06-30 09:57:07 +08:00
|
|
|
|
-record(rtu_pdu, {slaveId, funcode, dataByteSize, data}).
|
2021-08-27 16:58:39 +08:00
|
|
|
|
-record(tcp_request, {sock, tid = 1, address = 1, function, start, data}).
|
2021-06-30 09:57:07 +08:00
|
|
|
|
|
|
|
|
|
-record(tcp_request1, {
|
|
|
|
|
id,
|
|
|
|
|
tid = 1,
|
|
|
|
|
address = 1,
|
|
|
|
|
function,
|
|
|
|
|
start,
|
|
|
|
|
data,
|
|
|
|
|
env = #{}
|
|
|
|
|
}).
|
|
|
|
|
|
|
|
|
|
%%_________________________________________________________________________________________________________________________________________________________________
|
|
|
|
|
%%表1 ModBus功能码
|
|
|
|
|
%%_________________________________________________________________________________________________________________________________________________________________
|
|
|
|
|
%%|功能码 | 名称 | 作用
|
|
|
|
|
%%|01 |读取线圈状态 |取得一组逻辑线圈的当前状态(ON/OFF)
|
|
|
|
|
%%|02 |读取输入状态 |取得一组开关输入的当前状态(ON/OFF)
|
|
|
|
|
%%|03 |读取保持寄存器 | 在一个或多个保持寄存器中取得当前的二进制值
|
|
|
|
|
%%|04 |读取输入寄存器 | 在一个或多个输入寄存器中取得当前的二进制值
|
|
|
|
|
%%|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| 保留 |用于异常应答
|
|
|
|
|
%%__________________________________________________________________________________________________________________________________________________________________
|
|
|
|
|
|
|
|
|
|
%%modbus完整支持很多功能码,但是实际在应用的时候常用的也就那么几个。具体如下:
|
|
|
|
|
%%
|
|
|
|
|
%%0x01: 读线圈寄存器
|
|
|
|
|
%%0x02: 读离散输入寄存器
|
|
|
|
|
%%0x03: 读保持寄存器
|
|
|
|
|
%%0x04: 读输入寄存器
|
|
|
|
|
%%0x05: 写单个线圈寄存器
|
|
|
|
|
%%0x06: 写单个保持寄存器
|
|
|
|
|
%%0x0f: 写多个线圈寄存器
|
|
|
|
|
%%0x10: 写多个保持寄存器
|
|
|
|
|
%%如上所示一共8种功能码。这其中有涉及到线圈、离散输入、保持、输入四种寄存器。这名字也不知道谁起的,让人看了一点不通俗易懂,搞得晕晕乎乎。实际上你要是看清他的本质就很简单了。下面分别解释一下:
|
|
|
|
|
%%
|
|
|
|
|
%%线圈寄存器:实际上就可以类比为开关量,每个bit都对应一个信号的开关状态。所以一个byte就可以同时控制8路的信号。比如控制外部8路io的高低。 线圈寄存器支持读也支持写,写在功能码里面又分为写单个线圈寄存器和写多个线圈寄存器。对应上面的功能码也就是:0x01 0x05 0x0f
|
|
|
|
|
%%
|
|
|
|
|
%%离散输入寄存器:如果线圈寄存器理解了这个自然也明白了。离散输入寄存器就相当于线圈寄存器的只读模式,他也是每个bit表示一个开关量,而他的开关量只能读取输入的开关信号,是不能够写的。比如我读取外部按键的按下还是松开。所以功能码也简单就一个读的 0x02
|
|
|
|
|
%%
|
|
|
|
|
%%保持寄存器:这个寄存器的单位不再是bit而是两个byte,也就是可以存放具体的数据量的,并且是可读写的。比如我我设置时间年月日,不但可以写也可以读出来现在的时间。写也分为单个写和多个写,所以功能码有对应的三个:0x03 0x06 0x10
|
|
|
|
|
%%
|
|
|
|
|
%%输入寄存器:只剩下这最后一个了,这个和保持寄存器类似,但是也是只支持读而不能写。一个寄存器也是占据两个byte的空间。类比我我通过读取输入寄存器获取现在的AD采集值。对应的功能码也就一个 0x04
|
|
|
|
|
%%
|
|
|
|
|
%%对应的错误返回:
|
|
|
|
|
%%在对应功能码基础上加上0x80
|
|
|
|
|
%%
|
|
|
|
|
%%1、“01”读取线圈状态发送:
|
|
|
|
|
%%————————————————
|
|
|
|
|
%%版权声明:本文为CSDN博主「JiaoCL」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
|
|
|
|
|
%%原文链接:https://blog.csdn.net/liboxiu/article/details/86473516
|
2022-02-21 14:16:09 +08:00
|
|
|
|
|
|
|
|
|
-define(MODBUS_RTU, <<"MODBUSRTU">>).
|
2022-05-17 21:18:23 +08:00
|
|
|
|
-define(MODBUS_TCP, <<"MODBUSTCP">>).
|