树莓派通过TTL3.3转485 Modbus采集水表

所需道具

  1. 树莓派,我用的是树莓派zero wh;
  2. 具有光电直读功能的有线水表,我用的是咸鱼淘的埃美柯 LXSY-20E1;
  3. TTL3.3 转 485模块,带隔离的贵些;
  4. 5V转12V升压模块。

原理

    树莓派有UART(GPIO14 Tx 和 GPIO15 Rx)串口通讯功能,电器特性是3.3V TTL,直读远传水表支持M-Bus/485通讯接口,我买的光电直读水表485要求12V供电(根据仪表厂家说明书)。TTL和485虽然都是串口通讯,但电器特性不一样,不能直接接!我已经烧掉一个树莓派0了,切记。

接线

  1. 树莓派GRIO14 Tx针脚接TTL转485模块的Tx,GPIO15 Rx接Rx;
  2. TTL转485模块的A+接水表485+(黄线或白线),B-接水表485-(蓝线或绿线);
  3. 树莓派3.3V和GND针脚接TTL转485模块,给模块供电,万用表测模块电压;
  4. 树莓派5V和GND针脚分别接升压模块IN+和IN-(GND),给升压模块供电,万用表测升压模块OUT+、OUT-电压;
  5. 升压模块供电OUT+、OUT分别接水表的红线、黑线。

python代码

    根据水表Modbus规约,读数的格式为 01 03 00 00 00 02 C4 0B,01 为表地址,根据水表厂家说明书,或者从0开始到255轮询;03为Modbus读寄存器命令;00 00为数据起始地址;00 02为读2个字,即4个字节;C4 0B为CRC16校验码。另外,读取到的数据要根据水表的说明书乘以倍率,我的要乘以0.01。

    python代码如下(没有优化,欢迎大家改进分享)。

import sys, time, math, serial ,struct
import RPi.GPIO as GPIO

def crc16(x):
	a = 0xFFFF
	b = 0xA001
	for byte in x:
		a ^= byte
		for i in range(8):
			last = a % 2
			a >>= 1
			if last == 1:
				a ^= b

	return (0x00FF & a)*256 + (0xFF00 & a)/256

def modbusEncode(address, words=1):
	sendbuf = [address,0x03,0x00,0x00,0x00,words]
	crc = crc16(sendbuf)
	sendbuf.append((0xFF00 & crc)>>8)
	sendbuf.append(0x00FF & crc)
	print(sendbuf)
	return sendbuf

def readFlux(usart, address):
	sendbuf = modbusEncode(address,2)
	usart.write(sendbuf)
	recvbuf = bytearray(usart.read(9))
	if len(recvbuf)==9:
		b3 = int(recvbuf[3])
		b2 = int(recvbuf[4])
		b1 = int(recvbuf[5])
		b0 = int(recvbuf[6])
		result = (b3<<24) |(b2<<16) |(b1<<8) | b0
		return result*0.01
	return 0

if __name__ == "__main__":
	port="/dev/ttyAMA0"
	usart=serial.Serial(port,9600,timeout=5)
	usart.flushInput()
	while(True):
		print(readFlux(usart,0))#0为表地址,要根据水表地址修改.
		time.sleep(1)
	GPIO.cleanup()

  

猜你喜欢

转载自blog.csdn.net/xhydongda/article/details/109443775
今日推荐