Hilfe bei neuer Funktion in LS7366R.py

Python auf Einplatinencomputer wie Raspberry Pi, Banana Pi / Python für Micro-Controller
Antworten
luemmel76
User
Beiträge: 22
Registriert: Freitag 26. Februar 2016, 17:42
Wohnort: Südhessen

Hallo zusammen,

ich versuche das Script LS7366R.py von hier mit der Funktion WRITE_DTR + LOAD_COUNTER (Zeile def loadCounter(self, enc_val):) zu erweitern um einen Startzählerwert vorzugeben.

Bisher sind meine Versuche gescheitert, bekomme zwar keine Fehlermeldung aber auch der Wert (9999) wird nicht in den LS7366R geschrieben. Jetzt hab ich hier gelesen wie man in der Arduino Sprache den Byte-Wert zerlegt und in den LS7366R schreibt, nur weiß ich nicht wie ich das in Python hinbekomme den dezimalen Wert 9999 in bytes umzuwandeln und dann rüzuberschreiben.

hier mein LS7366R.py:

Code: Alles auswählen

#!/usr/bin/python

#Python library to interface with the chip LS7366R for the Raspberry Pi
#Written by Federico Bolanos
#Source: https://github.com/fbolanos/LS7366R
#Last Edit: February 8th 2016
#Reason: Refactoring some names

import sys
import spidev
from time import sleep


# Usage: import LS7366R then create an object by calling enc = LS7366R(CSX, CLK, BTMD)
# CSX is either CE0 or CE1, CLK is the speed, BTMD is the bytemode 1-4 the resolution of your counter.
# example: lever.Encoder(0, 1000000, 4)
# These are the values I normally use.

class LS7366R():

    #-------------------------------------------
    # Constants

    #   Commands
    CLEAR_COUNTER = 0x20
    CLEAR_STATUS  = 0x30
    READ_COUNTER  = 0x60
    READ_STATUS   = 0x70
    WRITE_DTR     = 0x98
    LOAD_COUNTER  = 0xE0
    LOAD_OTR      = 0xE4
    WRITE_MODE0   = 0x88
    WRITE_MODE1   = 0x90

    #   Count Operating Modes
    #   0x00: non-quadrature count mode. (A = clock, B = direction).
    #   0x01: x1 quadrature count mode (one count per quadrature cycle).
    #   0x02: x2 quadrature count mode (two counts per quadrature cycle).
    #   0x03: x4 quadrature count mode (four counts per quadrature cycle).
    FOURX_COUNT = 0x01

    #   Count Byte Modes
    FOURBYTE_COUNTER  = 0x00	# counts from 0 to 4,294,967,295
    THREEBYTE_COUNTER = 0x01	# counts from 0 to    16,777,215
    TWOBYTE_COUNTER   = 0x02	# counts from 0 to        65,535
    ONEBYTE_COUNTER   = 0x03	# counts from 0 to           255

    #   Enable/disable counter
    EN_CNTR  = 0x00  # counting enabled
    DIS_CNTR = 0x04  # counting disabled

    BYTE_MODE = [ONEBYTE_COUNTER, TWOBYTE_COUNTER, THREEBYTE_COUNTER, FOURBYTE_COUNTER]

    #   Values
    max_val = 4294967295

    # Global Variables

    counterSize = 4 #Default 4

    #----------------------------------------------
    # Constructor

    def __init__(self, CSX, CLK, BTMD):
        self.counterSize = BTMD #Sets the byte mode that will be used

        self.spi = spidev.SpiDev() #Initialize object
        self.spi.open(0, CSX) #Which CS line will be used
        self.spi.max_speed_hz = CLK #Speed of clk (modifies speed transaction)

        #Init the Encoder
        print 'Clearing Encoder CS%s\'s Count...\t' % (str(CSX)), self.clearCounter()
        print 'Clearing Encoder CS%s\'s Status..\t' % (str(CSX)), self.clearStatus()

        self.spi.xfer2([self.WRITE_MODE0, self.FOURX_COUNT])

        sleep(.1) #Rest

        self.spi.xfer2([self.WRITE_MODE1, self.BYTE_MODE[self.counterSize-1]])

    def close(self):
        print '\nThanks for using me! :)'
        self.spi.close()

    def clearCounter(self):
        self.spi.xfer2([self.CLEAR_COUNTER])

        return '[DONE]'

    def clearStatus(self):
        self.spi.xfer2([self.CLEAR_STATUS])

        return '[DONE]'

    def loadCounter(self, enc_val):		# neue Funktion @Thilo
        VAL = [hex(enc_val).upper()]
        loadTransaction = [self.WRITE_DTR]
        self.spi.xfer2(loadTransaction, VAL)
        self.spi.xfer2([self.LOAD_COUNTER])

        return '[DONE]'

    def readCount(self):		# andere Vorgehensweise @Thilo
	readTransaction = [self.READ_COUNTER]

	for i in range(self.counterSize):
	    readTransaction.append(0)

	data = self.spi.xfer2(readTransaction)

	if self.counterSize == 4:
	    count_value = (data[1]<<24) + (data[2]<<16) + (data[3]<<8) + (data[4])
	else:
	    if self.counterSize == 3:
		count_value = (data[1]<<16) + (data[2]<<8) + (data[3])
	    else:
		if self.counterSize == 2:
		    count_value = (data[1]<<8) + (data[2])
		else:
		    count_value = data[1]

	return count_value

    def readCounter(self):
        readTransaction = [self.READ_COUNTER]

        for i in range(self.counterSize):
            readTransaction.append(0)

        data = self.spi.xfer2(readTransaction)

	EncoderCount = 0
        for i in range(self.counterSize):
            EncoderCount = (EncoderCount << 8) + data[i+1]

        if data[1] != 255:
            return ("+" + str(EncoderCount))
        else:
            return (EncoderCount - (self.max_val+1))

    def readStatus(self):
        data = self.spi.xfer2([self.READ_STATUS, 0xFF])

        return data[1]


if __name__ == "__main__":
    from time import sleep

    encoder = LS7366R(0, 1000000, 4)
    try:
        while True:
	    sys.stdout.write('\rEncoder count: ' + str(encoder.readCounter())+"    CTRL+C for exit",)
	    sys.stdout.flush()
            sleep(0.2)
    except KeyboardInterrupt:
        encoder.close()
        print "All done, bye bye."
und hier Auszüge für die byte Umwandlung und Übertragung aus dem zweiten Link:

Code: Alles auswählen

// =================================================================================
// Wrong, DTR changes its width with the byte mode. This function needs to be fixed
// to reflect those changes.
void LS7366R::writeDTR(unsigned long set){
  byte b1, b2, b3, b4;
  b1 = set & 0xFF;
  b2 = (set >> 8) & 0xFF;
  b3 = (set >> 16) & 0xFF;
  b4 = (set >> 32) & 0xFF;

  digitalWrite(_SS, LOW);
  
  SPI.transfer(0x98);  // Write DTR
  SPI.transfer(b1);
  SPI.transfer(b2);
  SPI.transfer(b3);
  SPI.transfer(b4);

  digitalWrite(_SS, HIGH); 
}
// =================================================================================
Wäre super nett wenn ihr mir helfen könntet

Gruß
Thilo
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

SPI kennt keine Fehler in der Übertragung. Da wird rausgehauen was da ist, und ob das verstanden wurde steht auf nem anderen Blatt. Insofern ist es nicht verwunderlich, das du keine Fehler bekommst.

Deine WRITE_DTR Anweisung ist Unfug. Das hex hat da nix verloren. Da müssen 5 Bytes rein. Mach eine Liste mit 5 Werten, der erste das Kommando, die anderen deine gewünschte Vorbelegung. Kodier das erstmal hart, um das zum laufen zu bringen. Und dann schreib die 5 werte Liste mit xfer2. Ohne zweites Argument. Danach dann dein LOAD wie gehabt.
luemmel76
User
Beiträge: 22
Registriert: Freitag 26. Februar 2016, 17:42
Wohnort: Südhessen

ok, mit

Code: Alles auswählen

bytes_string = [self.WRITE_DTR, 0x00, 0x63]
self.spi.xfer2(bytes_string)
bekomme ich es schonmal hin das er den Zählerwert 99 übermittelt und auch beim aufruf von readCount wird mir die 99 als Startwert anzeigt.
Nach weiterem rumprobieren bekomme ich mit

Code: Alles auswählen

bytes_string = [self.WRITE_DTR, 0x27, 0x0f]
self.spi.xfer2(bytes_string)
auch die 9999 übermittelt und angezeigt.

Aber die ganze Zahl 9999 automatisch in einzelne bytes zu zerlegen bekomme ich nicht hin, trotz jetzt schon stundenlangem googeln und probieren :(
Benutzeravatar
pillmuncher
User
Beiträge: 1482
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

@luemmel76: meinst du sowas?

Code: Alles auswählen

>>> 9999 // 0x100, 9999 % 0x100
(39, 15)
>>> 39 * 0x100 + 15                                                             
9999
In specifications, Murphy's Law supersedes Ohm's.
narpfel
User
Beiträge: 643
Registriert: Freitag 20. Oktober 2017, 16:10

@luemmel76: Zum Zerlegen von Zahlen in ihre Bytes bietet sich auch das `struct`-Modul aus der Standardbibliothek an:

Code: Alles auswählen

>>> struct.pack(">h", 9999)
"'\x0f"
>>> map(ord, struct.pack(">h", 9999))
[39, 15]
luemmel76
User
Beiträge: 22
Registriert: Freitag 26. Februar 2016, 17:42
Wohnort: Südhessen

hallo narpfel,

mit struct.pack hab ich schon rumprobiert, deine Variante funktioniert an der python console und im Schript jetzt auch gut für den ONEBYTE_COUNTER und TWOBYTE_COUNTER Modus, da ich aber gerne dem Author was zurück geben möchte was auch mit dem THREEBYTE_COUNTER und FOURBYTE_COUNTER Modus funktioniert, wäre eine counterSize abhängige Lösung schon was feines :wink:

counterSize = BYTE_MODE = BTM, wobei BTM beim aufruf des moduls mit übergeben wird.

quasi eine IF Abfrage welchen Wert counterSize hat und dann entsrechend auch den Wert umwandelt:

Code: Alles auswählen

if counterSize == 4:
...
    bytes_string = [self.WRITE_DTR, data[0], data[1], data[2], data[3]]
    elif counterSize == 3:
        ...
        bytes_string = [self.WRITE_DTR, data[0], data[1], data[2]]
            elif counterSize ==2:
                data = map(ord, struct.pack(">h", enc_val))   # das funktioniert mit counterSize = 2 und Werten von 1-9999
                bytes_string = [self.WRITE_DTR, data[0], data[1]]   # das funktioniert mit counterSize = 2 und Werten von 1-9999
                else:
                    # counterSize = 1
                    ...
                    bytes_string = [self.WRITE_DTR, data[0]]
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Da die Byte Order litte endian ist, kannst du dir das (falsch weil nicht richtig eingerückte) if/elif gehummse ersparen und einfach slicen:

Code: Alles auswählen

all_data = [self.WRITE_DTR] + data
send_data = all_data[:counterSize + 1]
Sirius3
User
Beiträge: 17712
Registriert: Sonntag 21. Oktober 2012, 17:20

Die Methodennamen halten sich nicht an die üblichen Namenskonvention, `read_counter` is unnötig kompliziert.

Code: Alles auswählen

class LS7366R(object):
    #   Commands
    CLEAR_COUNTER = 0x20
    CLEAR_STATUS  = 0x30
    READ_COUNTER  = 0x60
    READ_STATUS   = 0x70
    WRITE_DTR     = 0x98
    LOAD_COUNTER  = 0xE0
    LOAD_OTR      = 0xE4
    WRITE_MODE0   = 0x88
    WRITE_MODE1   = 0x90

    #   Count Operating Modes
    #   0x00: non-quadrature count mode. (A = clock, B = direction).
    #   0x01: x1 quadrature count mode (one count per quadrature cycle).
    #   0x02: x2 quadrature count mode (two counts per quadrature cycle).
    #   0x03: x4 quadrature count mode (four counts per quadrature cycle).
    FOURX_COUNT = 0x01

    #   Count Byte Modes
    FOURBYTE_COUNTER  = 0x00   # counts from 0 to 4,294,967,295
    THREEBYTE_COUNTER = 0x01   # counts from 0 to    16,777,215
    TWOBYTE_COUNTER   = 0x02   # counts from 0 to        65,535
    ONEBYTE_COUNTER   = 0x03   # counts from 0 to           255

    #   Enable/disable counter
    EN_CNTR  = 0x00  # counting enabled
    DIS_CNTR = 0x04  # counting disabled

    BYTE_MODE = [ONEBYTE_COUNTER, TWOBYTE_COUNTER, THREEBYTE_COUNTER, FOURBYTE_COUNTER]

    def __init__(self, cs_line, max_speed_hz, byte_mode):
        self.byte_mode = byte_mode

        self.spi = spidev.SpiDev()
        self.spi.open(0, cs_line) # Which CS line will be used
        self.spi.max_speed_hz = max_speed_hz #Speed of clk (modifies speed transaction)

        #Init the Encoder
        self.clearCounter()
        self.clearStatus()
        self.spi.xfer2([self.WRITE_MODE0, self.FOURX_COUNT])
        sleep(.1) #Rest
        self.spi.xfer2([self.WRITE_MODE1, self.BYTE_MODE[self.byte_mode-1]])

    def close(self):
        self.spi.close()

    def clear_counter(self):
        self.spi.xfer2([self.CLEAR_COUNTER])

    def clear_status(self):
        self.spi.xfer2([self.CLEAR_STATUS])

    def load_counter(self, enc_val):
        data = struct.pack(">I", enc_val)[-self.byte_mode:]
        self.spi.xfer2([self.WRITE_DTR] + list(ord(k) for k in data))
        self.spi.xfer2([self.LOAD_COUNTER])

    def read_counter(self):
        data = [self.READ_COUNTER] + [0] * self.byte_mode
        data = self.spi.xfer2(data)
        return reduce(lambda a,b: (a<<8) + b, data[1:], 0)

    def read_status(self):
        data = self.spi.xfer2([self.READ_STATUS, 0xFF])
        return data[1]
luemmel76
User
Beiträge: 22
Registriert: Freitag 26. Februar 2016, 17:42
Wohnort: Südhessen

WOW ,vielen vielen Dank Sirius3 das funktioniert ja wie geschmiert :D :D

Darf ich das an den ursprünglichen Autor weitergeben?
Antworten