Modbus 有两种通信传输方式,一种是 ASCII 模式,一种是 RTU 模式。由于 ASCII 模式的数据字节是 7bit 数据位,51 单片机无法实现,而且应用也相对较少,所以这里我们只用 RTU 模式。两种模式相似,会用一种另外一种也就会了。一条典型的 RTU 数据帧如图18-5 所示。、

      

freemodbus两个串口都做从机 串口发送modbus协议_单片机


          和我们实用串口通信程序类似,我们一次发送的数据帧必须是作为一个连续的数据流进行传输。我们在实用串口通信程序中采用的方法是定义 30ms,如果接收到的数据超过了30ms 还没有接收到下一个字节,我们就认为这次的数据结束。而 Modbus 的 RTU 模式规定不同数据帧之间的间隔是 3.5 个字节通信时间以上。如果在一帧数据完成之前有超过 3.5 个字节时间的停顿,接收设备将刷新当前的消息并假定下一个字节是一个新的数据帧的开始。同样的,如果一个新消息在小于 3.5 个字节时间内接着前边一个数据开的,接收的设备将会认为它是前一帧数据的延续。这将会导致一个错误,因此大家看 RTU 数据帧最后还有16bit 的 CRC校验。
         起始位和结束符:图 18-5 上代表的是一个数据帧,前后都至少有 3.5 个字节的时间间隔,起始位和结束符实际上没有任何数据,T1-T2-T3-T4 代表的是时间间隔 3.5 个字节以上的时间,而真正有意义的第一个字节是设备地址。

        设备地址:很多同学不理解,在多机通信的时候,数据那么多,我们依靠什么判断这个数据帧是哪个设备的呢?没错,就是依靠这个设备地址字节。每个设备都有一个自己的地址,当设备接收到一帧数据后,程序首先对设备地址字节进行判断比较,如果与自己的地址不同,则对这帧数据直接不予理会,如果如果与自己的地址相同,就要对这帧数据进行解析,按照之后的功能码执行相应的功能。如果地址是 0x00,则认为是一个广播命令,就是所有的从机设备都要执行的指令。

        功能代码:在第二个字节功能代码字节中,Modbus 规定了部分功能代码,此外也保留了一部分功能代码作为备用或者用户自定义,这些功能码大家不需要去记忆,甚至都不用去看,直到你有用到的那天再过来查这个表格即可,如表18-1 所示。

  

freemodbus两个串口都做从机 串口发送modbus协议_Modbus协议_02

freemodbus两个串口都做从机 串口发送modbus协议_单片机_03

freemodbus两个串口都做从机 串口发送modbus协议_工业现场总线协议_04





         我们程序对功能码的处理,就是程序来检测这个字节的数值,然后根据其数值来做相应的功能处理。

         数据:跟在功能代码后边的是 n 个8bit的数据。这个 n 值的到底是多少,是功能代码来确定的,不同的功能代码后边跟的数据数量不同。举个例子,如果功能码是 0x03,也就是读保持寄存器,那么主机发送数据 n 的组成部分就是:2 个字节的寄存器起始地址,加 2 个字节的寄存器数量 N*。从机数据 n 的组成部分是:1 个字节的字节数,因为我们回复的寄存器的值是 2 个字节,所以这个字节数也就是 2N*个,再加上 2N*个寄存器的值,如图 18-6 所示。

    

freemodbus两个串口都做从机 串口发送modbus协议_freemodbus两个串口都做从机_05


        CRC 校验:CRC 校验是一种数据算法,是用来校验数据对错的。CRC 校验函数把一帧数据除最后两个字节外,前边所有的字节进行特定的算法计算,计算完后生成了一个 16bit的数据,作为 CRC 校验码,添加在一帧数据的最后。接收方接收到数据后,同样会把前边的字节进行 CRC 计算,计算完了再和发过来的 CRC 的 16bit 的数据进行较,如果相同则认为数据正常,没有出错,如果比较不相同,则说明数据在传输中发生了错误,这帧数据将被丢弃,就像没收到一样,而发送方会在得不到回应后做相应的处理错误处理。

          RTU 模式的每个字节的位是这样分布的:1 个起始位、8 个数据位,最小有效位先发送、1 个奇偶校验位(如果无校验则没有这一位)、1 位停止位(有校验位时)或者 2 个停止位(无校验位时)。