近两周完成了MODBUS协议RTU格式的开发,包含了从站和主站的功能,算是完成一个简易版的MODBUS协议栈了,做个小结。
模式
MODBUS是一个工业应用层的消息协议,描述了不同总线或者网络上设备的一种主从交互的方式。协议包含了链路层与应用层的实现, 具体链路的我也不懂,没有深究。主要还是讲协议本身实现层面上的一些逻辑。
主从模式,就是请求都是主机发起,从机被动应答或者不答(广播时)一个机制。不问不答。由于MODBUS原先是针对总线结构而定义的,因此对带宽要求比较苛刻,挂在同一个总线上的设备不能很多,最多247台从机, 从机地址为1-247, 0作为广播地址, 248-255为保留地址。从机之间不会进行交互。每个地址在总线上只能有一台从机。
单播模式: 主机定位到一个独立的从机,向其发送请求。从机在接收处理完请求后,返回一个对应的响应给主机。
广播模式:主机发送一个广播包给总线上的所有从机,从机不需要响应。所有的从机需要接收广播的报文。
报文格式
协议层面,MODBUS定义了一个数据格式,简称PDU。格式为1个字节的功能码加数据。PDU前加一个字节的地址,后面加2个字节的CRC校验码,最终组成MODBUS的帧。
CRC是针对从地址开始到整个PDU来计算的。CRC有2个字节,低位在前,这样子接收端收到完整报文的时候,只要重新计算完整报文(包含CRC)的crc值为0就表示报文传输正确。
功能码指示了主机希望从机执行什么动作,随后的数据表示请求和响应的数据。
状态机
MODBUS状态机按数据链路分成了2层:
- 主从机状态机
- 数据接收状态机
数据帧的传输模式包含了RTU和ASCII两种模式。后面再说。
主机状态机
- IDLE状态,上电后处于这个状态,这个状态的适合没有任何进行中的请求。只有这个状态的时候,主机才能发送一个新的请求。同一个时刻,主机只会有一个进行中的请求,发送请求后,切换到另外的状态。
- “Waiting for reply”状态,当发送完一个单播的请求后,转为这个状态。主机开启一个超时等待响应。
- 接收到回应后,主机先进行校验。如果出现校验错误的话,状态不变更,继续等待超时。
- 如果直到超时都没有接收到正确的响应,主机会报超时错误,然后回到IDLE状态,重新发起请求。重试的次数可以配置。
- “Waiting Turnaround delay”状态,当发送完一个广播的请求后,转为这个状态,由于广播请求没有从机会进行响应,所以需要开启一个足够长的超时等待从机处理完请求。只有当超时后,再回到IDLE状态,开始另一个请求的发送。
- 一般单播超时设置为1s到几s的时长,波特率为9600bps时。Turnaround delay超时设置为100ms-200ms
协议层面的状态机比较简单,这边不需要考虑传输的细节。实际实现时,也要把两个状态机的逻辑分开来看。我在实现时,直接省略了Processing reply 和 error的状态,实际这两个状态可以只是一个中间的状态,合并到waiting for reply的处理逻辑里了。具体实现可以有一些取舍,我主要是为了快速处理响应,不等那么多个状态了。框架的缘故,调度的周期会比较长,而不是在一个死循环里面。
从机状态机
- IDLE状态表示没有接收到请求,也是上电后的初始状态。
- 当接收到一个请求后,首先进行报文的校验。按约定请求必须使主机发起的,没有什么机制可以确定正确性。
- 如果收到的是单播请求,从机需要在操作完成后,回应一个报文,告知主机执行的结果。
- 如果收到的帧错误,只的是crc校验出错,从机不会作任何动作。需要主机的超时重发机制来搞定。
- MODBUS可以有一些诊断的计数器,用于诊断错误原因,定位问题。可以通过特定的功能码来读取。
这里有一个主从机的交互时序图,可以清晰的看到各个流程。
传输模式
MODBUS传输模式有两种, RTU和ASCII码。不同的模式,每一个字节的内容含义是不一样的。同一条总线上交互的MODBUS设备需要采用相同的传输模式,否则就很难玩了。协议约定默认所有的MODBUS设备都是要实现RTU模式的, ASCII码模式作为一个备选方案。
- RTU模式,每个字节代表数据的一个8位十六进制内容, 0xab
- ASCII码模式, 每两个字节代表数据的一个8位十六进制内容, 每个字节分别代表一个字符。 类比上面的0xab, 需要两个字节, 分别存储’a’ 和‘b’两个字符。
RTU模式
RTU模式通过传输11bits的数据来确定最终传递的8位数字。
MODBUS的每一帧的开始和结束时通过字符传递间隔来确定的。帧与帧之间间隔至少3.5个字符时间。 同一帧之间的字符间隔不能超过1.5个字符时间,否则就认为这是一个错包。
RTU帧接收也有一个状态机,用于确定接收到一个完整的帧的。
ASCII码模式
ASCII模式下,帧的组成和RTU模式不一样。帧与帧之间的分隔是通过特定的字符来标识的。
具体的细节可以看官方的文档,就不细说了, 没有深究。
链路
MODBUS的链路主要是串行总线,也可以通过普通的以太网帧来封装,就是TCP-MODBUS,是另外的东东了。
我做的这个项目,是由串行总线来处理的。 有RS485和RS232两种。
END
总的来说, MODBUS是一个应用比较广泛的总线协议, 很多厂家会在其基础上进行自定义。具体的应用实现也会有不一样。 MODBUS还提供了应用层协议的约定。 可以通过官网获取具体的文档。各个文档讲的比较通俗易懂,反正我是看懂了。
官网地址 : https://modbus.org/
行动,才不会被动!
欢迎关注个人公众号 微信 -> 搜索 -> fishmwei,沟通交流。