- 1. 帧format
- 2. ASCII帧的传输状态
- 3. ASCII帧的message传输
- 4. function code
- 5. ASCII传输示例
- 6. 常用function codeOperation
- 7. Function 01(01H)读线圈
- 8. Function 02(02H)读离散输入
- 9. Function 03(03H)读保持register
- 10. Function 04(04H)读输入register
- 11. Function 05(05H)写单线圈
- 12. Function 06(06H)写单个保持register
- 13. Function 15(0FH)写多个线圈
- 14. Function 16(10H)写多个保持register
- 15. LRC verification
Modbus ASCII是Modbus的一种消息帧,相比RTU,ASCII的传输是按照字符传的,传输的data量会比RTUMore,所以data量大的时候一般使用的RTU,data量小的时候才会用ASCII,然后ASCII协议帧里面添加了start和End,更换了校验算法,下面详细介绍ASCII协议
帧format
Modbus ASCII 模式下的通讯帧format如下:
| 名称 | Length (byte) | 描述 |
|---|---|---|
| Start | 1 | 以冒号 : 开头,ASCII hexadecimal值为 3A |
| Address | 2 | hexadecimal节点address,字符表示 |
| Function | 2 | hexadecimalfunction code,字符表示 |
| Data | n x 2 | n 是databyte count,它取决于function code |
| LRC | 2 | LRC冗余检验码 |
| End | 2 | CR / LF |
注:address、Function、data和 LRC 都是表示 8 位值 (0-255) 的大写hexadecimal可读字符对;即:在 Modbus ASCII 中,每个databyte被分割成表示hexadecimal值中的两个 ASCII 字符的两个byte。
| 组件 | 描述 | 字符数 | ASCII表示 |
|---|---|---|---|
| Start | 消息开始 | 1 CHAR | : |
| Address | 节点address(hexadecimal表示) | 2 CHARS | |
| Function | function code(hexadecimal表示) | 2 CHARS | |
| Data | data(根据function code变化,hexadecimal表示) | n CHARS | |
| LRC CHECK | 纵向冗余检验码(LRC) | 2 CHARS | |
| END | 消息End,回车换行 | 2 CHARS | CRLF |
在 ASCII 模式下,Modbus 消息的每个部分都以特定的字符数和format出现,如下所示:
:AA BB CC...DD EE<CRLF>
:– 消息的开始符号。AA– 节点address,hexadecimal表示。BB– function code,hexadecimal表示。CC...DD– datafield,根据function code和需要传输的dataLength变化。EE– LRC 校验码,用于Error检测。<CRLF>– 消息的End符号,代表回车和换行(Carriage Return Line Feed)。

ASCII帧的传输状态

上面状态图可以得到的信息:
1)“空闲” 态是没有send和receivemessage要处理的正常状态。
2)每次receive到 “:” 字符表示新的message的开始。如果在一个message的receive过程中收到该字符,则当前地message被认为不完整并被丢弃。而一个新的receive缓冲区被重新分配。
3)检测到帧End后,Complete LRC 计算和检验。然后,分析address域以确定帧是否发往此设备,如果不是,则丢弃此帧。 为了减少receive处理time,address域可以在一接到就分析,而不需要等到整个帧End。
ASCII帧的message传输
由于ASCIImessage帧与RTUmessage帧有着很大的不同,ASCIImessage帧是有start和End标识符的,而RTU帧没有这样的标识。所以ASCIImessage帧的receive就简单方便多了,也不需要什么t3.5的帧间隔time。
但是呢,为了保证receive的message帧连续,还是可以约定字符间的传输time的。一般认为,message中的字符time间隔可以达到一秒,如果超过了这个time间隔,就认为发生了Error,要废弃掉这一帧messagedata,重新开始receive。
function code
ASCII 模式下最常用的Function代码与 RTU 模式下的Function代码定义相同。以下是一些基本的function code及其描述:
| 访问address | 映射address | 描述 | Function | 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传输示例
例如,要读取address 0x20C1 的两个register,需要send以下 ASCII 消息:
:010420C1000218<CRLF>
Request:
:– 消息开始 – 0x3A01– slave address – 0x0104– function code (Read input register) – 0x0420C1– 要读取的register address – 0x20C10002– 要读取的registerLength (必须是 2) – 0x000218– LRC 校验码<CRLF>– 消息End,回车换行 – 0x0D0A
Response:
:01040400001234B1<CRLF>
Response:
:– 消息开始 – 0x3A01– slave address – 0x0104– function code (Read input register) – 0x0404– 读取dataLength (4 bytes) – 0x0400001234– 从 VAR1 读取的值 – 0x00001234B1– LRC 校验码<CRLF>– 消息End,回车换行 – 0x0D0A
常用function codeOperation
以下是 Modbus 的常用function code及其Request和Response示例:
Function 01(01H)读线圈
- Request:读取从机中线圈的 ON/OFF 状态。

- Response:Coil statusResponse消息被打包为datafield的每比特表示一个线圈。

Function 02(02H)读离散输入
- Request:读取从机中离散输入的 ON/OFF 状态。

- Response:离散input stateResponse消息的构造与Coil status相同。

Function 03(03H)读保持register
- Request:读取从机中保持register的binary内容。

- Response:保持register data在每个register中打包为两个byte。

Function 04(04H)读输入register
- Request:读取从机中输入register的binary内容。

- Response:读输入register data的Response消息的构造与Read and hold register相同。

Function 05(05H)写单线圈
- Request:将单个线圈写入 ON 或 OFF。

- Response:正常的Response是Request的回显。

Function 06(06H)写单个保持register
- Request将一个值写入单个保持register中。当广播时,该函数在所有附加的从机上设置相同的register引用。Request消息指定要写入的register引用(指定address和numerical value)。

- Response

Function 15(0FH)写多个线圈
- Request:将一个线圈Sequence中的每个线圈写入 ON 或 OFF。

- Response:正常Response返回从address、Function代码、starting address和写入的线圈quantity。

Function 16(10H)写多个保持register
- Request:将值写入到一个保持registerSequence中。

- Response:正常Response返回从address、Function代码、starting address和写入的number of registers。

LRC verification
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;
}
发表回复