用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) / 10
SR寫:
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 String
Dim CRC_JS() As Byte
Dim CRCC() As Byte
Dim 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
'DoEvents
End 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
uj5u.com熱心網友回復:
有人幫忙看下么???uj5u.com熱心網友回復:
一,CRC校驗碼B0EB是對的,
回傳的錯誤碼代碼是03,解釋是"非法資料值",
發送的時候高位元組在后低位元組在前,可能需要送出409C
二,
Integer型別只支持有符號數,超過32767的話會變成負數,所以需要定義成Long型資料
uj5u.com熱心網友回復:
補充一,我測驗了一下,你發的資料包是對的,不用交換9C40,應該是你的設備不支持4000.0,你需要另想辦法
uj5u.com熱心網友回復:
第一,你的回傳陣列長度不對,長度應該是8,但是你這里只有6
第二:
你的儀表端是否兩個暫存器在存盤回傳值的高低位?
如果是的話,你的讀取應該改成
發送幀命令
02 03 00 A1 00 02 校驗值重新計算
我估計這個01應該是你的讀取資料長度,改成02,讀回兩個暫存器值,組合兩個值,再除以10,就是儀表顯示值了
uj5u.com熱心網友回復:
但是我的儀表通訊手冊定義是高位在前低位在后的
你看我的代碼只有一處定義Integer,好像和這個沒有關系吧?
Dim i As Integer
uj5u.com熱心網友回復:
能否幫我看下我這個問題
和我另外重新發問的帖子里的手冊內容有關,謝謝
見這個帖子http://bbs.csdn.net/topics/390992706
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/101109.html
上一篇:cad vba 選單檔案
下一篇:vb 表單問題
