工控智汇

工控智汇

modbus10分钟搞懂

admin 158 76

1.先谈谈我们怎么应用


这是一个普通单片机进行的MODBUS输入输出控制,可以应用在任何需要读取或者控制的硬件厂商,解决上位机与硬件通讯的问题,如果通过转换网关实现远端控制,云端控制等。

输入输出接线与功能描述:

输出部分:NC(常关)COM(公共脚)N0(常开)

负载220V10A建议在220V6A以下

1.只是一个开关的关闭与断开,没有任何电压输出。

2.只能通过485通讯发指令来控制继电器的开启与关闭。

3.默认情况NCCOM是接通的,当485发送开启指令的时候

NC与COM断开,NO与COM接通。反之。

输入部分:IN1接开关或者电压信号(3V-30V),

1.只能通过电脑读取开关量的状态,不能控制继电器,如果需要能控制继电器跟店家沟通。

2.IN1接开关(无电压信号):IN1接VCC电脑去取为1否则为0

通信协议

ModbusRTU指令

波特率:96008NONE1

16进制发送16进制接收

操作步骤:1.软件选择通讯波特率2.设置地址(通讯使用的设备地址,默认地址为01)/*******************************************************************/

注意:只接一个设备,否则地址都会被设置。设置地址为:010010000000010200016A00//修改成01设置地址为:020010000000010200022A01//修改成02设置地址为:03001000000001020003EBC1//修改成03

读取地址00030000000185db返回:00030200014444//01为地址

/*******************************************************************//*******************************************************************/各字节代表的意义:[1号地址]//--------------------------------------------1号继电器开启:0105000101009d9a

字节1:地址字节2:功能吗字节34:寄存器地址字节56:寄存器数据字节78:CRC校验

//==============================================================[1号地址]//--------------------------------------------0号继电器开启:01050000FF008C3A0号继电器关闭:010500000000CDCA//--------------------------------------------1号继电器开启:01050001FF00DDFA1号继电器关闭:0105000100009C0A//-------------------------------------------2号继电器开启:01050002FF002DFA2号继电器关闭:0105000200006C0A//-------------------------------------------3号继电器开启:01050003FF007C3A3号继电器关闭:0105000300003DCA//-------------------------------------------4号继电器开启:01050004FF00CDFB4号继电器关闭:0105000400008C0B//--------------------------------------------5号继电器开启:01050005FF009C3B5号继电器关闭:010500050000DDCB//-------------------------------------------6号继电器开启:01050006FF006C3B6号继电器关闭:0105000600002DCB//-------------------------------------------7号继电器开启:01050007FF003DFB7号继电器关闭:0105000700007C0B//-------------------------------------------

/************************************************************************/读取0号继电器状态:010100000001FDCA读取1号继电器状态:010100010001AC0A读取2号继电器状态:0101000200015C0A读取3号继电器状态:0101000300010DCA读取4号继电器状态:010100040001BC0B读取5号继电器状态:010100050001EDCB读取6号继电器状态:0101000600011DCB读取7号继电器状态:0101000700014C0B

读取所有继电器状态:0101000000083DCC/***********************************************************************/闪开指令:说明:开启后马上关闭,100MS为一个单位[1代表100MS]

1号地址:0号继电器闪开:010502000700CE42//700MS=7*100MS=700MS1号继电器闪开:0105020108009A72//800MS返回:跟发送指令一样2号地址:0号继电器闪开:020502000500CF11//500MS1号继电器闪开:0205020106009E21//600MS

//======================================================================全灭:010F000000080100FE95全亮:010F0000000801FFBED5

/**********************************************************************/单一翻转指令:0号继电器翻转:010500005500F29A1号继电器翻转:010500015500A35A2号继电器翻转:010500025500535A3号继电器翻转:010500035500029A4号继电器翻转:010500045500B35B5号继电器翻转:010500055500E29B6号继电器翻转:010500065500129B7号继电器翻转:010500075500435B

全部翻转指令:010500005A00F76A

/*********************************************************************/读取所有接口输入状态发送:01020000000879CC//读取8个输入状态返回:01020100A188

那么我们根据上述功能及通信协议就可以开发对应的上位机

通过网关就可以做很多少事情

简单来说就是打通硬件最后一米

2、先聊聊“数据通信模型”

玩嵌入式的小伙伴们肯定是玩过各种通信方式和通信协议,因为我们所做的项目不是一个独立的个体,它需要跟外界交互,交互就需要有一套大家都遵守的东西那就是我们的协议,一般的与计算机有点关系的信息类专业,大学应该或多或少学过《计算机网络》这门课程,可以说计算机网络系统是一套非常完备的通信系统。我们今天的modbus协议的介绍肯定比他简单不知道多少倍,所以大家不要惊慌。不过我觉得说起通信一定不能缺少下面这个模型:


可以说几乎所有的通信方式都会基于该数据通信模型进行分层制定和开发。我们在前面的文章中的编程技巧也提到了这个模型,个人觉得它最大的特点就是分层,并且下层仅仅为上层提供服务,但是却只一个层面上的交互。(形象点说,就好打我们电话我们只在乎你说的话的内容,我们并不在乎我们所说的话是怎样通过电话和通信传递给对方的)

好了,我们平时在嵌入式中经常遇到的串行数据通信,比如串口通信,SPI,IIC,CAN等等,他们都属于上面模型中的数据链路层和物理层,可能很多小伙伴们自己制定了简单的通信协议,那么可以说直接从用户层--数据链路层--物理层进行传输,中间层基本上就没有了。所以说我们可抽取其中的几个层面来进行我们通信协议的设计。

3、通信的本质(纯粹个人理解)

通信的本质我觉得就是沟通嘛。那么在我们编程中我们可以叫做"交换数据",比如说我把数据传给你,你接受到处理以后把我想要的数据传给我,就这么简单。我们也知道大部分信号都是电信号,然后我们去看电信号来对应数据吗?电信号数据无非就是0和1,可以对应着我们程序的二进制文件,有点难懂,既然传输的是数据我们如果能够用8bit-byte的形式来表示那就最好了。那我们在程序中接受到数据直接就可以拿来使用了。

对于SPI,IIC等这类通讯方式,我们就认为在传byte就行了,我们在以后的项目开发中我们经常会遇到通信FIFO来进行缓冲(所以我之前写了一篇《无数据类型的队列实现》是非常有用的),最终解析数据的话基本上都是去FIFO中取数据进行解析,所以用如下图模型(大家好像叫字节流-那么就叫"字节流模型")再好不过了。对于CAN这种一次性发送多个byte的通信方式,虽然有特殊的处理的通信协议,不过我们完全可以转化为如下图所示的方式进行数据解析和处理。(只是说我们可能会考虑到传输效率和应用等会开发出新的通信协议)


4、超级简单的Modbus协议

根据我们第二小节所说的字节流模型,我们知道数据都是1个bye一个byte传输的,我们只要规定好每个byte代表什么意思,然后把byte组合起来是不是发送方也接受方都懂了?那么规定这些byte意思的就是我们的协议-协议完全可以自己定,不过我们这里今天选用了一种应用非常广泛的modbus协议来供大家学习和参考。一方面可以参考协议如何制定,以后可以直接模仿创造自己新的协议,另一方面可以积累一些设计上的经验。好了,下面开始我们的modbus协议的讲解:(这里我不可能把modbus协议全面的为大家讲解,也没有必要,因为很多东西都是重复的,只要大家理解查查modbus协议手册分分钟的事情)

1)介绍modbus协议核心

modbus协议是一种请求/应答的协议。说白了就是一问一答。可能小伙伴们会问,主机向从机写数据也是问吗?是的,比说说:我问你123456789收到没?你回答说接受到了123456789.下面为大家展示一下modbus一些的核心:


modbus的核心就是由这样四个区域的byte组成的数据包来进行相互传输相互交互的。

地址:(占用1byte)modbus通信总线上有非常多的设备,并且其总线上只有一个主机,就好像一间教室里面一个老师正在发作业本一样,老师会根据学生的名称(也就是该地址)发送对应的作业本给学生,而学生写完作业以后也会填上字节的名字进行上交。并且这些地址肯定是唯一的标识,因为我们modbus协议还不能像老师一样能够根据外表来同名区分。(总结:如果该数据包是主机发送,那么地址就是对应从机的地址,如果该数据包是从机的上报,那么该地址就是从机的地址)

功能码:(占用1byte)字面上的意思就是区分不同的数据帧的类型,其实modbus协议就是通过不同的功能码定义了数据部分的不同格式,从而实现了多种传输功能。所以modbus的功能码特别多,不够我总结了一下基本上就是读数据和写数据,只是说形式上分得更多了点,我们只要根据modbus协议上规定的方式进行填充即可。后面我会举例说明。

数据:(根据功能码占用多个byte)根据功能码的不同,不同的byte代表不同的意思。

校验:(占用2byte)为了保持数据的稳定性,尽量避免在通讯过程中的数据错乱,就好比把前面的数据进行求和然后放在该区域发送出去。只是说modbus协议使用更加优秀的CRC校验(前面我也发表过CRC校验的文章,CRC校验分很多类型,在数据校验中经常使用)

说了很简单吧,下面我以一个功能码为大家进行具体的讲解:(其他功能码和一些注意事项都可以在modbus的详细协议文档中找到答案)

2)modbus协议功能码实例

我们以功能码:0x04为例,下面完全满足我们上面的格式(其中数据区位于功能码和校验之间)

发送方地址功能码起始地址输入寄存器数量校验


注意:1)modbus中的地址和数据都是大端模式,也是就是说高字节先传,比如地址2byte分别是0x1122,那么发送字节流的时候先发0x11然后放0x22。

2)上面接受方接受到数据,会判断功能码,字节数输入寄存器个数等等,是否在正确的范围,如果都满足要求,就以接受方(success)的数据格式正确的返回数据,如果检查有问题就会以接收方(Fault)的格式把0x04+0x80作为功能码,然后确定好异常的类型(在modbus标准协议中有说明)然后进行发送。

3)其他的功能码都是类似的,并且Modbus协议是一种不依赖物理通讯的通信协议!大家可以根据自己实际的项目进行改造。