簡體   English   中英

使用python通過串行發送十六進制

[英]Sending hex over serial with python

這個周末我要做一個小項目。 有一個太陽能電池逆變器(丹佛斯 ULX 3600i),我將嘗試連接到我的 linux 機器,看看我是否可以從中獲取數據,例如為統計數據創造了多少能量。 上面有一個用於 RJ45 連接的輸入,但帶有 RS485。

我得到了電纜,通過我在電腦上的 USB 端口連接它,在電腦和逆變器之間有一個 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 協議( 第 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

將“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位字節:線索,請參閱>>和<<運算符以及結構包“B”格式

在確定下面的方案之前,我嘗試了多種方案將我的十六進制字符命令字符串轉換為字節,這些字節在 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'a5a51a002a0054373031763200000c08201e0a040000e389f86b'

我從來沒有把輸出解析成字節,但這將是一個很好的補充。

免責聲明:我對 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)

因為那是它停止的地方(希望我是對的。)為了避免這種情況,你可以使用“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()

這基本上可以幫助您以一種相當“干凈的方式”退出程序。 希望有幫助。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM