Hex-Werte aus Liste auslesen und seriell steuern

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Benutzeravatar
gatonero
User
Beiträge: 21
Registriert: Montag 4. April 2022, 21:12

Ich möchte von einem ESP32 ein serielles LCD ansteuern. Für die Cursor-Steuerung möchte ich die Werte aus einer Liste auslesen. Normalerweise übergebe ich die Werte z.B. mit
'\x16'
. Solche Werte kann ich aber nicht in eine Liste übernehmen. Deshalb habe ich die Werte dort z.B. mit
0x80
eingetragen. Diese Werte kann ich auch an das LCD fehlerfrei übertragen, dort wird aber nicht gesteuert, sondern der Wert dezimal ausgegeben.

Nach einigen Stunden bin ich nun soweit, dass ich um Hilfe bitte.

Code: Alles auswählen

from time import sleep

import machine

LCD_ON = '\x16'
LCD_CLEAR = '\x0C'
LCD_LIGHT_ON = '\x11'
LCD_COMMAND_LIST = [0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86]

class LCD:
    def __init__(self):
        self.connection = machine.UART(2, baudrate=19200)

    def setup(self):
        self.connection.write(LCD_ON)  # Display Ein.
        sleep(0.2)
        self.connection.write(LCD_CLEAR)  # Display löschen, Cursor auf 0, 0.
        sleep(0.2)
        self.connection.write(LCD_LIGHT_ON)  # Display Hintergrundbeleuchtung Ein.
        sleep(0.2)

    def message(self):
        self.connection.write("Hallo Welt!")

    def setCursorHome(self):
        LCD_CURSOR_POS = str(LCD_COMMAND_LIST[0])
        self.connection.write(LCD_CURSOR_POS)


lcd = LCD()
lcd.setup()
lcd.message()
lcd.setCursorHome()
Die Funktion str() benutze ich, um den Fehler "TypeError: object with buffer protocol required" zu vermeiden.
Benutzeravatar
gatonero
User
Beiträge: 21
Registriert: Montag 4. April 2022, 21:12

Kurz vor dem Einschlafen ist mir noch plötzlich die Lösung eingefallen! :-)

Code: Alles auswählen

from time import sleep

import machine

LCD_ON = '\x19'
LCD_CLEAR = '\x0C'
LCD_LIGHT_ON = '\x11'
LCD_COMMAND_LIST = ['\x80', '\x81', '\x82', '\x83', '\x84', '\x85', '\x86']

class LCD:
    def __init__(self):
        self.connection = machine.UART(2, baudrate=19200)

    def setup(self):
        self.connection.write(LCD_ON)  # Display Ein.
        sleep(0.2)
        self.connection.write(LCD_CLEAR)  # Display löschen, Cursor auf 0, 0.
        sleep(0.2)
        self.connection.write(LCD_LIGHT_ON)  # Display Hintergrundbeleuchtung Ein.
        sleep(0.2)

    def message(self):
        self.connection.write("Hallo Welt!")

    def setCursorHome(self):
        LCD_CURSOR_POS = str(LCD_COMMAND_LIST[0])
        self.connection.write(LCD_CURSOR_POS)


lcd = LCD()
lcd.setup()
lcd.message()
lcd.setCursorHome()
Benutzeravatar
__blackjack__
User
Beiträge: 13270
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@gatonero: Der `str()`-Aufruf ist überflüssig, das ist ja bereits eine Zeichenkette.

Warum die Liste und dann magische Indexwerte? Warum nicht einfach weitere Konstanten definieren die einen sinnvollen Namen haben, an dem man ablesen kann, was der Wert für eine Bedeutung hat?

KOMPLETT_GROSS schreibt man nur Konstanten. `LCD_CURSOR_POS` ist nicht wirklich eine. Und Namen ausser Konstanten und Klassen werden klein_mit_unterstrichen geschrieben.

Die Konstanten könnte man auch in die Klasse stecken statt einen Präfix als Pseudo-Namensraum zu verwenden.

Ungetestet:

Code: Alles auswählen

from time import sleep

import machine


class LCD:
    ON = "\x19"
    CLEAR = "\x0C"
    LIGHT_ON = "\x11"
    CURSOR_HOME = "\x80"

    def __init__(self):
        self.connection = machine.UART(2, baudrate=19200)

    def setup(self):
        for command in [self.ON, self.CLEAR, self.LIGHT_ON]:
            self.connection.write(command)
            sleep(0.2)

    def display_greeting(self):
        self.connection.write("Hallo Welt!")

    def set_cursor_home(self):
        self.connection.write(self.CURSOR_HOME)


lcd = LCD()
lcd.setup()
lcd.display_greeting()
lcd.set_cursor_home()
Please call it what it is: copyright infringement, not piracy. Piracy takes place in international waters, and involves one or more of theft, murder, rape and kidnapping. Making an unauthorized copy of a piece of software is not piracy, it is an infringement of a government-granted monopoly.
imonbln
User
Beiträge: 149
Registriert: Freitag 3. Dezember 2021, 17:07

Die Funktion, welche du gestern gesucht hast, ist chr. Die macht aus 0x80 \x80.

Generell zu dein Programm üblicher weise kommen imports vor from.
Variablen in Methoden werden immer kleingeschrieben, es muss also lcd_cursor_pos heißen und nicht LCD_CURSOR_POS. Ausserdem würde ich empfehlen die ganzen Lcd Controll Charater in ein Enum zu packen, das macht den Code viel leichter.
Design technisch, denke ich das die __init__ Funktion das Setup mit machen sollte, den Objekte sollten nach dem Initialisieren "ready to use" sein. das self.connection.write gefolgt von dem sleep würde ich in einer eigen write Methode kapseln.

folgender Code bei rauskommt:

Code: Alles auswählen

import enum
import machine
from time import sleep


@enum.unique
class LcdControl(enum.IntEnum):
    ON = 0x16 # oder  0x19?
    CLEAR = 0x0C
    LIGHT_ON = 0x11
    CURSOR_HOME = 0x80
    MAGIC1 = 0x81  # unklar was das macht  
    MAGIC2 = 0x82 

    def __str__(self):
        return chr(self.value)


class Lcd:

    def __init__(self):
        self.connection = machine.UART(2, baudrate=19200)
        self.write(LcdControl.ON)
        self.write(LcdControl.CLEAR)
        self.write(LcdControl.LIGHT_ON)

    def write(self, payload):
        self.connection.write(str(payload))
        sleep(0.2)


lcd = Lcd()
lcd.write("Hallo Welt")
lcd.write(LcdControl.CURSOR_HOME)
Benutzeravatar
gatonero
User
Beiträge: 21
Registriert: Montag 4. April 2022, 21:12

@__blackjack__

Die Steuerbefehle sind so umfangreich, dass ich nicht mit Konstanten arbeiten kann/will. Über eine Positionsangabe, z.B. (3, 10) ermittel ich mir den zugehörigen Steuerbefehl aus einer Liste.

kleine Erklärung: Ich habe 30 Jahre Cobol programmiert und befasse mich seit zwei Wochen mit Python. :oops:

Code: Alles auswählen

LCD_ROW = 0
LCD_COL = 0
LCD_ROW_MAX = 3
LCD_COL_MAX = 19
LCD_POS_LIST = [[0, 0], [0, 1], [0, 2], [0, 3], [0, 4], [0, 5], [0, 6],
                [0, 7], [0, 8], [0, 9], [0, 10], [0, 11], [0, 12], [0, 13],
                [0, 14], [0, 15], [0, 16], [0, 17], [0, 18], [0, 19],
                [1, 0], [1, 1], [1, 2], [1, 3], [1, 4], [1, 5], [1, 6],
                [1, 7], [1, 8], [1, 9], [1, 10], [1, 11], [1, 12], [1, 13],
                [1, 14], [1, 15], [1, 16], [1, 17], [1, 18], [1, 19],
                [2, 0], [2, 1], [2, 2], [2, 3], [2, 4], [2, 5], [2, 6],
                [2, 7], [2, 8], [2, 9], [2, 10], [2, 11], [2, 12], [2, 13],
                [2, 14], [2, 15], [2, 16], [2, 17], [2, 18], [2, 19],
                [3, 0], [3, 1], [3, 2], [3, 3], [3, 4], [3, 5], [3, 6],
                [3, 7], [3, 8], [3, 9], [3, 10], [3, 11], [3, 12], [3, 13],
                [3, 14], [3, 15], [3, 16], [3, 17], [3, 18], [3, 19]]


LCD_COMMAND_LIST = ['\x80', '\x81', '\x82', '\x83', '\x84', '\x85', '\x86', '\x87', '\x88', '\x89', '\x8A', '\x8B', '\x8C', '\x8D', '\x8E', '\x8F',
                    '\x90', '\x91', '\x92', '\x93', '\x94', '\x95', '\x96', '\x97', '\x98', '\x99', '\x9A', '\x9B', '\x9C', '\x9D', '\x9E', '\x9F',
                    '\xA0', '\xA1', '\xA2', '\xA3', '\xA4', '\xA5', '\xA6', '\xA7', '\xA8', '\xA9', '\xAA', '\xAB', '\xAC', '\xAD', '\xAE', '\xAF',
                    '\xB0', '\xB1', '\xB2', '\xB3', '\xB4', '\xB5', '\xB6', '\xB7', '\xB8', '\xB9', '\xBA', '\xBB', '\xBC', '\xBD', '\xBE', '\xBF',
                    '\xC0', '\xC1', '\xC2', '\xC3', '\xC4', '\xC5', '\xC6', '\xC7', '\xC8', '\xC9', '\xCA', '\xCB', '\xCC', '\xCD', '\xCE', '\xCF']

Die Funktion sieht so aus:

Code: Alles auswählen

class CharLCD:
    def cursorPos(self, LCD_ROW, LCD_COL):
        #print('*** In cursorPos: ', LCD_ROW, LCD_COL)
        if LCD_ROW < LCD_ROW_MIN:
            LCD_ROW = LCD_ROW_MIN
        if LCD_ROW > LCD_ROW_MAX:
            LCD_ROW = LCD_ROW_MAX
        if LCD_COL < LCD_COL_MIN:
            LCD_COL = LCD_COL_MIN
        if LCD_COL > LCD_COL_MAX:
            LCD_COL = LCD_COL_MAX

        #print('ROW', LCD_ROW)
        #print('COL', LCD_COL)

        #print('*** Gewuenschte Position: ', LCD_ROW, LCD_COL)
        searchPOS = [LCD_ROW, LCD_COL]
        #print('*** SuchPosition: ', searchPOS)
        if searchPOS in LCD_POS_LIST:
            searchINDEX = LCD_POS_LIST.index([LCD_ROW, LCD_COL])
            #print('*** SuchIndex: ', searchINDEX)
        else:
            print('Not found')

        if searchINDEX < len(LCD_COMMAND_LIST):
            LCD_CURSOR_POS = LCD_COMMAND_LIST[searchINDEX]
            sleep(LCD_BOUNCE)
            self.connection.write(str(LCD_CURSOR_POS))
            sleep(LCD_BOUNCE)
        else:
            print('Out of range ')
Der gesamt Code ist auf github zu finden. https://github.com/gatonero/parallaxLCD
Zuletzt geändert von gatonero am Freitag 8. April 2022, 21:33, insgesamt 2-mal geändert.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

In dem Code den ich dir gezeigt habe steht doch, wie man das einfach aus dem Koordinaten ausrechnet. Statt da so eine monster Liste zu bauen.
Benutzeravatar
gatonero
User
Beiträge: 21
Registriert: Montag 4. April 2022, 21:12

enum gibt es leider nicht in Micropython.
Benutzeravatar
gatonero
User
Beiträge: 21
Registriert: Montag 4. April 2022, 21:12

@__blackjack__: Im Netz habe ich eine Alternative gefunden, die zu funktionieren scheint.

Code: Alles auswählen

def enum(**enums):
    return type('Enum', (), enums)

Numbers = enum(ONE=1, TWO=2, THREE='three')

print(Numbers.ONE)
print(Numbers.TWO)
Damit werde ich es weiter versuchen.
Benutzeravatar
__blackjack__
User
Beiträge: 13270
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@gatonero: Das wäre eigentlich ein Wörterbuch das Koordinaten-Tupel auf Steuercodes abbildet und keine zwei Listen. Aber hast Du Dir die Werte mal angeschaut? Man kann den Steuercode doch trivial aus den Koordinaten *berechnen*. Das ist einfach ``chr(128 + row * 20 + column)``.

Komplett in Grossbuchstaben werden Konstanten benannt. Argumente von Funktionen und Methoden sind aber keine Konstanten. Sonst müsste man die Werte ja nicht übergeben.

Testen vor einer Operation die sowieso eine Ausnahme auslösen würde ist in Python nicht üblich. `list.index()` löst eine Ausnahme aus falls das Element nicht gefunden wird. Der ``in``-Test vorher sucht ja nur unnötigerweise vorher schon mal das Element, macht dann aber nichts weiter, nur damit dann `index()` noch mal nach dem Element sucht.

Ausserdem ist es ein Programmierfehler einfach auszugeben das nichts gefunden wurde, um dann so weiter zu machen als sei alles ok, nur um dann gleich darauf in eine Ausnahme zu laufen weil `searchINDEX` dann ja gar nicht definiert wurde.

Zugriff ein auf nicht existierendes Listenelement würde auch eine Ausnahme auslösen, also ist auch hier der Test vor dem Zugriff doppelte Arbeit, die man sich sparen würde. Und auch hier ist die Behandlung fragwürdig, auch wenn das hier zu keinem Folgefehler führen würde.

`LCD_CURSOR_POS` ist auch keine Konstante.

Der `str()`-Aufruf beim `write()` ist überflüssig, denn das ist ja bereits eine Zeichenkette.

Ungetestet:

Code: Alles auswählen

class CharacterLCD:
    def set_cursor_position(self, row, column):
        row = max(min(row, LCD_ROW_MAX), LCD_ROW_MIN)
        column = max(min(column, LCD_COL_MAX), LCD_COL_MIN)
        sleep(LCD_BOUNCE)
        self.connection.write(chr(0x80 + row * (LCD_ROW_MAX + 1) + column))
        sleep(LCD_BOUNCE)
Please call it what it is: copyright infringement, not piracy. Piracy takes place in international waters, and involves one or more of theft, murder, rape and kidnapping. Making an unauthorized copy of a piece of software is not piracy, it is an infringement of a government-granted monopoly.
Benutzeravatar
gatonero
User
Beiträge: 21
Registriert: Montag 4. April 2022, 21:12

@__blackjack__: Danke vielmals! :-)

Manchmal bin ich einfach vernagelt, und versuche mit einem gefundenen, gangbaren Mittel mit dem Kopf durch die Wand zu gehen. :oops:

So passt es jetzt:

Code: Alles auswählen

import machine
import gc
from time import sleep

gc.enable

LCD_UART = 2
LCD_BAUDRATE = 19200
LCD_BOUNCE = 0.05
LCD_DISPLAY_ON = '\x18'
LCD_DISPLAY_CLEAR = '\x0C'
LCD_BACKLIGHT_ON = '\x11'
LCD_ROW = 0
LCD_ROW_MIN = 0
LCD_ROW_MAX = 4
LCD_COL = 0
LCD_COL_MIN = 0
LCD_COL_MAX = 20

class CharLCD:
    def __init__(self):
        self.connection = machine.UART(LCD_UART, baudrate=LCD_BAUDRATE)
        sleep(LCD_BOUNCE)
        self.connection.write(str(LCD_DISPLAY_ON))
        sleep(LCD_BOUNCE)
        self.clear
        self.connection.write(LCD_BACKLIGHT_ON)
        sleep(LCD_BOUNCE)

    def clear(self):
        self.connection.write(LCD_DISPLAY_CLEAR)
        sleep(LCD_BOUNCE)

    def print(self, message, *pos):
        LCD_ROW = 0
        LCD_COL = 0
        if pos:
            for i in range(len(pos)):
                if pos[i]:
                    if i == 0:
                        LCD_ROW = pos[i]
                        LCD_COL = 0
                    if i == 1:
                        LCD_ROW = pos[i - 1]
                        LCD_COL = pos[i]
        
        self.cursorPos(LCD_ROW, LCD_COL)
        self.connection.write(message)
        sleep(LCD_BOUNCE)

    def cursorPos(self, row, column):
        row = max(min(row, LCD_ROW_MAX), LCD_ROW_MIN)
        column = max(min(column, LCD_COL_MAX), LCD_COL_MIN)
        self.connection.write(chr(0x80 + row * LCD_COL_MAX + column))
        sleep(LCD_BOUNCE)
Von Dir empfohlene "Schönheitsoperationen" stehen noch aus. ;-)
Sirius3
User
Beiträge: 17844
Registriert: Sonntag 21. Oktober 2012, 17:20

Funktionen muß man aufrufen. Das gilt sowohl für gc.enable als auch für self.clear.
Eine for-Schleife über einen Index ist an sich schon nicht gut, aber wenn dann innerhalb der Schleife für jeden Indexwert per if noch unterschiedliche Sachen gemacht werden, dann ist das kompletter Unsinn.
Also kann man die Schleife auflösen:

Code: Alles auswählen

    if len(pos) >= 2:
        row = pos[0]
        column = pos[1]
    elif len(pos) == 1:
        row = pos[0]
        column = 0
    else:
        row = 0
        column = 0
Das ist immer noch sehr viel Code für sehr wenig Inhalt:

Code: Alles auswählen

    row = pos[0] if len(pos) >= 1 else 0
    column = pos[1] if len(pos) >= 2 else 0
Aber Default-Werte kann Python schon von sich aus, so dass ein viel lesbarerer Code übrigbleibt, ohne *-Magie:

Code: Alles auswählen

    def print(self, message, row=0, column=0):
        self.cursor_pos(row, column)
        self.connection.write(message)
        sleep(LCD_BOUNCE)
Alles zusammen:

Code: Alles auswählen

class CharLCD:
    def __init__(self):
        self.connection = machine.UART(LCD_UART, baudrate=LCD_BAUDRATE)
        sleep(LCD_BOUNCE)
        self.write(LCD_DISPLAY_ON)
        self.clear()
        self.write(LCD_BACKLIGHT_ON)

    def write(self, text):
        self.connection.write(text)
        sleep(LCD_BOUNCE)

    def clear(self):
        self.write(LCD_DISPLAY_CLEAR)

    def print(self, message, row=0, column=0):
        self.cursor_pos(row, column)
        self.write(message)

    def cursorPos(self, row, column):
        row = max(min(row, LCD_ROW_MAX), LCD_ROW_MIN)
        column = max(min(column, LCD_COL_MAX), LCD_COL_MIN)
        self.write(chr(0x80 + row * LCD_COL_MAX + column))
Benutzeravatar
gatonero
User
Beiträge: 21
Registriert: Montag 4. April 2022, 21:12

Vielen Dank für Deine Mühen! Ich lerne dadurch sehr viel. :-)
LukeNukem
User
Beiträge: 232
Registriert: Mittwoch 19. Mai 2021, 03:40

Alldieweil mir die bisher präsentierten Lösungen irgendwie nicht so recht gefallen wollten, habe ich mir da mal was überlegt.

Vorweg: da ich weder Micropython noch die entsprechende Hardware habe, ist das hier gezeigte nur auf meinem Desktop mit Python 3.8.10, 3.10.4 und Pypy 7.3.1 getestet. Die Type Hints habe ich wieder entfernt, nachdem ich gelesen habe, daß Micropython sie wohl nicht unterstützt.

Als bekennender Faulpelz hatte ich auch keine Lust, die LCD-Befehle aus dem Datenblatt von Parallax abzutippen, und habe sie stattdessen einfach mit pdfplumber aus dem PDF extrahiert (siehe docs/-Unterverzeichnis) und eine Library (lib/lcd_parallax.py) daraus autogeneriert. Da Hardwarehersteller hie und da aktualisierte Versionen ihrer Datenblätter publizieren, erschien mir das auch für mögliche künftige Änderungen sinnvoller.

Kernidee der Angelegenheit war, daß es (soweit ich das im Moment überblicke) verschiedene "Befehlsarten" für so ein LC-Display gibt: einfache Befehle wie "Licht einschalten", "LCD-Inhalte löschen", dann Befehle zum Schreiben der Ausgabe auf das LCD und zuletzt Befehle zur Positionierung des Cursors. Diese "Befehlsarten" werden in der Klasse LcdCommand (lib/lcdcommand.py) mit den Methoden "cmd()", "write()" und "goto()" abgebildet.

Außerdem werden das Display, auf welches geschrieben werden soll, die Klasse mit den einfachen Befehlen und das Dictionary mit den Positionierungsbefehlen dem Konstruktor der Klasse LcdCommand übergeben -- der Gedanke dahinter ist, daß eine Hardware, auf der Micropython läuft, womöglich sogar mehrere LD-Displays daran haben kann und diese nicht nur am ersten U(S)ART, sondern etwa auch an I2C oder SPI hängen können. Aus diesem Grund wollte ich die Befehle für konkrete LC-Displays entkoppeln, so daß unterschiedliche LC-Displays mit verschiedenen Befehlssätzen angesteuert werden können. Meine LcdCommand-Klasse sollte demzufolge im Prinzip auch mit allem klarkommen, das eine write()-Methode hat, siehe dazu auch die Klasse "DummyWriter" in demo.py mit ihrer statischen write()-Methode. Zuletzt muß dem Konstruktor die nach jedem Befehl einzuhaltende Pause übergeben werden, damit das LC-Display genügend Zeit hat, um den gerade gesendeten Befehl auszuführen.

Im Datenblatt habe ich gesehen, daß dort mehrere LC-Displays beschrieben werden, darunter auch solche mit lediglich zwei Zeilen und einer Zeilenlänge von nur 16 Zeichen. Dazu habe ich nichts gemacht (siehe weiter oben unter "Faulpelz") und überlasse Interessierten diesen Teil, ebenso wie die weitere Dokumentation, gerne als Übung. ;-)

Mein Code kann unter https://drive.google.com/file/d/1JqcQl6 ... sp=sharing heruntergeladen werden, die SHA256-Prüfsumme des 348 Kilobyte (356184 Byte) großen Zip-Archivs ist 3d2acd189d195c3b9e9b0c517389ca63e8c8e92100f85fa8acc3a2c03ab5680b. HTH, YMMV! ;-)
Benutzeravatar
gatonero
User
Beiträge: 21
Registriert: Montag 4. April 2022, 21:12

Puuh, der Fachmann staunt und der Laie wundert sich! :shock:

Wobei ich mich eher zu Letzteren zähle, mit meinen zwei bis drei Wochen Python-Kenntnissen. :oops:
  • Die Grundidee habe ich verstanden und finde sie genial. Das mit dem pdfplumber zu verstehen, hebe ich mir für sehr viel später auf.
  • Keine Ahnung, was das für Dinger in dem __pycache__ Ordner sind. Dieser Ordner ist auf jeden Fall nicht auf dem Board angekommen
  • Auf dem PC habe ich das fehlerfrei zum Laufen gekriegt. Auf dem ESP32 tut sich noch nichts. Das versuche ich dort erstmal zum Laufen zu kriegen und dann das Ganze zu verstehen.
Sirius3
User
Beiträge: 17844
Registriert: Sonntag 21. Oktober 2012, 17:20

Meiner Meinung nach ist das ein gutes (bzw. schlechtes) Beispiel für Overengineering. Die Kasse bringt einem nichts, wenn man wirklich ein LCD-Display ansprechen will. Die Positionsangaben lassen sich einfacher ausrechnen, wie __blackjack__ das ja schon geschrieben hatte.
Und ohne Funktionen, die auch die Konstanten verwenden, sind 90% davon nutzlos.
Gerade im Micropython-Umfeld will man eine kleine Klasse, die genau das macht, was man braucht.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Auch die ganzen Konstanten zur Definition der Sonderzeichen sind ueberfluessig, da eine durchnummerierte Konstante nun wirklich keinen Vorteil gegenueber einer Methode "define_special_char(number, data)" hat. Dafuer aber 8KB kostbaren Flash-Speicher abgeschenkt, nur fuer die Konstanten.
Benutzeravatar
gatonero
User
Beiträge: 21
Registriert: Montag 4. April 2022, 21:12

Eine Frage, was mus ich tun, um aus der Funktion cursorPos die ermittelten Werte zu erhalten, um sie in anderen Funktionen manipulieren kann? Ich denke dabei an eine Funkton, mit der eine per Parameter übergebenen Anzahl, die message nach links, rechts, oben oder unten verschoben werden kann.

Code: Alles auswählen

class CharLCD:
    def __init__(self):
        self.connection = machine.UART(LCD_UART, baudrate=LCD_BAUDRATE)
        sleep(LCD_BOUNCE)
        self.write(LCD_DISPLAY_ON)
        self.clear()
        self.write(LCD_BACKLIGHT_ON)

    def write(self, text):
        self.connection.write(text)
        sleep(LCD_BOUNCE)

    def clear(self):
        self.write(LCD_DISPLAY_CLEAR)

    def print(self, message, row=0, column=0):
        self.cursor_pos(row, column)
        self.write(message)

    def cursorPos(self, row, column):
        row = max(min(row, LCD_ROW_MAX), LCD_ROW_MIN)
        column = max(min(column, LCD_COL_MAX), LCD_COL_MIN)
        self.write(chr(0x80 + row * LCD_COL_MAX + column))[code]
Sirius3
User
Beiträge: 17844
Registriert: Sonntag 21. Oktober 2012, 17:20

`print` erwartet die absoluten Positionen row und column, wenn Du das relativ verändern willst, mußt Du das selbst programmieren:

Code: Alles auswählen

lcd = CharLCD()
text = " Laufschrift "
for row in range(10):
    self.print(text, row)
Benutzeravatar
gatonero
User
Beiträge: 21
Registriert: Montag 4. April 2022, 21:12

Damit komme ich sehr schnell über die Begrenzungen des LCDs hinaus und erhalte ungültige Positionen. Z.B. wenn die maximale Zeilen- oder Spaltenanzahl überschritten wird Deshalb möchte ich die Funktion

Code: Alles auswählen

def cursorPos(self, row, column):
    row = max(min(row, LCD_ROW_MAX), LCD_ROW_MIN)
    column = max(min(column, LCD_COL_MAX), LCD_COL_MIN)
    self.write(chr(0x80 + row * LCD_COL_MAX + column))[code]
verwenden, die immer gültige Werte liefert und diese Werte dann weiter verändern.
Sirius3
User
Beiträge: 17844
Registriert: Sonntag 21. Oktober 2012, 17:20

Das war ja auch nur ein Beispiel, für die richtige Einhaltung der Begrenzung mußt Du natürlich auch sorgen, in dem Du das so programmierst!
Die cursor_pos-Methode wird ja von `print` benutzt und sorgt nur dafür, dass der Text an einer bestimmten Stelle startet.
Antworten