资讯详情

Modbus协议完全资料与程序解析

1简述,modbus是一种工业用的多设备之间的主从通信协议。只要两台设备之间,是采用modbus协议的主从关系,并连接到相同网络,即可互相通信。因为Modbus只是协议,而且只规定了数据帧,底层连接,可以是232,485或者以太网。设备一般采用232和485进行通信,因为成本低。当然要是考虑远距离传输和多卖钱的话,也会采用以太网,不过应该就会相应复杂一些了。 2模式,modbus有两种模式,一种叫 RTU模式,另一种叫 acsii模式,RTU模式是纯二进制的,而acsii模式,一个信息中的每8位字节作为2个ascii字符传输的,这种模式的主要优点时允许字符之间的时间间隔长达1秒,也不会出现错误。而较acsii模式,RTU模式的优点是用最少的字节,表达更多的内容。但同时也要求设备必须连续传输。 3通讯,modbus属于 主从通讯,可以是一主一从或者一主多从。通讯的方式为主机向从机发送命令(或者叫请求)从机向主机发送响应。主机不发送,从机不返回,一发,一收,不发不收。而且一个时间,只有一个机器发送请求或者响应,否则的话,则会出错。 4信息帧,由于项目上没有涉及到acsii模式,所以本文只讨论RTU模式,不讨论acsii模式,以后如果要是用的上,肯定会继续讨论。用不上,就不讨论了。RTU帧,开始时,必须要有3.5个静止的时间,也就是时间间隔,用来区分上一帧和下一帧,如果没有时间间隔的话,则会分辨不出哪里是帧开始,哪里是帧结束了。3.5个时间间隔依据波特率不同而不同。同样,结束时也需要时间。除了时间以外,还有 地址,功能码,数据, crc校验四个部分,每个部分的字节数不同,地址功能码各1个字节,crc是2个字节其完整表达如下:
开始 地址 功能 数据 校验 结束
3.5t 1字节 8b 1字节 8b n字节 n*8b 2字节16b 3.5t
4.1、地址:主要用于区分从机,在下位机程序中,的宏定义中设置不同的从机地址。 #define Modbus_addr0x01 设备响应时,第一位也是本机地址。地址的范围是从0-247,地址0为广播地址,所有机器均可以识别。 4.2、功能码:表示主机要命令这个设备的什么功能,执行什么程序。我看了一下正规的modbus的功能码多达24个, 不同厂家生产的不同型号的设备,可能会支持不同的功能码,所以买之前需要注意一下。具体功能如下: 01 读线圈状态 02 读输入状态 03 读保持寄存器 04 读输入寄存器 05 强制单个线圈 06 预置单个寄存器 07 读不正常状态 08 诊断 09 程序484 10 查询484 11 通讯事件控制 12 通讯事件记录 13 程序控制器 14 查询控制器 15 强制多个寄存器 16 预置多个寄存器 17 报告从机id 18 程序884/M84 19 通讯链路复位 20 读通用参考值 21 写通用参考值 22 Mask Write 4X Register 23 Read/Write 4X Registers 24 Read FIFO 队列 虽然看着功能很多,但实际上有用的,只有01 02 03 04 05 06 15 和16功能码。 4.3、数据区,根据功能码的不同数据的长度是不同的。 4.4、crc校验 包含两个字节,发送端发送时,一帧的所有数据统一计算出一个crc校验码,然后加在一帧的最后两位中,然后等到发送到接收端时接收端重新计算一次除最后两位的一帧所有数据,然后根据两个数据的对比,来判断接收到的数据是否正确。 5、程序,以下位机为程序对象,主要使用c语言编写,首先,先从变量入手,既然modbus接受以帧为单位,所以就要设置两个缓冲区,用来接收数据,我们这里使用数组来存储接收来的数据 Modbus_send_buf[Modbus_max_send_buf];//数据发送缓冲 和 Modbus_recevie_buf[Modbus_max_recevie_buf];//数据接收缓冲 ,其中 Modbus_max_send_buf,和 Modbus_max_recevie_buf ,为宏定义,这样可以方便的修改一帧最大的存储数据。有了发送接收缓冲,就可以写中断函数了,进入中断后,首先做一些必要的工作,清ES ,判断 ,清IR,做完后,就可以开始接收数据了,但有个问题?如果设备处于空闲状态,那么接收数据后按命令执行,但如果当设备正在执行指令的时候,则不应该再继续的接收指令,那样的话,会让程序进入混乱状态。所以要在基础工作做完后,增加一个判断,来确定设备的忙闲。 if((Modbus_cmd_flag == 0) && (Modbus_exe_flag == 0)),判断完以后就可以继续下面的工作了。如果通讯中包含奇偶校验的话,那么则判断奇偶校验。下面就是接收数据。 Modbus_recevie_buf[Modbus_recevie_count] = SBUF; ,将接收来的数据存入数组并记录存入的数据个数 Modbus_recevie_count,由于modbus是通过时间来判断一帧的结束的,所以在程序中,必须要有一个定时器函数,这个定时器用来判断程序是正在接受,还是已经接受完成了。所以中断的最后所做的是 自加 Modbus_recevie_count++;,定时器清0 Modbus_timeout_cnt = 0; ,将设备状态转入接收状态 Modbus_recevie_flag = 1;。此时,串口中断的工作就完成了。 下面开始分析定时器,定时器的目的其实就1个,判断一帧是否接收完毕,如果完毕,则进入下一步。在定时器中断函数中,首先要对定时器值进行初始化,这个就不多说了,然后是判断程序是否处于接受状态 if(Modbus_recevie_flag == 1),这个状态只有在串口中断函数中才会被置位,其他的情况不会被置位。若程序不是接收状态,则直接跳出定时器中断,若程序处于接收状态,则定时计数自加 Modbus_timeout_cnt++;,自加后进入判断 if(Modbus_timeout_cnt >= Modbus_max_timeout_cnt),判断的值即为modbus接收一帧传输完成所需要的时间间隔。至于是多少时间,可以通过修改 Modbus_max_timeout_cnt来确定。可以将定时器终端设置为1ms1次,在9600的情况下将超时时间设为4, #define Modbus_max_timeout_cnt 4,这样如果串口中断不在接收数据时,定时计数将不会清0,当到达设定的超时时间后即判断接收结束,转向命令解析状态。
锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台