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