从对硬件一点不懂得小白,一点点探索实现功能,感觉对硬件的开发有一点点的心得,记录下来。
本次主要实现的功能如下:
1.传感器可以探测土壤的温度,湿度,盐分,电导率,ph值等数据
2.数据可以实时传送到后台平台
3.数据可以在app上显示并可以在app中控制传感器等可控设备(例如:伸缩杆)
采购设备如下:
有人的:温度传感器(探测温度 湿度 盐分 电导率 485通信)
有人的:ph值传感器(探测ph值 485通信)
有人的:网络io 424设备(进行数据的转发和解析)
其他牌的:伸缩杆(主要是绑定传感器,可以插入土壤中,探测数据,然后收回)
设备的连接:
温度传感器 ph值传感器 伸缩杆 都是连接在网络io上的,通过网络io来与后台进行数据的交互,
后台发送指令由网络io设备解析并转发,最后返回数据给后台服务器。
具体如何连接,每个设备都有说明书。
实现步骤如下:
1.通过socket编程监听端口,给设备提供连接,设备在配置好远程的服务器ip和端口,然后重启之后会自动连接远程服务器,连接成功后会建立长连接。
2.创建读线程,和创建写工具类
3.定时通过modbus协议向设备发送命令,然后获取数据存放在map中,因为功能小,所以放map中,没有存放数据库中
4.前台页面实时获取后台数据展示
MODBUS-RTU报文
一.modbus报文模型
这里两个缩略词以前不知道,但是现在要明白指的是什么,“ADU”“PDU”
ADU: 应用数据单元
PDU: 协议数据单元
报文格式:
设备地址 | 功能码 | 起始寄存器地址高8位 | 读取的寄存器数高8位 | 低8位 | CRC校验低8位 | CRC校验高8位 |
---|---|---|---|---|---|---|
8bit | 8bit | 8bit | 8bit | 8bit | 8bit | 8bit |
先来简单分析一条MODBUS-RTU报文,例如:01 06 00 01 00 17 98 04
0x01 | 06 | 00 01 | 00 17 | 98 04 |
---|---|---|---|---|
从机地址 | 功能号 | 数据地址 | 数据 | CRC校验 |
这一串数据的意思是:把数据 0x0017(十进制23) 写入 1号从机地址 0x0001数据地址。
先弄明白下面的东西。
1.报文
一个报文就是一帧数据,一个数据帧就一个报文: 指的是一串完整的指令数据,就像上面的一串数据。
2、CRC校验
意义:例如上面的 98 04 是它前面的数据(01 06 00 01 00 17)通过一算法计算出来的结果,其实就像是计算累加和那样。(累加和:就是010600010017加起来的值,然后它的算法就是加法)。
作用:在数据传输过程中可能数据会发生错误,CRC检验检测接收的数据是否正确。比如主机发出01
06 00 01 00 17 98 04,那么从机接收到后要根据01 06 00 01 00 17 再计算CRC校验值,从机判断自己计算出来的CRC
校验是否与接收的CRC校验(98 04主机计算的)相等,如果不相等那么说明数据传输有错误这些数据不能要。
CRC校验网址:http://www.ip33.com/crc.html
3、功能号
意义:modbus 定义。
作用:指示具体的操作。
常用功能号:见下面
我们是要两个设备通讯,用的是MODBUS协议。上面简单介绍了:“报文”“CRC校验”“功能号”。
二.报文数据模型
三.一个报文分析
在单片机中拿出一部分内存(RAM)进行两个设备通讯,例如:
数组后面的注释,说明
OX[20] 代表是输出线圈,用功能码 0x01,0x05,0x0F 访问, 开头地址是 0
IX[20] 代表是输入线圈,用功能码 0x02 访问, 开头地址是 1
另外两个一样的道理。
注意:所谓的“线圈”“寄存器”就是“位变量”“16位变量”,不要被迷惑。之所以称“线圈”我觉得应该是对于应用的设备,MODBUS协议是专门针对485总线设备(例PLC)开发的。
四.主机对从机写数据操作
如果单片机接收到一个报文那么就对报文进行解析执行相应的处理,如下面报文:
0x01 | 06 | 00 01 | 00 17 | 98 04 |
---|---|---|---|---|
从机地址 | 功能号 | 数据地址 | 数据 | CRC校验 |
假如本机地址是 1 ,那么单片机接收到这串数据根据数据计算CRC校验判断数据是否正确,如果判断数据无误,则结果是:
HoldDataReg[1] = 0x0017;
MODBUS主机就完成了一次对从机数据的写操作,实现了通讯。
五.主机对从机读数据操作
主机进行读HoldDataReg[1] 操作,则报文是:
0x01 | 03 | 00 01 | 00 01 | D5 CA |
---|---|---|---|---|
从机地址 | 功能号 | 数据地址 | 读取数据个数 | CRC校验 |
单片机接收到这串数据根据数据计算CRC校验判断数据是否正确,如果判断数据无误,则结果是:返回信息给主机,返回的信息也是有格式的:
从机对主机返回内容
0x01 | 03 | 02 | 00 17 | F8 4A |
---|---|---|---|---|
从机地址 | 功能号 | 数据字节个数 | 两个字节数据 | CRC校验 |
这样MODBUS主机就完成了一次对从机数据的读操作,实现了通讯。
六.常用功能码
数据类型 | 读功能码 | 写功能码 | 对象类型 | 访问类型 |
离散量输入 | 02 |
| 单个位 | 只读 |
线圈状态 | 01 | 05,15 | 单个位 | 读写 |
输入寄存器 | 04 |
| 16位比特字 | 只读 |
保持寄存器 | 03 | 06,16 | 16位比特字 | 读写 |
七.寄存器起始地址(起始数据地址)
数据类型 | 参数地址,寄存器编号 |
离散量输入 | 00001~0FFFF |
线圈状态 | 10001~1FFFF |
输入寄存器 | 30001~3FFFF |
保持寄存器 | 40001~4FFFF |
举例:
Modbus协议中寄存器地址从1开始,而实际存储中地址从0开始。假如要读取寄存器编号为40005(4为块编号,5为modbus中寄存器地址)的寄存器的数据,则应把0004放入报文的地址域。
八.报文实例
1、读40005、40006两个寄存器,假设从机地址为1
下行报文:01 03 00 04 00 02 85 ca
从机地址 | 功能码 | 寄存器起始地址 | 读取寄存器个数 | CRC校验 |
01 | 03 | 00 04 | 00 02 | 85 ca |
上行报文:01 03 04 00 00 00 00 21 33
从机地址 | 功能码 | 返回字节个数 | 寄存器40005数据 | 寄存器40006数据 | CRC校验 |
01 | 03 | 04 | 00 00 | 00 00 | 21 33 |
2、向40005寄存器中写入0x12,0x34,假设从机地址为1
下行报文:01 06 00 04 00 01 12 34 4a b0
从机地址 | 功能码 | 寄存器起始地址 | 读取寄存器个数 | 要写入的数据 | CRC校验 |
01 | 06 | 00 04 | 00 01 | 12 34 | 4a b0 |
上行报文:01 06 00 04 00 01 12 34 4a b0
从机地址 | 功能码 | 寄存器起始地址 | 读取寄存器个数 | 写入的数据 | CRC校验 |
01 | 06 | 00 04 | 00 01 | 12 34 | 4a b0 |