mirror of
https://gitee.com/dgiiot/dgiot.git
synced 2024-12-05 13:47:46 +08:00
139 lines
8.4 KiB
Erlang
139 lines
8.4 KiB
Erlang
-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,
|
||
env = <<>>,
|
||
dtutype = <<>>,
|
||
hb = 60
|
||
}).
|
||
|
||
-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).
|
||
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
-define(FC_READ_COILS, 16#01). %读线圈寄存器
|
||
-define(FC_READ_INPUTS, 16#02). %读离散输入寄存器
|
||
-define(FC_READ_HREGS, 16#03). %读保持寄存器
|
||
-define(FC_READ_IREGS, 16#04). %读输入寄存器
|
||
|
||
-define(FC_WRITE_COIL, 16#05). %写单个线圈寄存器
|
||
-define(FC_WRITE_HREG, 16#06). %写单个保持寄存器
|
||
-define(FC_WRITE_COILS, 16#0f). %写多个线圈寄存器
|
||
-define(FC_WRITE_HREGS, 16#10). %写多个保持寄存器
|
||
|
||
%%_____________________________________________
|
||
%%表2 ModBus功能码与数据类型对应表 |
|
||
%%|代码 |功能 |数据类型 |
|
||
%%|01 |读 |位 |
|
||
%%|02 |读 |位 |
|
||
%%|03 |读 |整型、字符型、状态字、浮点型 |
|
||
%%|04 |读 |整型、状态字、浮点型 |
|
||
%%|05 |写 |位 |
|
||
%%|06 |写 |整型、字符型、状态字、浮点型 |
|
||
%%|08 |N/A |重复“回路反馈”信息 |
|
||
%%|15 |写 |位 |
|
||
%%|16 |写 |整型、字符型、状态字、浮点型 |
|
||
%%——————————————————————————————————————————————
|
||
|
||
-record(rtu_req, {slaveId, funcode, address, registersnumber, dataByteSize, quality}).
|
||
-record(rtu_pdu, {slaveId, funcode, dataByteSize, data}).
|
||
-record(tcp_request, {sock, tid = 1, address = 1, function, start, data}).
|
||
|
||
-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
|
||
|
||
-define(MODBUS_RTU, <<"MODBUSRTU">>).
|
||
-define(MODBUS_TCP, <<"MODBUSTCP">>). |