Modbus ASCII是Modbus的一种消息帧,相比RTU,ASCII的传输是按照字符传的,传输的数据量会比RTU更多,所以数据量大的时候一般使用的RTU,数据量小的时候才会用ASCII,然后ASCII协议帧里面添加了起始和结束,更换了校验算法,下面详细介绍ASCII协议
帧格式
Modbus ASCII 模式下的通讯帧格式如下:
名称 | 长度 (字节) | 描述 |
---|---|---|
Start | 1 | 以冒号 : 开头,ASCII 十六进制值为 3A |
Address | 2 | 十六进制节点地址,字符表示 |
Function | 2 | 十六进制功能码,字符表示 |
Data | n x 2 | n 是数据字节数,它取决于功能码 |
LRC | 2 | LRC冗余检验码 |
End | 2 | CR / LF |
注:地址、功能、数据和 LRC 都是表示 8 位值 (0-255) 的大写十六进制可读字符对;即:在 Modbus ASCII 中,每个数据字节被分割成表示十六进制值中的两个 ASCII 字符的两个字节。
组件 | 描述 | 字符数 | ASCII表示 |
---|---|---|---|
Start | 消息开始 | 1 CHAR | : |
Address | 节点地址(十六进制表示) | 2 CHARS | |
Function | 功能码(十六进制表示) | 2 CHARS | |
Data | 数据(根据功能码变化,十六进制表示) | n CHARS | |
LRC CHECK | 纵向冗余检验码(LRC) | 2 CHARS | |
END | 消息结束,回车换行 | 2 CHARS | CRLF |
在 ASCII 模式下,Modbus 消息的每个部分都以特定的字符数和格式出现,如下所示:
:AA BB CC...DD EE<CRLF>
:
– 消息的开始符号。AA
– 节点地址,十六进制表示。BB
– 功能码,十六进制表示。CC...DD
– 数据字段,根据功能码和需要传输的数据长度变化。EE
– LRC 校验码,用于错误检测。<CRLF>
– 消息的结束符号,代表回车和换行(Carriage Return Line Feed)。
ASCII帧的传输状态
上面状态图可以得到的信息:
1)“空闲” 态是没有发送和接收报文要处理的正常状态。
2)每次接收到 “:” 字符表示新的报文的开始。如果在一个报文的接收过程中收到该字符,则当前地报文被认为不完整并被丢弃。而一个新的接收缓冲区被重新分配。
3)检测到帧结束后,完成 LRC 计算和检验。然后,分析地址域以确定帧是否发往此设备,如果不是,则丢弃此帧。 为了减少接收处理时间,地址域可以在一接到就分析,而不需要等到整个帧结束。
ASCII帧的报文传输
由于ASCII报文帧与RTU报文帧有着很大的不同,ASCII报文帧是有起始和结束标识符的,而RTU帧没有这样的标识。所以ASCII报文帧的接收就简单方便多了,也不需要什么t3.5的帧间隔时间。
但是呢,为了保证接收的报文帧连续,还是可以约定字符间的传输时间的。一般认为,报文中的字符时间间隔可以达到一秒,如果超过了这个时间间隔,就认为发生了错误,要废弃掉这一帧报文数据,重新开始接收。
功能码
ASCII 模式下最常用的功能代码与 RTU 模式下的功能代码定义相同。以下是一些基本的功能码及其描述:
访问地址 | 映射地址 | 描述 | 功能 | R/W |
---|---|---|---|---|
1 ~ 10000 | address-1 | Coils | 01/05/15 | R/W |
10001 ~ 20000 | address-10001 | Discrete Inputs | 02 | R |
30001 ~ 40000 | address-30001 | Input Registers | 04 | R |
40001 ~ 50000 | address-40001 | Holding Registers | 03/06/16 | R/W |
ASCII传输示例
例如,要读取地址 0x20C1
的两个寄存器,需要发送以下 ASCII 消息:
:010420C1000218<CRLF>
请求:
:
– 消息开始 – 0x3A01
– 从站地址 – 0x0104
– 功能码 (读取输入寄存器) – 0x0420C1
– 要读取的寄存器地址 – 0x20C10002
– 要读取的寄存器长度 (必须是 2) – 0x000218
– LRC 校验码<CRLF>
– 消息结束,回车换行 – 0x0D0A
响应:
:01040400001234B1<CRLF>
响应:
:
– 消息开始 – 0x3A01
– 从站地址 – 0x0104
– 功能码 (读取输入寄存器) – 0x0404
– 读取数据长度 (4 字节) – 0x0400001234
– 从 VAR1 读取的值 – 0x00001234B1
– LRC 校验码<CRLF>
– 消息结束,回车换行 – 0x0D0A
常用功能码操作
以下是 Modbus 的常用功能码及其请求和响应示例:
功能 01(01H)读线圈
- 请求:读取从机中线圈的 ON/OFF 状态。
- 响应:线圈状态响应消息被打包为数据字段的每比特表示一个线圈。
功能 02(02H)读离散输入
- 请求:读取从机中离散输入的 ON/OFF 状态。
- 响应:离散输入状态响应消息的构造与线圈状态相同。
功能 03(03H)读保持寄存器
- 请求:读取从机中保持寄存器的二进制内容。
- 响应:保持寄存器数据在每个寄存器中打包为两个字节。
功能 04(04H)读输入寄存器
- 请求:读取从机中输入寄存器的二进制内容。
- 响应:读输入寄存器数据的响应消息的构造与读取保持寄存器相同。
功能 05(05H)写单线圈
- 请求:将单个线圈写入 ON 或 OFF。
- 响应:正常的响应是请求的回显。
功能 06(06H)写单个保持寄存器
- 请求将一个值写入单个保持寄存器中。当广播时,该函数在所有附加的从机上设置相同的寄存器引用。请求消息指定要写入的寄存器引用(指定地址和数值)。
- 响应
功能 15(0FH)写多个线圈
- 请求:将一个线圈序列中的每个线圈写入 ON 或 OFF。
- 响应:正常响应返回从地址、功能代码、起始地址和写入的线圈数量。
功能 16(10H)写多个保持寄存器
- 请求:将值写入到一个保持寄存器序列中。
- 响应:正常响应返回从地址、功能代码、起始地址和写入的寄存器数量。
LRC校验
LRC 校验码的计算方法如下:
unsigned char ucMBLRC( unsigned char * pucFrame, unsigned short usLen ) { unsigned char ucLRC = 0; /* LRC char initialized */ while( usLen-- ) { ucLRC += *pucFrame++; /* Add buffer byte without carry */ } /* Return twos complement */ ucLRC = ( UCHAR ) ( -( ( CHAR ) ucLRC ) ); return ucLRC; }