用VB写的,协议是modbus rtu
手上有一块仪表,现在就是对其中一个参数的读和写有点疑惑一直搞不明白
请大家帮忙分析到底是我代码的问题还是仪表的限制假设这个参数是SR,从我的软件上去修改它的数值,最大不能修改超过3276.7这个数
如果仪表上显示超过6553.5,那么我的软件上通讯过来的显示一直都是3276.8一、我要修改SR参数为一个大于3276.7的数,比如4000.0。仪表的通讯手册说明小数点不做传送
我要把SR修改成4000实际我就要发送成40000,转成十六进制就是9C40发送帧命令
地址 功能码 第一个字地址 字的值 CRC
02 06 00 A1 9C 40 B0EB 正常情况接收帧命令应该是这样的
02 06 00 A1 9C 40 B0EB 可是为什么在我的软件上返回的却是 028603F261 ???
我自己分析估计是CRC计算错误造成的仪表返回错误数据,
我用前面数值在其他CRC计算工具上有的计算结果是B0D8
在我的软件上测试只要把SR这个参数改成大于3276.7的数据即要发送的数据大于32767
就无法修改,小于这个数就可以正常修改二、现在再说下从仪表读取SR参数的问题
只要仪表的SR这个参数大于6553.5,那么软件上就一直显示3276.8发送帧命令
02 03 00 A1 00 01 D5DB只要SR>6553.5那么返回的数据都是下面这个
02 03 02 FF FF FDF4还有查看了这写和读的极限值好像写正好卡在Ingter 整形数范围-32768~32767
而读好像是String 字符串最大值65535,和这两个有关吧,我是个新手到底是什么原因麻烦帮忙看下三、下面附上我的代码SR读:txtSegRate.Text = Euro3504(.txtDevAdd.Text, 3, 0, "A1", 0, 1, True) / 10SR写:Private Sub cmdSegRate_Click() strData = Replace(Format(DEC_to_HEX(txtSegRate.Text * 10), "@@@@"), " ", "0") Call Euro3504(txtDevAdd.Text, 6, 0, "A1", Left(strData, 2), Right(strData, 2), True)
End Sub
模块代码:
Public Declare Sub Sleep Lib "Kernel32" (ByVal dwMilliseconds As Long)Public Function Euro3504(A1 As String, A2 As String, A3 As String, A4 As String, A5 As String, A6 As String, Flag As Boolean) As StringDim CRC_JS() As Byte
Dim CRCC() As ByteDim Reply As String
Dim R_S As Variant
Dim RR() As Byte
Dim i As Integer'MESSAGE FRAME FORMAT 消息帧格式 ReDim CRCC(5)
CRCC(0) = "&H" + A1
CRCC(1) = "&H" + A2
CRCC(2) = "&H" + A3
CRCC(3) = "&H" + A4
CRCC(4) = "&H" + A5
CRCC(5) = "&H" + A6
CRC_JS = CRC16(CRCC) '调用CRC效验计算函数
If Flag = True Then Eurotherm.MSComm1.Output = CRCC '发送帧命令
Eurotherm.MSComm1.Output = CRC_JS
Eurotherm.MSComm1.OutBufferCount = 0 '清除传输缓冲区
Delay 300 '超过35ms就可以
R_S = Eurotherm.MSComm1.Input
Eurotherm.MSComm1.InBufferCount = 0 '清除传输缓冲区
RR = R_S
Reply = ""
For i = 0 To UBound(RR)
Reply = Reply + Right("0" + Hex(Int(Str(RR(i)))), 2) + ""
Next End If If Reply <> "" Then
Euro3504 = HEX_to_DEC(Mid(Reply, 7, 4)) ' 转十进制
'显示负数,排除Segment Rate地址A1,这个参数只要显示超过3278.6就显示负数了
'因为小数点不传送读取出来就是>32786
If Euro3504 > 32786 And A4 <> "A1" Then
Euro3504 = Euro3504 - 65536
End If
End If
End Function
Public Function HEX_to_DEC(ByVal Hex As String) As Long '十六进制转成十进制
Dim i As Long
Dim b As Long Hex = UCase(Hex)
For i = 1 To Len(Hex)
Select Case Mid(Hex, Len(Hex) - i + 1, 1)
Case "0": b = b + 16 ^ (i - 1) * 0
Case "1": b = b + 16 ^ (i - 1) * 1
Case "2": b = b + 16 ^ (i - 1) * 2
Case "3": b = b + 16 ^ (i - 1) * 3
Case "4": b = b + 16 ^ (i - 1) * 4
Case "5": b = b + 16 ^ (i - 1) * 5
Case "6": b = b + 16 ^ (i - 1) * 6
Case "7": b = b + 16 ^ (i - 1) * 7
Case "8": b = b + 16 ^ (i - 1) * 8
Case "9": b = b + 16 ^ (i - 1) * 9
Case "A": b = b + 16 ^ (i - 1) * 10
Case "B": b = b + 16 ^ (i - 1) * 11
Case "C": b = b + 16 ^ (i - 1) * 12
Case "D": b = b + 16 ^ (i - 1) * 13
Case "E": b = b + 16 ^ (i - 1) * 14
Case "F": b = b + 16 ^ (i - 1) * 15
End Select
Next i
HEX_to_DEC = b
End Function
Public Function DEC_to_HEX(Dec As Long) As String '十进制转化为十六进制
Dim a As String
DEC_to_HEX = ""
Do While Dec > 0
a = CStr(Dec Mod 16)
Select Case a
Case "10": a = "A"
Case "11": a = "B"
Case "12": a = "C"
Case "13": a = "D"
Case "14": a = "E"
Case "15": a = "F"
End Select
DEC_to_HEX = a & DEC_to_HEX
Dec = Dec \ 16
Loop
End Function
Public Sub Delay(mmSec As Long) ' 延时ms 级过程 Dim start As Single
DoEvents
Sleep mmSec
'DoEventsEnd Sub
Public Function CRC16(data() As Byte) As String 'CRC16校验位函数 Dim CRC16Lo As Byte, CRC16Hi As Byte 'CRC寄存器 Dim CL As Byte, CH As Byte '多项式码&HA001 Dim SaveHi As Byte, SaveLo As Byte Dim i As Integer Dim Flag As Integer CRC16Lo = &HFF CRC16Hi = &HFF CL = &H1 CH = &HA0 For i = 0 To UBound(data) CRC16Lo = CRC16Lo Xor data(i) '每一个数据与CRC寄存器进行异或 For Flag = 0 To 7 SaveHi = CRC16Hi SaveLo = CRC16Lo CRC16Hi = CRC16Hi \ 2 '高位右移一位 CRC16Lo = CRC16Lo \ 2 '低位右移一位 If ((SaveHi And &H1) = &H1) Then '如果高位字节最后一位为1 CRC16Lo = CRC16Lo Or &H80 '则低位字节右移后前面补1 End If '否则自动补0 If ((SaveLo And &H1) = &H1) Then '如果LSB为1,则与多项式码进行异或 CRC16Hi = CRC16Hi Xor CH CRC16Lo = CRC16Lo Xor CL End If Next Flag Next i Dim ReturnData(1) As Byte ReturnData(0) = CRC16Lo 'CRC低位 ReturnData(1) = CRC16Hi 'CRC高位 CRC16 = ReturnData
End Function
手上有一块仪表,现在就是对其中一个参数的读和写有点疑惑一直搞不明白
请大家帮忙分析到底是我代码的问题还是仪表的限制假设这个参数是SR,从我的软件上去修改它的数值,最大不能修改超过3276.7这个数
如果仪表上显示超过6553.5,那么我的软件上通讯过来的显示一直都是3276.8一、我要修改SR参数为一个大于3276.7的数,比如4000.0。仪表的通讯手册说明小数点不做传送
我要把SR修改成4000实际我就要发送成40000,转成十六进制就是9C40发送帧命令
地址 功能码 第一个字地址 字的值 CRC
02 06 00 A1 9C 40 B0EB 正常情况接收帧命令应该是这样的
02 06 00 A1 9C 40 B0EB 可是为什么在我的软件上返回的却是 028603F261 ???
我自己分析估计是CRC计算错误造成的仪表返回错误数据,
我用前面数值在其他CRC计算工具上有的计算结果是B0D8
在我的软件上测试只要把SR这个参数改成大于3276.7的数据即要发送的数据大于32767
就无法修改,小于这个数就可以正常修改二、现在再说下从仪表读取SR参数的问题
只要仪表的SR这个参数大于6553.5,那么软件上就一直显示3276.8发送帧命令
02 03 00 A1 00 01 D5DB只要SR>6553.5那么返回的数据都是下面这个
02 03 02 FF FF FDF4还有查看了这写和读的极限值好像写正好卡在Ingter 整形数范围-32768~32767
而读好像是String 字符串最大值65535,和这两个有关吧,我是个新手到底是什么原因麻烦帮忙看下三、下面附上我的代码SR读:txtSegRate.Text = Euro3504(.txtDevAdd.Text, 3, 0, "A1", 0, 1, True) / 10SR写:Private Sub cmdSegRate_Click() strData = Replace(Format(DEC_to_HEX(txtSegRate.Text * 10), "@@@@"), " ", "0") Call Euro3504(txtDevAdd.Text, 6, 0, "A1", Left(strData, 2), Right(strData, 2), True)
End Sub
模块代码:
Public Declare Sub Sleep Lib "Kernel32" (ByVal dwMilliseconds As Long)Public Function Euro3504(A1 As String, A2 As String, A3 As String, A4 As String, A5 As String, A6 As String, Flag As Boolean) As StringDim CRC_JS() As Byte
Dim CRCC() As ByteDim Reply As String
Dim R_S As Variant
Dim RR() As Byte
Dim i As Integer'MESSAGE FRAME FORMAT 消息帧格式 ReDim CRCC(5)
CRCC(0) = "&H" + A1
CRCC(1) = "&H" + A2
CRCC(2) = "&H" + A3
CRCC(3) = "&H" + A4
CRCC(4) = "&H" + A5
CRCC(5) = "&H" + A6
CRC_JS = CRC16(CRCC) '调用CRC效验计算函数
If Flag = True Then Eurotherm.MSComm1.Output = CRCC '发送帧命令
Eurotherm.MSComm1.Output = CRC_JS
Eurotherm.MSComm1.OutBufferCount = 0 '清除传输缓冲区
Delay 300 '超过35ms就可以
R_S = Eurotherm.MSComm1.Input
Eurotherm.MSComm1.InBufferCount = 0 '清除传输缓冲区
RR = R_S
Reply = ""
For i = 0 To UBound(RR)
Reply = Reply + Right("0" + Hex(Int(Str(RR(i)))), 2) + ""
Next End If If Reply <> "" Then
Euro3504 = HEX_to_DEC(Mid(Reply, 7, 4)) ' 转十进制
'显示负数,排除Segment Rate地址A1,这个参数只要显示超过3278.6就显示负数了
'因为小数点不传送读取出来就是>32786
If Euro3504 > 32786 And A4 <> "A1" Then
Euro3504 = Euro3504 - 65536
End If
End If
End Function
Public Function HEX_to_DEC(ByVal Hex As String) As Long '十六进制转成十进制
Dim i As Long
Dim b As Long Hex = UCase(Hex)
For i = 1 To Len(Hex)
Select Case Mid(Hex, Len(Hex) - i + 1, 1)
Case "0": b = b + 16 ^ (i - 1) * 0
Case "1": b = b + 16 ^ (i - 1) * 1
Case "2": b = b + 16 ^ (i - 1) * 2
Case "3": b = b + 16 ^ (i - 1) * 3
Case "4": b = b + 16 ^ (i - 1) * 4
Case "5": b = b + 16 ^ (i - 1) * 5
Case "6": b = b + 16 ^ (i - 1) * 6
Case "7": b = b + 16 ^ (i - 1) * 7
Case "8": b = b + 16 ^ (i - 1) * 8
Case "9": b = b + 16 ^ (i - 1) * 9
Case "A": b = b + 16 ^ (i - 1) * 10
Case "B": b = b + 16 ^ (i - 1) * 11
Case "C": b = b + 16 ^ (i - 1) * 12
Case "D": b = b + 16 ^ (i - 1) * 13
Case "E": b = b + 16 ^ (i - 1) * 14
Case "F": b = b + 16 ^ (i - 1) * 15
End Select
Next i
HEX_to_DEC = b
End Function
Public Function DEC_to_HEX(Dec As Long) As String '十进制转化为十六进制
Dim a As String
DEC_to_HEX = ""
Do While Dec > 0
a = CStr(Dec Mod 16)
Select Case a
Case "10": a = "A"
Case "11": a = "B"
Case "12": a = "C"
Case "13": a = "D"
Case "14": a = "E"
Case "15": a = "F"
End Select
DEC_to_HEX = a & DEC_to_HEX
Dec = Dec \ 16
Loop
End Function
Public Sub Delay(mmSec As Long) ' 延时ms 级过程 Dim start As Single
DoEvents
Sleep mmSec
'DoEventsEnd Sub
Public Function CRC16(data() As Byte) As String 'CRC16校验位函数 Dim CRC16Lo As Byte, CRC16Hi As Byte 'CRC寄存器 Dim CL As Byte, CH As Byte '多项式码&HA001 Dim SaveHi As Byte, SaveLo As Byte Dim i As Integer Dim Flag As Integer CRC16Lo = &HFF CRC16Hi = &HFF CL = &H1 CH = &HA0 For i = 0 To UBound(data) CRC16Lo = CRC16Lo Xor data(i) '每一个数据与CRC寄存器进行异或 For Flag = 0 To 7 SaveHi = CRC16Hi SaveLo = CRC16Lo CRC16Hi = CRC16Hi \ 2 '高位右移一位 CRC16Lo = CRC16Lo \ 2 '低位右移一位 If ((SaveHi And &H1) = &H1) Then '如果高位字节最后一位为1 CRC16Lo = CRC16Lo Or &H80 '则低位字节右移后前面补1 End If '否则自动补0 If ((SaveLo And &H1) = &H1) Then '如果LSB为1,则与多项式码进行异或 CRC16Hi = CRC16Hi Xor CH CRC16Lo = CRC16Lo Xor CL End If Next Flag Next i Dim ReturnData(1) As Byte ReturnData(0) = CRC16Lo 'CRC低位 ReturnData(1) = CRC16Hi 'CRC高位 CRC16 = ReturnData
End Function
CRC校验码B0EB是对的,
返回的错误码代码是03,解释是"非法数据值",
发送的时候高字节在后低字节在前,可能需要送出409C二,
Integer类型只支持有符号数,超过32767的话会变成负数,所以需要定义成Long型数据
Dim i As Integer
和我另外重新发问的帖子里的手册内容有关,谢谢
见这个帖子http://bbs.csdn.net/topics/390992706