简体   繁体   English

使用python通过串行发送十六进制

[英]Sending hex over serial with python

This weekend I am going to make a little project.这个周末我要做一个小项目。 Got a solarcell inverter (Danfoss ULX 3600i) which I will try to connect to my linux machine, to see if I can grab the data from it, how much energy created eg for stats.有一个太阳能电池逆变器(丹佛斯 ULX 3600i),我将尝试连接到我的 linux 机器,看看我是否可以从中获取数据,例如为统计数据创造了多少能量。 There is an input for RJ45 connection on it, but with RS485.上面有一个用于 RJ45 连接的输入,但带有 RS485。

I got the cables to connect it through my usb port in the pc with an RS485 converter in between the pc and the inverter.我得到了电缆,通过我在电脑上的 USB 端口连接它,在电脑和逆变器之间有一个 RS485 转换器。

I am then writing a small python code to make request.然后我正在编写一个小的 python 代码来发出请求。 However I cant figure out how to send the data correctly.但是我不知道如何正确发送数据。

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()

The inverter is using the Danfoss ComLynx protocol (on page 26 is the data I am trying to send):逆变器使用 Danfoss ComLynx 协议( 第 26 页是我尝试发送的数据):

EDIT: I now can send a request as the LED light on the Adam 4520 RS485 converter is blinking once, however no data back, but get this error when I do a CTRL+C in terminal:编辑:我现在可以发送请求,因为 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

Rewrite "thestring" as将“thestring”重写为

thestring = "\x7E\xFF\x03\x00\x01\x00\x02\x0A\x01\xC8\x04\xD0\x01\x02\x80\x00\x00\x00\x00\x8E\xE7\z7E"

You won't need to pack it, you can say data=thestring and send it.你不需要打包它,你可以说data=thestring并发送它。 This will only work if the various ids in the document match exactly what is on your equipment这仅在文档中的各种 ID 与您设备上的完全匹配时才有效

You need to figure out how the python "struct" works, how to encode binary and how to put two 4 bit values into one 8 bit byte: clue, see the >> and << operators and the struct pack "B" format您需要弄清楚python “struct”如何工作,如何编码二进制以及如何将两个4位值放入一个8位字节:线索,请参阅>>和<<运算符以及结构包“B”格式

I tried a number of schemes to convert my command string of hex characters into bytes which were recognized as hex on the far end of the UART, before settling on the scheme below.在确定下面的方案之前,我尝试了多种方案将我的十六进制字符命令字符串转换为字节,这些字节在 UART 的远端被识别为十六进制。 I chose to send the string one byte at a time, because the far end could not process more than four bytes at a time, so I could not send the entire string.我选择一次发送一个字节,因为远端一次不能处理超过四个字节,所以我不能发送整个字符串。 The formatting of the individual hex_byte is similar to an sprintf in C.单个 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')

Here is what I see displayed in my Python 3.4.5 window.这是我在 Python 3.4.5 窗口中看到的内容。

cmd_name: HEART_BEAT_CMD cmd_name: HEART_BEAT_CMD

cmd_string: a5a50a00010000003e1b cmd_string: a5a50a00010000003e1b

response: b'a5a51a002a0054373031763200000c08201e0a040000e389f86b'回复:b'a5a51a002a0054373031763200000c08201e0a040000e389f86b'

I never got around to parsing the output into bytes, but that would be a nice addition.我从来没有把输出解析成字节,但这将是一个很好的补充。

Disclaimer: I am very new to both python and serial port programming.免责声明:我对 python 和串口编程都很陌生。 I know this is a very old question and might have been solved already, but I'd like to do my part(I guess) and maybe learn in the process!我知道这是一个非常古老的问题,可能已经解决了,但我想尽我的一份力量(我猜),也许在这个过程中学习! I know the answer to the second part of the question about the KeyboardInterrupt(or at least I think I do.) So here goes我知道关于 KeyboardInterrupt 问题的第二部分的答案(或者至少我认为我知道。)所以这里是

KeyboardInterrupt is basically when the user hits "Control+C" while the program is still running. KeyboardInterrupt 基本上是当用户在程序仍在运行时点击“Control+C”。 This makes the program stop at right whichever line it was executing at then moment.这使得程序停止在它当时正在执行的任何一行的右侧。 Hence the因此

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)

Because that's where it stopped(hopefully I'm right.) To avoid this, you could use "try.. except"因为那是它停止的地方(希望我是对的。)为了避免这种情况,你可以使用“try..except”

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()

This basically helps you exit your program in a rather "clean way."这基本上可以帮助您以一种相当“干净的方式”退出程序。 Hope that helps.希望有帮助。

ser.write(b'\\x1A') #### esto es = control + z

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM