基于Modbus协议的串口通讯程序——(RS485总线系统应用之3) rs485 modbus协议

《基于Modbus协议的串口通讯程序》

东风汽车有限公司计量测试中心 王德宪

内容摘要:本文在遵循Modbus协议的基础上,阐述了Modbus的两种传输模式和串口通讯程序的设计实例,并给出了VB语言的程序清单。可供有关技术人员在相关设计和应用工作中参考。

关键词:Modbus协议、串口通讯、VB程序

1. Modbus协议简介

Modbus 协议是一种国际通用的通信标准。我国在2004年9月发布了GB/Z19582《基于Modbus协议的工业自动化网络规范》,2008年3月国家标准化管理委员会正式批准为GB/T 19582-2008。

Modbus协议规定每个控制器必须有自己的设备地址。当一个控制器在Modbus网络上接收到一条消息时,首先要识别是否发给自己。如果是并且需要回应,控制器将生成反馈消息并依据Modbus协议发出。

不论是何种控制器经过何种网络进行通信,Modbus协议定义了一个控制器能够识别的消息域的框架结构和内容的公共格式。它描述了一个控制器请求访问其它设备的过程,以及如何回应来自其它设备的请求。还规定了如何侦测和记录错误。

遵循Modbus协议,不同厂家生产的控制设备可以连接在同一个工业网络。在这个网络上,主机设备可以方便地对各种控制设备进行集中监控,各控制设备之间也可以直接相互通信。

1.1 Modbus的两种传输模式

Modbus的两种传输模式分别是ASCII(美国标准信息交换代码)和RTU(远程终端装置)。在同一个Modbus网络上的所有设备都必须选择相同的传输模式和串口参数。

1.1.1 ASCII模式

使用ASCII字符帧时,位的发送序列是:

有奇偶校验:

启始位

1

2

3

4

5

6

7

奇偶位

停止位

无奇偶校验:

启始位

1

2

3

4

5

6

7

停止位

停止位

当控制器设为在Modbus网络上以ASCII模式通信时,在消息中的每个字节(8Bit)都作为一个ASCII字符发送。这种方式的主要优点是字符发送的时间间隔可达到1秒而不产生错误。

ASCII模式的消息帧结构:

冒号符

地址码

功能代码

数据数量

数据1

...

数据n

LRC高字节

LRC低字节

回车符

换行符

1.1.2 RTU模式

使用RTU字符帧时,位的发送序列是:

有奇偶校验:

启始位

1

2

3

4

5

6

7

8

奇偶位

停止位

无奇偶校验:

启始位

1

2

3

4

5

6

7

8

停止位

停止位

当控制器设为在Modbus网络上以RTU模式通信时,在消息中的每个字节(8Bit)包含两个4Bit的十六进制字符。这种方式的主要优点是:在同样的波特率下,可比ASCII方式传送更多的数据。

RTU模式的消息帧结构:

地址

功能代码

数据数量

数据1

...

数据n

CRC低字节

CRC高字节

1.2 Modbus的消息帧结构

在ASCII或RTU两种传输模式中,传输设备将Modbus消息转换为有起点和终点的帧,这就可以使接收设备在消息起始处同步接收数据,读取地址信息,判断哪一个设备被选中,判知何时信息已传送完毕。有些消息也能侦测到错误并且能返回结果。

1.2.1 ASCII帧

使用ASCII模式,每帧消息以冒号(:)字符(ASCII码 3AH)开始,以回车换行符结束(ASCII码 0DH,0AH)。

其它域可以使用的传输字符是十六进制的0...9,A...F。网络上的设备不断侦测“:”字符,当有一个冒号接收到时,每个从设备都解码下个域(地址域)来判断是否是发给自己的。

消息中字符间发送的时间间隔最长不能超过1秒,否则接收的设备将认为传输错误。一个典型消息帧如下所示:

基于Modbus协议的串口通讯程序——(RS485总线系统应用之3) rs485 modbus协议

起始位

地址域

功能码域

数据域

LRC校验域

结束符

1个字符

2个字符

2个字符

n个字符

2个字符

2个字符

1.2.2 RTU帧

使用RTU模式,发送每帧消息之前至少要有3.5个字节时间的停顿。传输的第一个域是设备地址。可以使用的传输字符是十六进制的0...9,A...F。网络上的设备不断侦测网络总线,当接收到地址域时,每个从设备都进行解码以判断是否发给自己。在最后一个传输字节之后,应至少停顿3.5个字节时间,一个新的消息必须在此停顿后再开始。

起始位

地址域

功能码域

数据域

CRC校验域

结束符

停顿3.5个字节

8Bit

8Bit

n个8Bit

16Bit

停顿3.5个字节

1.2.3 消息帧中各域的说明

地址域包含两个字符(ASCII)或8Bit(RTU)。允许的从设备地址范围是十进制的0~247。主设备将要联络的从设备的地址放入消息中的地址域来选通从设备。当从设备发送回应消息时,它把自己的地址放入回应的地址域中,以便主设备知道是哪一个设备作出的回应。地址0用作广播地址,以使所有的从设备都能认识。当Modbus协议用于更高水准的网络时,广播可能被禁止或以其它方式代替。

功能码域包含了两个字符(ASCII)或8Bit(RTU)。可能的代码范围是十六进制的01H~FFH。

数据域可以由若干个ASCII字符或RTU字节组成。数据域的值由十六进制数构成,范围为00H~FFH。数据域包含了寄存器地址、要处理的数据字节数以及相应的数据值。

错误检测域包含两个字符(ASCII)或一个16Bit值(RTU)。错误检测域的内容是通过LRC(纵向冗长检测)或CRC(循环冗长检测)方法得出的。需要注意的是:LRC的高位字节在低位字节之前,而CRC的低位字节在高位字节之前。

2. 串口通讯程序设计实例

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

地址域

功能码域

数据域

错误校验域

单字节

单字节

读寄存器地址高字节

读寄存器地址低字节

读寄存器个数高字节

读寄存器个数低字节

CRC低字节

CRC高字节

0XH

04H

00H

00H

00H

02H

XXH

XXH

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

地址域

功能码域

数据域

错误校验域

单字节

2字节的命令数据

2字节的温度数据

2字节的湿度数据

2字节的露点数据

CRC低字节

CRC高字节

0XH

XXXXH

XXXXH

XXXXH

XXH

XXH

XXH

3.VB语言设计的上述实例的串口通讯程序清单

Private Declare Function timeGetTime Lib"winmm.dll" () As Long

Public btLoCRC As Byte, btHiCRC As Byte, t0 AsLong, t1 As Long, t2 As Long, t3 As Long

Public Rnumber As Integer, ii As Integer, i AsInteger, 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秒读一轮温湿度表数据

IfMSComm1.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

EndWith

Timer1.Interval = 100'定时器1定时100毫秒

Timer1.Enabled = True'定时器1开始计时

End Sub

Private Sub Timer1_Timer()'定时发送(读数据的)命令

Timer1.Enabled = False'定时器1停止计时

t0= timeGetTime'从系统取得当前(开始读温湿度表) 时刻

Dimtbisend(7) As Byte'定义发送数据的数组

IfMSComm1.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

EndIf

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 AsString

Dim INByte() As Byte

IfMSComm1.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'清接收缓存

EndIf

End Sub

Function CRC16(Data() As Byte, No As Integer,CRC16Lo As Byte, CRC16Hi As Byte) As String

DimCL 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

Fori = 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

参考文献:

①《基于Modbus协议的工业自动化网络规范》GB/T 19582.1-2008

②《Modbus协议中文版》可在互联网上下载

  

爱华网本文地址 » http://www.413yy.cn/a/25101013/164478.html

更多阅读

串口线与并口线的区别 串口并口区别

串口线与并口线的区别——简介我们经常碰到串口线或者并口线,究竟他们有什么区别呢?串口线与并口线的区别——工具/原料串口线,并口线串口线与并口线的区别——方法/步骤串口线与并口线的区

串口通信的分类 基于fpga的串口通信

串口通信的分类串口通信可以分为同步通信和异步通信两类。同步通信是按照软件识别同步字符来实现数据的发送和接收,异步通信是一种利用字符的再同步技术的通信方式。2.1同步通信同步通信是一种连续串行传送数据的通信方式,一次通信

串口并口硬盘连接详细步骤 硬盘串口和并口的区别

提前声明:我并不是计算机硬件或维修专业,同时也根本没有学习过类似的课程。都是自己瞎琢么出来的,如有不足,敬请多提意见。一般的情况是两个串口的硬盘连接,或是两个并口的硬盘连接,所以,自认为这篇文章叙述的是最复杂的状态,即串口硬盘和

如何用VB编写串口程序 如何编写串口驱动程序

VB控件MSComm功能介绍VB中的MSComm 控件通过串行端口传输和接收数据,为应用程序提供串行通讯功能。MSComm控件在串口编程时非常方便,程序员不必去花时间去了解较为复杂的API函数,而且在VC、VB、Delphi等语言中均可使用。 Microsoft Com

声明:《基于Modbus协议的串口通讯程序——(RS485总线系统应用之3) rs485 modbus协议》为网友淡墨留痕分享!如侵犯到您的合法权益请联系我们删除