STM32移植FreeModbus RTU教程1(ModbusRTU协议说明 )
STM32移植FreeModbus RTU从机教程1(ModbusRTU协议简要说明)
ModbusRTU说明
Modbus 协议是应用于电子控制器上的一种通用语言, 实现控制器之间、控制器由网络和其
它设备之间的通信,支持传统的RS232/RS422/RS485 和最新发展的以太网设备,最常用的是
TIA/EIA-485 (RS485) 两线制接口。它已经成为一种通用工业标准。有了它, 不同厂商生产的控制设备可以连成工业网络, 进行集中控制。此协议定义了一个控制器能认识使用的消息结构。
Modbus 协议是一种请求——应答方式的协议。
有两种串行传输模式分为ASCII与RTU两种模式,通常使用RTU(Remote Terminal Unit)模式。
RTU模式特点及基本术语、公共功能码
-
RTU模式特点:
① 消息中每个8bit 字节包含两个4bit 的十六进制字符,因此,在波特率相同的情况下,传输效率比ascii 传输方式大
② 1 个起始位、8 个数据位、1 个奇偶校验位和1 个停止位(或者两个停止位)
③ 错误检测域是CRC 检验
④ 消息发送至少要以3.5 个字符时间的停顿间隔开始。整个消息帧必须作为一连续的流传输。如果在帧完成之前有超过1.5 个字符时间的停顿时间, 接收设备将刷新不完整的消息并假定下一个字节是一个新消息的地址域。同样地, 如果一个新消息在小于3.5 个字符时间内接着前个消息开始,接收的设备将认为它是前一消息的延续。1.5~3.5 个字符间隔就算接收异常,只有超过3.5 个字符间隔才认为帧结束。 -
基本术语 ,字word 、字节byte 、位bit
1 word = 2 byte;
1 byte = 8 bit.;
CRC校验码:校验码是由前面的数据通过某种算法得出的,用以检验该组数据的正确性。 -
公共功能码及相关寄存器地址:
MODBUS 数据模型有四种,通过不同的功能码来读写这些数据对象。
对象类别 | 对象类型 | 访问类型 | 内容说明 |
---|---|---|---|
离散量输入 | 单个bit | 只读 | 相当于开关量,每个bit对应一个开关信号状态(只能读取输入的开关量,无法通过应用程序进行更改,列如读取外部拨码开关的值。) |
线圈 | 单个bit | 读写 | 相当于开关量,每个bit对应一个开关信号状态(可进行读写,列如通过1byte可控制8个IO口输出高低电平,此8个IO口电平可控可读) |
输入寄存器 | 16bit | 只读 | I/O 系统提供这种类型数据(无法通过应用程序进行更改的外部设备模拟量数据,如温度、气体浓度值等) |
保持寄存器 | 16bit | 读写 | 通过应用程序改变这种类型数据(例如可通过应用程序进行读写的当前设备RTC时钟值、设备运行模式等。) |
常用的功能码有:01H、02H、03H、04H、05H、06H、0FH、10H。
但在实际应用中, 厂家通常会根据实用性做些变通,但并不影响数据的读写,如当前设备开关量较少的情况下,将离散量输入值(如读取到的拨码开关8421码)归入04H输入寄存器中,将线圈开关量(输出高低电平控制继电器的通断)读写归入03H 06H 10H保持寄存器中。
最常用的功能码有:03H、04H、06H、10H。
Modbus 协议定义的寄存器地址是5 位十进制地址,即:
线圈( DO)地址: 00001~09999
触点( DI)地址: 10001~19999
输入寄存器( AI)地址: 30001~39999
输出寄存器( AO)地址: 40001~49999
由于上述各类地址是唯一对应的,因此有些资料就以其第一个数字区分各类地址,
即: 0x 代表线圈( DO)类地址, 1x 代表触点( DI)类地址、3x 代表输入寄存器( AI)类地
址、4x 代表输出寄存器( AO)类地址。
在实际编程中, 由于前缀的区分作用, 所以只需说明后4 位数, 而且需转换为4 位十六进制地址。*
Modbus 协议中寄存器地址从1 开始,而实际存储中地址从0 开始。
计算公式为:实际报文寄存器地址(16进制) = PLC地址位低四位(10进制) - 1;
如要读取寄存器编号为40005 (4 为块编号, 5 为modbus 中寄存器地址)的寄存器的数据,则应把00 04 放入报文的地址域。
功能码 | 描述 | 寄存器编号(10进制) | 实际报文寄存器地址(16进制) |
---|---|---|---|
01H | 读线圈寄存器 | 00001~09999 | 0x0000~0xFFFF |
02H | 读离散量输入寄存器 | 10001~19999 | 0x0000~0xFFFF |
03H | 读保持寄存器 | 40001~49999 | 0x0000~0xFFFF |
04H | 读输入寄存器 | 30001~39999 | 0x0000~0xFFFF |
05H | 写单个线圈寄存器 | 00001~09999 | 0x0000~0xFFFF |
06H | 写单个保持寄存器 | 40001~49999 | 0x0000~0xFFFF |
0FH | 写多个线圈寄存器 | 00001~09999 | 0x0000~0xFFFF |
10H | 写多个保持寄存器 | 40001~49999 | 0x0000~0xFFFF |
MODBUS功能码与Modbus 协议定义的寄存器地址对应关系:
一般厂商的码表或者信息点表、地址映射表里面有相对地址(实际发送报文寄存器地址)及寄存器号(Modbus 协议定义的寄存器地址)的说明。
地址位00001-09999 用01H/05H/0FH功能码读写,报文寄存器地址(即相对地址)为0x0000~0xFFFF
地址位10001-19999 用02H功能码读取,报文寄存器地址(即相对地址)为0x0000~0xFFFF
地址位30001-39999 用04H功能码读取,报文寄存器地址(即相对地址)为0x0000~0xFFFF
地址位40001-49999 用03H/06H/10H功能码读取,报文寄存器地址(即相对地址)为0x0000~0xFFFF
4. 最常用功能代码报文格式说明:
功能码03H
描述:读保持寄存器。可读取单个或多个保持寄存器。报文格式如下+CRC校验低字节+CRC校验高字节
N=读取寄存器个数;
功能码04H
描述:读输入寄存器命令。该命令支持单个寄存器访问也支持多个寄存器访问。报文格式如下+CRC校验低字节+CRC校验高字节
功能码06H
描述:读输入寄存器命令。该命令支持单个寄存器访问也支持多个寄存器访问。报文格式如下+CRC校验低字节+CRC校验高字节
功能码10H
描述:写多个保持寄存器。报文格式如下+CRC校验低字节+CRC校验高字节
Modbus RTU通信报文格式
读数据:假如读40001 、40002 两个寄存器,假设从机地址为1
从机地址范围: 1~247,0 为广播地址,占一个字节。
理论上Modbus 协议可以接247 个从机,但若用于485 接口上则由于485 接口的限制,在没有中继情况下,最多可以接32 个从机。
下行报文:
从机地址 | 功能码 | 寄存器起始地址高字节 | 寄存器起始地址低字节 | 读取寄存器个数高字节 | 读取寄存器个数低字节 | CRC校验低字节 | CRC校验高字节 |
---|---|---|---|---|---|---|---|
0x01 | 0x03 | 0x00 | 0x00 | 0x00 | 0x02 | 0xC4 | 0x0B |
上行报文:
从机地址 | 功能码 | 返回数据字节数 | 05寄存器数据高字节 | 05寄存器数据低字节 | 06寄存器数据高字节 | 06寄存器数据低字节 | CRC校验低字节 | CRC校验高字节 |
---|---|---|---|---|---|---|---|---|
0x01 | 0x03 | 0x04 | 0x00 | 0x00 | 0x0B | 0xB8 | 0xFD | 0x71 |
写数据:假如向42001寄存器中写入数据 00 40,假设从机地址为1
下行报文:
从机地址 | 功能码 | 寄存器起始地址高字节 | 寄存器起始地址低字节 | 要写的数据高字节 | 要写的数据低字节 | CRC校验低字节 | CRC校验高字节 |
---|---|---|---|---|---|---|---|
0x01 | 0x06 | 0x07 | 0xD0 | 0x00 | 0x40 | 0x88 | 0xB7 |
上行报文:
从机地址 | 功能码 | 寄存器起始地址高字节 | 寄存器起始地址低字节 | 写入的数据高字节 | 写入的数据低字节 | CRC校验低字节 | CRC校验高字节 |
---|---|---|---|---|---|---|---|
0x01 | 0x06 | 0x07 | 0xD0 | 0x00 | 0x40 | 0x88 | 0xB7 |
从机若正常返回,则功能不变,若错误返回,则功能码的最高位为1,且从机会将一独特的代码(错误代码由厂家定义说明)放到回应消息的数据域中, 以便于告诉主设备发生了什么错误。主设备应用程序得到异议的回应后, 典型的处理过程是重发消息, 或者诊断发给从设备的消息并报告给操作员。如03 功能码,错误返回为83 。
设备异常返回信息(03功能码):01地址 + 03|0x80 + ErrCode + CRC
如下表某厂家设备的错误代码说明:
错误代码( ErrCode) | 内容 | 说明 |
---|---|---|
0x00 | 成功 | 没有错误 |
0x01 | 功能码错误 | 指定了不存在的功能代码。请确认功能代码。 |
0x02 | 寄存器地址错误 | 指定了指定功能代码不能使用的寄存器号地址。 |
0x03 | 数据值域错误 | 寄存器中被提交存储的数据项有一个应用程序期望之外的值 |
0x04 | 写入失败 | 正在设法执行请求的操作时,产生不可重新获得的差错。 |