这个周末我要做一个小项目。有一个太阳能电池逆变器(丹佛斯ULX 3600i),我将尝试连接到我的linux机器,看看我是否可以从中获取数据,为统计数据创造了多少能量。它上面有一个RJ45连接输入,但带有RS485。
我通过电脑中的usb端口将电缆连接到PC和逆变器之间的RS485转换器。
然后我编写一个小的python代码来发出请求。但是我无法弄清楚如何正确发送数据。
import serial
import struct
ser = serial.Serial(
port='/dev/ttyUSB0',
baudrate=19200,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS
)
print(ser.isOpen())
thestring = "7E FF 03 00 01 00 02 0A 01 C8 04 D0 01 02 80 00 00 00 00 8E E7 7E"
data = struct.pack(hex(thestring))
#data = struct.pack(hex, 0x7E, 0xFF, 0x03, 0x00, 0x01, 0x00, 0x02, 0x0A, 0x01, 0xC8, 0x04, 0xD0, 0x01, 0x02, 0x80, 0x00, 0x00, 0x00, 0x00, 0x8E, 0xE7, 0x7E)
ser.write(data)
s = ser.read(1)
print(s)
ser.close()
逆变器正在使用Danfoss ComLynx协议(在page 26上是我要发送的数据):
编辑: 我现在可以发送请求,因为Adam 4520 RS485转换器上的LED指示灯闪烁一次,但没有数据返回,但是当我在终端中执行CTRL + C时出现此错误:
dontommy@dtbeast:~/workspace/python_scripting/src$ ./sollar.py
True
^CTraceback (most recent call last):
File "./sollar.py", line 30, in <module>
s = ser.readline().decode('utf-8')
File "/usr/local/lib/python3.2/dist-packages/serial/serialposix.py", line 446, in read
ready,_,_ = select.select([self.fd],[],[], self._timeout)
KeyboardInterrupt
答案 0 :(得分:5)
将“thestring”重写为
thestring = "\x7E\xFF\x03\x00\x01\x00\x02\x0A\x01\xC8\x04\xD0\x01\x02\x80\x00\x00\x00\x00\x8E\xE7\z7E"
您不需要打包它,您可以说 data = thestring 并发送它。只有当文档中的各种ID与设备上的内容完全匹配时,这才有效
您需要弄清楚python “struct”如何工作,如何编码二进制以及如何将两个4位值放入一个8位字节:线索,请参阅&gt; &GT;和&lt;&lt; 运算符和struct pack“B”格式
答案 1 :(得分:1)
在尝试下面的方案之前,我尝试了许多方案将我的十六进制字符的命令字符串转换为字节,这些字节在UART的远端被识别为十六进制。我选择一次发送一个字节的字符串,因为远端一次不能处理超过四个字节,所以我无法发送整个字符串。单个hex_byte的格式类似于C中的sprintf。
import time
import serial
import sys
import binascii
import inspect
# This function takes a command string and sends individual bytes.
# It also reports the response.
def send_command(cmd_name, cmd_string):
print ("\ncmd_name:", cmd_name)
print ("cmd_string:", cmd_string)
cmd_bytes = bytearray.fromhex(cmd_string)
for cmd_byte in cmd_bytes:
hex_byte = ("{0:02x}".format(cmd_byte))
#print (hex_byte)
ser.write(bytearray.fromhex(hex_byte))
time.sleep(.100)
# wait an extra 3 seconds for DISP_ON_CMD
if cmd_name == "DISP_ON_CMD":
time.sleep(5.0)
response = ser.read(32)
print ("response:", binascii.hexlify(bytearray(response)))
return
# Code to put processor into factory mode.
comm_init='c4c4'
# Here's the list of command strings, captured as tuples.
# The 16-bit Data and Msg CRCs are calculated via gen_crc.exe.
heart_beat_cmd= ("HEART_BEAT_CMD", 'a5a50a00010000003e1b')
这是我在Python 3.4.5窗口中看到的内容。
cmd_name:HEART_BEAT_CMD
cmd_string:a5a50a00010000003e1b
回复:b&#39; a5a51a002a0054373031763200000c08201e0a040000e389f86b&#39;
我从来没有把输出解析为字节,但这将是一个很好的补充。
答案 2 :(得分:0)
免责声明:我对python和串口编程都很陌生。我知道这是一个非常古老的问题,可能已经解决了,但我想尽我所能(我猜)并且可能在这个过程中学习!我知道关于KeyboardInterrupt的问题的第二部分的答案(或者至少我认为我这样做。)所以这里是
KeyboardInterrupt基本上是当用户在程序仍在运行时点击“Control + C”时。这使得程序在当时正在执行的任何一行停止。因此
File "./sollar.py", line 30, in <module>
s = ser.readline().decode('utf-8')
File "/usr/local/lib/python3.2/dist-packages/serial/serialposix.py", line 446, in read
ready,_,_ = select.select([self.fd],[],[], self._timeout)
因为那是它停止的地方(希望我是对的。)为了避免这种情况,你可以使用“试试......除了”
while True:
try:
# your main code here
break
except KeyboardInterrupt:
print("User interrupt encountered. Exiting...")
time.sleep(3)
exit()
except:
# for all other kinds of error, but not specifying which one
print("Unknown error...")
time.sleep(3)
exit()
这基本上可以帮助您以相当“干净的方式”退出程序。希望有所帮助。
答案 3 :(得分:-1)
ser.write(b'\x1A') #### esto es = control + z