天力
概述
天力的能源系统使用 [TAS](串口通信 | 天尘的知识库) 设备单口或者多口交换机,TCP版本的流量计测试工具在阿里云盘:备份文件 > setup > dev > 流量计测试工具IP
智能硬件
2024年10月21日 要采集水表数据,同一个厂家有两个规格的水表使用的通讯协议不一样 DN80 和 DN150 后来又联系到厂家另外一个人给的是DN150通讯协议,在:阿里云盘 > 备份文件 > 客户资料 > 天力 > 智能硬件 > 水表 > DN150 > DN150通讯协议CH.docx
DN80
仪表参数设置的说明书在:阿里云盘> 备份文件 > 客户资料 > 天力 > 智能硬件 > 水表 > DN80 > 电磁流量计使用说明书v2.02021年9月24日.pdf 。仪表密码100000
采用标准的 modbus rtu 协议通讯,读取数据是功能码03,支持波特率 1200,2400,4800,9600,19200,串口参数为:1 位起始位 8 位数据位 1 位停止位 N 无校验。2024年12月12日 10:53:27 高松发来仪表密码:07206
采集数据发送的指令介绍
01 04 10 10 00 02 74CE
# 01 - 设备地址码
# 04 - 功能码,读取设备数据
# 10 - 读取寄存器的地址高位
# 10 - 读取寄存器的地址地位
# 00 - 读取寄存器长度的高位
# 02 - 读取寄存器长度的低位
# 74CE - CRC校验码
接受到的数据
01 04 04 C4 1C 60 00 2F72
# 01 - 设备地址
# 04 - 功能码,表示读取
# 04 - 数据长度,4个寄存器
# C41C6000 - 瞬时流量,4个字段浮点数
# 2F72 - CRC校验码
瞬时流量数据为 Float Inverse 格式,采用 IEEE754,32 位浮点数格式,计算 C41C6000 的结果是 -625.5。
下面介绍读取正向累计整数部分数据的方法
01 04 10 18 00 02 F50C
# 01 - 仪表地址码
# 04 - 读取数据
# 10 - 被读取的寄存器地址高位
# 18 - 被读取的寄存器地址低位
# 00 - 读取寄存器长度的高位
# 02 - 读取寄存器长度的低位
# F50C - CRC校验码
# 接受到的数据:
01 04 04 01 23 45 67 78C8
# 01 - 地址码
# 04 - 功能码,表示读取数据
# 04 - 数据长度,表示4个寄存器
# 01 23 45 67 - 读取到的数据
# 78C8 - CRC校验码
解析上面的数据 1234567 ,正向累积量整数部分数据为 Long Inverse 格式,所以最终计算的结果是 19088743。下面是 2024年10月21日 16:43:15 天力厂里解析数据的实例
发送指令: 010410180002F50C
接受数据: 010404 000044D8 C8DE
上面 000044D8 整型数据,Long Inverse 计算方式如下:
4*16^3+4*16^2+13*16+8 = 16384 + 1024 + 208 + 8 = 17624
DN150
系统设置
在主界面长按“确认键”会弹出密码验证,输入1000进入设置界面
进入系统设置
查看协议版本号 MAY-18 2023 = Li协议 JUN-28 2023 = Li协议 AUG-16 2023 = 兰申协议
兰申协议读取正向累积数值整数(下面指令与仪表厂家技术确认过,还没有实际测试)
01 04 10 18 00 02 F50C
# 01 - 仪表地址码
# 04 - 读取数据
# 10 - 被读取的寄存器地址高位
# 18 - 被读取的寄存器地址低位
# 00 - 读取寄存器长度的高位
# 02 - 读取寄存器长度的低位
# F50C - CRC校验码
后来联系仪表厂家后又拿到一个 DN150的通讯说明书,在阿里云盘:备份文件 > 客户资料 > 天力 > 水表 > DN150 > DN150通讯协议CH。根据该协议通讯方式如下
# 读取正向累计整数
01030008000245C9
# 得到的响应数据如下
010304 00D92338 332A
# 解析其中的数据同 DN80 的正向累计整数部分是 Long Interverse 的方式解析数据
00D92338 换算成十进制为 14230328 即正向累计整数部分
# vb6 中转换数据:00D92338 = CLng("&H" + "00D92338") = 14230328
源码
2024年10月24日 制作的DN80,DN150构建读取指令、解析累计数据的源码如下
' 新东方智能化天力水表,苏州百业兴阀门科技有限公司
' 规格型号:LD-DN80
' 数据采集解析工具
' 传入地址码(一般为01),返回读取“正向累计量整数”的指令
Public Function GetInstruction80(ByVal port As String) As String
Dim ret As String
ret = port + "0410180002"
Dim crc As String
crc = GetCRCString(ret)
GetInstruction80 = ret + crc
End Function
Public Function GetInstruction(ByVal port As String) As String
Dim ret As String
ret = port + "0410180002"
Dim crc As String
crc = GetCRCString(ret)
GetInstruction = ret + crc
End Function
Public Function GetInstruction150(ByVal port As String) As String
Dim ret As String
ret = port + "0300080002"
Dim crc As String
crc = GetCRCString(ret)
GetInstruction150 = ret + crc
End Function
'传入响应的数据,返回“正向累计量整数”
Public Function GetData(ByVal res As String) As Long
Dim data As String
data = Mid(res, 7, 8)
GetData = CLng("&H" + data)
End Function
'传入字符串
'返回CRC的校验码
'返回值是用字符串表示的16进制
Private Function GetCRCString(ByVal vData As String) As String
Dim arrByteInstruction() As Byte
arrByteInstruction = String2ByteArray(vData)
Dim lCRC As Long
lCRC = GetCRCLong(arrByteInstruction)
Dim szCRC As String
szCRC = Hex(lCRC)
'CRC-16得到的校验码字符串长度应该是4
'检测缺少几个字符就在前面补足几个0
Dim diffLength As Integer
diffLength = 4 - Len(szCRC)
Dim i As Integer
For i = 1 To diffLength
szCRC = "0" & szCRC
Next i
GetCRCString = szCRC
End Function
'VB6实现CRC的工具类
'字节值表的方法
Private Function GetCRCHi(Ind As Long) As Byte
GetCRCHi = Choose(Ind + 1, &H0, &HC1, &H81, &H40, &H1, &HC0, &H80, &H41, &H1, &HC0, &H80, _
&H41, &H0, &HC1, &H81, &H40, &H1, &HC0, &H80, &H41, &H0, &HC1, &H81, &H40, &H0, &HC1, &H81, _
&H40, &H1, &HC0, &H80, &H41, &H1, &HC0, &H80, &H41, &H0, &HC1, &H81, &H40, &H0, &HC1, &H81, _
&H40, &H1, &HC0, &H80, &H41, &H0, &HC1, &H81, &H40, &H1, &HC0, &H80, &H41, &H1, &HC0, &H80, _
&H41, &H0, &HC1, &H81, &H40, &H1, &HC0, &H80, &H41, &H0, &HC1, &H81, &H40, &H0, &HC1, &H81, _
&H40, &H1, &HC0, &H80, &H41, &H0, &HC1, &H81, &H40, &H1, &HC0, &H80, &H41, &H1, &HC0, &H80, _
&H41, &H0, &HC1, &H81, &H40, &H0, &HC1, &H81, &H40, &H1, &HC0, &H80, &H41, &H1, &HC0, &H80, _
&H41, &H0, &HC1, &H81, &H40, &H1, &HC0, &H80, &H41, &H0, &HC1, &H81, &H40, &H0, &HC1, &H81, _
&H40, &H1, &HC0, &H80, &H41, &H1, &HC0, &H80, &H41, &H0, &HC1, &H81, &H40, &H0, &HC1, &H81, _
&H40, &H1, &HC0, &H80, &H41, &H0, &HC1, &H81, &H40, &H1, &HC0, &H80, &H41, &H1, &HC0, &H80, _
&H41, &H0, &HC1, &H81, &H40, &H0, &HC1, &H81, &H40, &H1, &HC0, &H80, &H41, &H1, &HC0, &H80, _
&H41, &H0, &HC1, &H81, &H40, &H1, &HC0, &H80, &H41, &H0, &HC1, &H81, &H40, &H0, &HC1, &H81, _
&H40, &H1, &HC0, &H80, &H41, &H0, &HC1, &H81, &H40, &H1, &HC0, &H80, &H41, &H1, &HC0, &H80, _
&H41, &H0, &HC1, &H81, &H40, &H1, &HC0, &H80, &H41, &H0, &HC1, &H81, &H40, &H0, &HC1, &H81, _
&H40, &H1, &HC0, &H80, &H41, &H1, &HC0, &H80, &H41, &H0, &HC1, &H81, &H40, &H0, &HC1, &H81, _
&H40, &H1, &HC0, &H80, &H41, &H0, &HC1, &H81, &H40, &H1, &HC0, &H80, &H41, &H1, &HC0, &H80, _
&H41, &H0, &HC1, &H81, &H40)
End Function
Private Function GetCRCLo(Ind As Long) As Byte
GetCRCLo = Choose(Ind + 1, &H0, &HC0, &HC1, &H1, &HC3, &H3, &H2, &HC2, &HC6, &H6, &H7, &HC7, _
&H5, &HC5, &HC4, &H4, &HCC, &HC, &HD, &HCD, &HF, &HCF, &HCE, &HE, &HA, &HCA, &HCB, &HB, &HC9, _
&H9, &H8, &HC8, &HD8, &H18, &H19, &HD9, &H1B, &HDB, &HDA, &H1A, &H1E, &HDE, &HDF, &H1F, &HDD, _
&H1D, &H1C, &HDC, &H14, &HD4, &HD5, &H15, &HD7, &H17, &H16, &HD6, &HD2, &H12, &H13, &HD3, &H11, _
&HD1, &HD0, &H10, &HF0, &H30, &H31, &HF1, &H33, &HF3, &HF2, &H32, &H36, &HF6, &HF7, &H37, &HF5, _
&H35, &H34, &HF4, &H3C, &HFC, &HFD, &H3D, &HFF, &H3F, &H3E, &HFE, &HFA, &H3A, &H3B, &HFB, &H39, _
&HF9, &HF8, &H38, &H28, &HE8, &HE9, &H29, &HEB, &H2B, &H2A, &HEA, &HEE, &H2E, &H2F, &HEF, &H2D, _
&HED, &HEC, &H2C, &HE4, &H24, &H25, &HE5, &H27, &HE7, &HE6, &H26, &H22, &HE2, &HE3, &H23, &HE1, _
&H21, &H20, &HE0, &HA0, &H60, &H61, &HA1, &H63, &HA3, &HA2, &H62, &H66, &HA6, &HA7, &H67, &HA5, _
&H65, &H64, &HA4, &H6C, &HAC, &HAD, &H6D, &HAF, &H6F, &H6E, &HAE, &HAA, &H6A, &H6B, &HAB, &H69, _
&HA9, &HA8, &H68, &H78, &HB8, &HB9, &H79, &HBB, &H7B, &H7A, &HBA, &HBE, &H7E, &H7F, &HBF, &H7D, _
&HBD, &HBC, &H7C, &HB4, &H74, &H75, &HB5, &H77, &HB7, &HB6, &H76, &H72, &HB2, &HB3, &H73, &HB1, _
&H71, &H70, &HB0, &H50, &H90, &H91, &H51, &H93, &H53, &H52, &H92, &H96, &H56, &H57, &H97, &H55, _
&H95, &H94, &H54, &H9C, &H5C, &H5D, &H9D, &H5F, &H9F, &H9E, &H5E, &H5A, &H9A, &H9B, &H5B, &H99, _
&H59, &H58, &H98, &H88, &H48, &H49, &H89, &H4B, &H8B, &H8A, &H4A, &H4E, &H8E, &H8F, &H4F, &H8D, _
&H4D, &H4C, &H8C, &H44, &H84, &H85, &H45, &H87, &H47, &H46, &H86, &H82, &H42, &H43, &H83, &H41, _
&H81, &H80, &H40)
End Function
'将使用字符串表示的数值转换为字节数组
Private Function String2ByteArray(ByVal vData As String) As Byte()
Dim byteInstruction() As Byte
Dim i As Long
If Len(vData) Mod 2 = 0 And Len(vData) <> 0 Then '检验16进制字符串长
ReDim byteInstruction(Len(vData) / 2 - 1)
For i = 0 To Len(vData) - 1 Step 2
byteInstruction(i / 2) = Val("&H" & Mid(vData, i + 1, 2))
Next
End If
String2ByteArray = byteInstruction
End Function
'传入:字节数组
'返回:CRC校验码的整数类型
'将返回的整数类型通过Hex(整数类型校验码)转换为16进制的字符串
Private Function GetCRCLong(data() As Byte) As Long
Dim CRC16Hi As Byte
Dim CRC16Lo As Byte
CRC16Hi = &HFF
CRC16Lo = &HFF
Dim i As Integer
Dim iIndex As Long
For i = 0 To UBound(data)
iIndex = CRC16Hi Xor data(i)
CRC16Hi = CRC16Lo Xor GetCRCHi(iIndex) '低位处理
CRC16Lo = GetCRCLo(iIndex) '高位处理
Next i
Dim ReturnData(1) As Byte
Dim test As Long
ReturnData(0) = CRC16Hi 'CRC低位
ReturnData(1) = CRC16Lo 'CRC高位
test = Val(Str(ReturnData(0))) * 256 + Val(Str(ReturnData(1)))
GetCRCLong = test
End Function
