本文在遵循Modbus協(xié)議的基礎(chǔ)上,闡述了Modbus的兩種傳輸模式和串口通訊程序的設(shè)計實例,并給出了VB語言的程序清單。
基于Modbus協(xié)議的串口通訊程序----Modbus協(xié)議簡介
MODBUS協(xié)議支持傳統(tǒng)的RS-232、RS-422、RS-485和以太網(wǎng)設(shè)備。許多工業(yè)設(shè)備,包括PLC,DCS,智能儀表等都在使用Modbus協(xié)議作為他們之間的通訊標準。
Modbus 協(xié)議是應(yīng)用于電子控制器上的一種通用語言。通過此協(xié)議,控制器相互之間、控制器經(jīng)由網(wǎng)絡(luò)(例如以太網(wǎng))和其它設(shè)備之間可以通信。Modbus 協(xié)議定義了一個控制器能認識使用的消息結(jié)構(gòu),而不管它們是經(jīng)過何種網(wǎng)絡(luò)進行通信的。它描述了一控制器請求訪問其它設(shè)備的過程,如果回應(yīng)來自其它設(shè)備的請求,以及怎樣偵測錯誤并記錄。它制定了消息域格局和內(nèi)容的公共格式。
基于Modbus協(xié)議的串口通訊程序----RS485總線簡介
rs-485采用半雙工工作方式,支持多點數(shù)據(jù)通信。rs-485總線網(wǎng)絡(luò)拓撲一般采用終端匹配的總線型結(jié)構(gòu)。即采用一條總線將各個節(jié)點串接起來,不支持環(huán)形或星型網(wǎng)絡(luò)。
rs-485采用平衡發(fā)送和差分接收,因此具有抑制共模干擾的能力。加上總線收發(fā)器具有高靈敏度,能檢測低至200mv的電壓,故傳輸信號能在千米以外得到恢復(fù)。 有些rs-485收發(fā)器修改輸入阻抗以便允許將多達8倍以上的節(jié)點數(shù)連接到相同總線。rs-485最常見的應(yīng)用是在工業(yè)環(huán)境下可編程邏輯控制器內(nèi)部之間的通信。
串口通訊程序設(shè)計實例
為了便于理解,下面列舉一種采用RTU模式通訊的應(yīng)用實例。這個實例的硬件由一臺計算機和分布在10個房間的10塊溫濕度表組成RS485網(wǎng)絡(luò)架構(gòu)。溫濕度表的地址分別設(shè)定為01H至0AH。計算機讀各溫濕度表數(shù)據(jù)的命令消息幀包含8個字節(jié):
被點名的溫濕度表接收到上述命令消息后,向計算機發(fā)送溫濕度數(shù)據(jù),該消息幀包含11個字節(jié):
VB語言設(shè)計的上述實例的串口通訊程序清單
Private Declare Function timeGetTime Lib “winmm.dll” () As Long
Public btLoCRC As Byte, btHiCRC As Byte, t0 As Long, t1 As Long, t2 As Long, t3 As Long
Public Rnumber As Integer, ii As Integer, i As Integer, j As Integer, k As Integer, ReadT, Crc
Dim TemperatureData(10), HumidityData(10)
Me.Height = 6660
Rnumber = 10 ‘房間數(shù)量(每個房間裝1塊溫濕度表)
ReadT = 10 ’每10秒讀一輪溫濕度表數(shù)據(jù)
If MSComm1.PortOpen = True Then MSComm1.PortOpen = False ‘如果串口1是打開狀態(tài)則關(guān)閉它
With MSComm1 ’設(shè)置串口參數(shù)
.CommPort = 1 ‘指定使用串口1
.Settings = “9600,N,8,1” ’波特率9600bit/s,無校驗,8個數(shù)據(jù)位,1個停止位
.InputMode = comInputModeBinary ‘發(fā)送二進制數(shù)值(=comInputModeText為發(fā)送字符)
.InputLen = 50 ’從接收緩沖區(qū)中可一次性讀取的數(shù)據(jù)個數(shù)
.InBufferCount = 0 ‘清空接收緩沖區(qū)
.OutBufferCount = 0 ’清空發(fā)送緩沖區(qū)
.RThreshold = 5 + 2 * 2 ‘設(shè)置成接收9個字節(jié)就產(chǎn)生OnComm事件
.InBufferSize = 512 ’設(shè)置接收緩存區(qū)容量
.OutBufferSize = 512 ‘設(shè)置發(fā)送緩存區(qū)容量
MSComm1.PortOpen = True ’打開串口1
End With
Timer1.Interval = 100 ‘定時器1定時100毫秒
Timer1.Enabled = True ’定時器1開始計時
End Sub
Private Sub Timer1_Timer() ‘定時發(fā)送(讀數(shù)據(jù)的)命令
Timer1.Enabled = False ’定時器1停止計時
t0 = timeGetTime ‘從系統(tǒng)取得當(dāng)前 (開始讀溫濕度表) 時刻
Dim tbisend(7) As Byte ’定義發(fā)送數(shù)據(jù)的數(shù)組
If MSComm1.PortOpen = True Then
For k = 1 To Rnumber ‘依次向各個房間的溫濕度表發(fā)送讀命令
ii = k
tbisend(0) = “&h” + Hex(k) ’被呼叫子機的地址碼
tbisend(1) = “&h” + Hex(4) ‘4是讀寄存器的功能碼
tbisend(2) = “&h” + Hex(0) ’被讀寄存器的起始地址高字節(jié)
tbisend(3) = “&h” + Hex(0) ‘被讀寄存器的起始地址低字節(jié)
tbisend(4) = “&h” + Hex(0) ’一次讀寄存器的個數(shù)的高字節(jié)
tbisend(5) = “&h” + Hex(2) ‘一次讀寄存器的個數(shù)的低字節(jié)
Crc = CRC16(tbisend, 6, btLoCRC, btHiCRC) ’計算tbisend(0)~tbisend(5)的CRC校驗值
tbisend(6) = “&h” + Hex(btLoCRC) ‘CRC低位
tbisend(7) = “&h” + Hex(btHiCRC) ’CRC高位
If MSComm1.PortOpen = False Then MSComm1.PortOpen = True
MSComm1.Output = tbisend ‘發(fā)送數(shù)據(jù)
t1 = timeGetTime
While timeGetTime 《 t1 + 100 ’延時等待100毫秒,以便有足夠時間接收從機發(fā)來的數(shù)據(jù)
DoEvents
Wend
Text1(k - 1).Value = TemperatureData(k) ‘顯示溫度值
Text2(k - 1).Value = HumidityData(k) ’顯示濕度值
Next k
End If
t2 = timeGetTime ‘從系統(tǒng)取得當(dāng)前 (結(jié)束讀溫濕度表) 時刻
t3 = t2 - t0 ’算出讀溫濕度表的耗時
Timer1.Interval = ReadT * 1000 - t3 ‘定時器1定時,如果不減去T3,會使讀周期變長
Timer1.Enabled = True ’定時器1開始計時
End Sub
Private Sub MSComm1_OnComm() ‘接收數(shù)據(jù)
Dim TemperatureData6 As String, HumidityData6 As String
Dim INByte() As Byte
If MSComm1.CommEvent = comEvReceive Then ’如有接收事件發(fā)生,則響應(yīng)并作計算
INByte = MSComm1.Input ‘接收數(shù)據(jù)
If INByte(0) = ii And INByte(1) = 4 Then ’如收到的地址碼=被叫從機地址并且功能碼=讀寄存器,
‘則將收到的CRC碼與收到的數(shù)據(jù)計算出的CRC碼比較
Crc = CRC16(INByte, UBound(INByte) - LBound(INByte) - 1, btLoCRC, btHiCRC) ’計算收到數(shù)據(jù)的CRC校驗值
If INByte(UBound(INByte) - 1) = btLoCRC And INByte(UBound(INByte)) = btHiCRC Then ‘如校驗正確則計算
TemperatureData6 = Hex(INByte(3)) & Format(Hex(INByte(4)), “00”) ’將溫度轉(zhuǎn)換成十六進制
HumidityData6 = Hex(INByte(5)) & Format(Hex(INByte(6)), “00”) ‘將濕度轉(zhuǎn)換成十六進制
TemperatureData(ii) = Format(Val(“&H” & TemperatureData6) / 10, “##0.0”) ’將溫度轉(zhuǎn)換為十進制
HumidityData(ii) = Format(Val(“&H” & HumidityData6) / 10, “##0.0”) ‘將濕度轉(zhuǎn)換為十進制
End If
End If
MSComm1.InBufferCount = 0 ’清接收緩存
End If
End Sub
Function CRC16(Data() As Byte, No As Integer, CRC16Lo As Byte, CRC16Hi As Byte) As String
Dim CL As Byte, CH As Byte, SaveLo As Byte, SaveHi As Byte
CRC16Hi = &HFF ‘為16位CRC校驗寄存器賦初始值 FFFFH
CRC16Lo = &HFF
CH = &HA0 ’為16位CRC校驗多項式賦初始值 A001H
CL = &H1
For i = 1 To No
CRC16Lo = CRC16Lo Xor Data(i - 1) ‘將被校驗的每個字節(jié)數(shù)據(jù)依次與CRC校驗寄存器進行異或
For j = 1 To 8 ’8次移位
SaveHi = CRC16Hi
SaveLo = CRC16Lo
CRC16Hi = CRC16Hi \ 2 ‘高位右移一位
CRC16Lo = CRC16Lo \ 2 ’低位右移一位
If ((SaveHi And &H1) = &H1) Then ‘如果高位字節(jié)最右一位為1,則低位字節(jié)最左位補1,否則補0
CRC16Lo = CRC16Lo Or &H80
End If
If ((SaveLo And &H1) = &H1) Then ’如低位字節(jié)最右一位為1,則與多項式值異或
CRC16Hi = CRC16Hi Xor CH
CRC16Lo = CRC16Lo Xor CL
End If
Next j
Next i
End Function
評論