基于Modbus协议的串口通讯程序_RS485总线系统应用

网络协议

14人已加入

描述

本文在遵循Modbus协议的基础上,阐述了Modbus的两种传输模式和串口通讯程序的设计实例,并给出了VB语言的程序清单。

基于Modbus协议的串口通讯程序----Modbus协议简介

MODBUS协议支持传统的RS-232、RS-422、RS-485和以太网设备。许多工业设备,包括PLC,DCS,智能仪表等都在使用Modbus协议作为他们之间的通讯标准。

Modbus 协议是应用于电子控制器上的一种通用语言。通过此协议,控制器相互之间、控制器经由网络(例如以太网)和其它设备之间可以通信。Modbus 协议定义了一个控制器能认识使用的消息结构,而不管它们是经过何种网络进行通信的。它描述了一控制器请求访问其它设备的过程,如果回应来自其它设备的请求,以及怎样侦测错误并记录。它制定了消息域格局和内容的公共格式。

ModBus协议

基于Modbus协议的串口通讯程序----RS485总线简介

rs-485采用半双工工作方式,支持多点数据通信。rs-485总线网络拓扑一般采用终端匹配的总线型结构。即采用一条总线将各个节点串接起来,不支持环形或星型网络。

ModBus协议

rs-485采用平衡发送和差分接收,因此具有抑制共模干扰的能力。加上总线收发器具有高灵敏度,能检测低至200mv的电压,故传输信号能在千米以外得到恢复。 有些rs-485收发器修改输入阻抗以便允许将多达8倍以上的节点数连接到相同总线。rs-485最常见的应用是在工业环境下可编程逻辑控制器内部之间的通信。

串口通讯程序设计实例

为了便于理解,下面列举一种采用RTU模式通讯的应用实例。这个实例的硬件由一台计算机和分布在10个房间的10块温湿度表组成RS485网络架构。温湿度表的地址分别设定为01H至0AH。计算机读各温湿度表数据的命令消息帧包含8个字节:

ModBus协议

被点名的温湿度表接收到上述命令消息后,向计算机发送温湿度数据,该消息帧包含11个字节:

ModBus协议

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)

Private Sub Form_Load()

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

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分