In "Zugriff auf SPS-Register in Python versuchen" habe ich versucht, einen einfachen Wortzugriff über SLMP in Python durchzuführen. Dieses Mal werde ich die Datenmanipulation beim Lesen und Schreiben eines Bitgeräts mit Binärcode in Python implementieren.
SLMP bietet zwei kontinuierliche Zugriffsmethoden auf Bit-Geräte.
Beim Zugriff in 1-Punkt-Einheiten handelt es sich um eine 4-Bit-BCD-Codedarstellung, wie unten gezeigt. Das Folgende ist ein Beispiel für die Kommunikation zum Zeitpunkt des Lesens.
Für den Zugriff in Einheiten von 16 Punkten ist 1 Bit eine binäre Darstellung von 1 Punkt. Das Folgende ist ein Beispiel für die Kommunikation zum Zeitpunkt des Lesens.
Natürlich sind 16-Punkte-Einheiten für das kontinuierliche Lesen und Schreiben von Massen vorteilhafter.
Der verwendete Kommunikationsbefehl ist der gleiche wie beim Zugriff auf Wörter, aber da Bitdaten wie oben beschrieben gepackt werden, ist eine Datenkonvertierung erforderlich, um sie als Array-Daten wie eine Liste in Python zu behandeln.
Dies ist ziemlich ärgerlich, und insbesondere bei 16-Punkte-Einheiten besteht die Sorge, dass sich dies auf die Verarbeitungsgeschwindigkeit in Python auswirkt, wenn Sie versuchen, Stück für Stück normal zu extrahieren. Hier implementieren wir es mit der Bitoperation von numpy.
Lesen Sie mit dem Befehl Lesen (0401h
) wie beim Wortzugriff. Der Unterbefehl unterscheidet sich jedoch von "0001h".
Wenn das empfangene Datenarray als "[0x00, 0x01, 0x00, 0x11, ...]" extrahiert wird, dann "[0, 0, 0, 1, 0, 0, 1, 1, ...] Muss wie `erweitert werden.
Der folgende Beispielcode erweitert die BDC-Codesequenz.
Das Argument data
und der Rückgabewert sind beide ndarray von numpy (dtype = uint8).
Da Array-Daten mithilfe von Numpy in einem Stapel berechnet werden können, ist keine Schleifenverarbeitung mit Python-Syntax erforderlich, und eine schnelle Verarbeitung ist insbesondere bei großen Datenmengen zu erwarten.
import numpy as np
# ex. data = np.array([0x12, 0x34, 0x56], 'u1')
def decode_bcd(data):
"""
Decode 4bit BCD array
[0x12,0x34,...] --> [1,2,3,4,...]
"""
binArrayH = (data >> 4) & 0x0F
binArrayL = data & 0x0F
binArray = np.empty(data.size * 2, 'u1')
binArray[::2] = binArrayH
binArray[1::2] = binArrayL
return binArray
Das Muster ist die Umkehrung des Lesens. Packen Sie den BCD-Code ein. Wenn die Originaldaten eine ungerade Zahl sind, werden die letzten 4 Bits nicht verwendet. Füllen Sie sie daher mit 0.
def encode_bcd(data):
"""
Encode 4bit BCD array
[1,2,3,4,...] --> [0x12,0x34,...]
Wenn die Anzahl der Eingänge ungerade ist, füllen Sie die letzten 4 Bits mit 0
"""
binArrayH = (data[::2] & 0x0F) << 4
binArrayL = data[1::2] & 0x0F
binArray = np.zeros_like(binArrayH)
if data.size % 2 == 0:
binArray = binArrayH | binArrayL
else:
binArray[:-1] = binArrayH[:-1] | binArrayL
binArray[-1] = binArrayH[-1]
return binArray
Wie beim Wortzugriff liest der Lesebefehl (0401h
) und die Unterbefehle sind dieselben.
Da es sich bei dem Inhalt um Wortdaten handelt, entspricht dies einem Kommunikationsbefehl.
Wie im obigen Kommunikationsbeispiel gezeigt, sind die empfangenen 4-Byte-Daten "[34h, 12h, 02h, 00h]"
[<M107>, ..., <M100>, <M115>, ..., <M108>, <M123>, ..., <M116>, <M131>, ..., <M124>]
^ ^ ^
Es wird durch Biterweiterung zu einem Datenarray von 16 * 4 = 32 Punkten erweitert.
Das Verwirrende dabei ist, dass ** die Adressen in umgekehrter Reihenfolge pro Byte gespeichert werden **. Mit anderen Worten, im obigen Beispiel ist das LSB des ersten 1-Bytes "34h" der Wert der Startadresse, wenn der Lesebefehl gesendet wird, und der Wert der Daten, deren Adresse in Richtung des MSB inkrementiert wird. Und für das 2. Byte "12h" ist das LSB diesmal der Wert von "Startadresse +8" ...
Der folgende Beispielcode verwendet das Entpackbit von numpy, um die einzelnen Bitdaten zu einem eindimensionalen Array zu erweitern. numpy.packbits, numpy.unpackbits /reference/generated/numpy.unpackbits.html) ist eine Funktion, die ein Dezimalzahl-Binärzahl-Array konvertiert.
Wenn die Reihenfolge von LSB und MSB umgekehrt werden muss, besteht das Miso darin, dass die Reihenfolge in Spaltenrichtung umgekehrt wird, indem die Schicht angegeben wird, nachdem sie einmal in zwei Dimensionen angeordnet und die Bits erweitert wurden.
def unpack_bits(data):
"""
Erweitern Sie die in der Reihenfolge vom LSB gespeicherten Bitfolgen zu einem Array
[<M107 ... M100>, <M115 ... M108>] --> [<M100>, ... ,<M107>, <M108>, ... ,<M115>]
"""
#Um die Datenreihenfolge nach dem Entpacken als pseudo-zweidimensionales Array umzukehren,
#Stellen Sie sicher, dass für jedes Byte Bitdaten gespeichert sind
# ex. [1,2,3] --> [[1],[2],[3]]
byteArray2D = data.reshape((data.size, 1))
#Bitdaten erweitern
# ex. [[1],[2],[3]] --> [[0,0,0,0,0,0,0,1],[0,0,0,0,0,0,1,0],[0,0,0,0,0,0,1,1]]
byteArray2D_bin = np.unpackbits(byteArray2D, axis=1)
#Kehren Sie nach dem Umkehren der Reihenfolge in Spaltenrichtung zum eindimensionalen Array zurück
return byteArray2D_bin[:, ::-1].flatten()
Das Muster ist die Umkehrung des Lesens. Packt 0/1 eindimensionale Array-Daten in eine Byte-Zeichenfolge.
def pack_bits(data):
"""
Packen Sie ein Array von Bitdaten in eine Byte-Zeichenfolge, die in der Reihenfolge vom LSB gespeichert ist
[<M100>, ... ,<M107>, <M108>, ... ,<M115>] --> [<M107 ... M100>, <M115 ... M108>]
"""
#Stellen Sie sicher, dass die Anzahl der Daten ein Vielfaches von 8 ist
size8 = -(-data.size // 8) * 8
#Geben Sie 0 ein, wenn die letzte Größe nicht ausreicht
byteArray_bin = np.zeros(size8, 'u1')
byteArray_bin[:size8] = data
#In ein zweidimensionales Array konvertiert, um die Datenreihenfolge alle 8 Bits zu invertieren
byteArray2D_bin = byteArray_bin.reshape((size8//8, 8))
#Bitdaten packen
return np.packbits(byteArray2D_bin[:, ::-1])
--Mitsubishi Electric SLMP Referenzhandbuch
Recommended Posts