Projekte

Anzeigen von Zeichen auf einem LCD mit einem EFM8-Mikrocontroller

Raspberry Pi 3: Sysinfo am 2x16 Zeichen LCD-Display anzeigen (Januar 2019).

Anonim

Anzeigen von Zeichen auf einem LCD mit einem EFM8-Mikrocontroller


Erfahren Sie, wie Sie Zeichen mithilfe eines Bildeditors entwerfen und auf einem LCD anzeigen, das von einem EFM8-Mikrocontroller gesteuert wird.

Einführung

In einem früheren Artikel wurde die Verwendung der SPI-Funktionalität eines EFM8-Mikrocontrollers zur Anzeige einer horizontalen Bildlaufzeile auf einem 128 x 128 Pixel großen LCD untersucht. In diesem Artikel werden wir dieselbe Low-Level-Schnittstelle verwenden, um die LCD-Anzeige mit allen Großbuchstaben des Alphabets zu aktualisieren. Noch besser: Sie lernen Techniken, mit denen Sie effizient jedes Zeichen oder Symbol entwerfen und anzeigen können, das mit 10 vertikalen und 8 horizontalen Pixeln angemessen dargestellt werden kann.

Vorherige Artikel in dieser Serie

  • Die EFM8-Serie von Silicon Laboratories: Eine leistungsstarke neue Embedded-Entwicklungsplattform
  • LCD über SPI steuern: Eine Einführung in die Projektentwicklung mit einem EFM8 Microcontroller

Benötigte Hardware / Software

  • SLSTK2000A EFM8-Evaluierungsboard
  • Simplicity Studio integrierte Entwicklungsumgebung
  • Scilab

Projektübersicht

Ziel ist es, alle Großbuchstaben auf einem 128 x 128 Pixel großen LCD-Display zu entwerfen und anzuzeigen. Der Text wird im typischen Textverarbeitungsformat auf dem LCD-Bildschirm ausgegeben: Ein Cursor verfolgt die Position, an der das nächste Zeichen angezeigt wird, und Sie geben einfach ein neues Zeichen ein, indem Sie eine Funktion namens InsertCharacter () aufrufen.

Die Schriftart ist ein benutzerdefinierter Zeichensatz mit fester Breite (und fester Höhe), der mit den im nächsten Abschnitt beschriebenen Techniken erstellt wurde. Die feste Zeichengröße beträgt 10 vertikale Pixel mal 8 horizontale Pixel (obwohl das Zeichen tatsächlich auf 9 mal 7 Pixel beschränkt ist, da eine leere Zeile und eine leere Spalte enthalten sind, um eine Trennung zwischen benachbarten Zeichen zu ermöglichen). Diese Größe wurde aus verschiedenen Gründen gewählt. Das LCD ist 128 Pixel breit, so dass 8 horizontale Pixel sicherstellen, dass eine gerade Anzahl von Zeichen über den Bildschirm passt. Wir verwenden 10 vertikale Pixel anstelle von 8, weil die resultierenden dünneren Buchstaben für das Auge etwas angenehmer sind. Diese Abmessungen ergeben auch Buchstaben, die groß genug sind, um leicht lesbar und dennoch klein genug zu sein, so dass das LCD eine bedeutungsvolle Anzahl von Zeichen gleichzeitig anzeigen kann. Der vielleicht wichtigste Grund ist jedoch der folgende: Der Code zum Kopieren der Pixeldaten von der Zeichenmatrix in den LCD-Datenpuffer ist mit einer Breite von 8 Pixeln viel einfacher, da die Bits, die die Pixelzustände darstellen, mit Bytegrenzen ausgerichtet sind. Das bedeutet, dass wir die LCD-Daten korrekt aktualisieren können, indem wir saubere Byteoperationen anstelle von unbeholfenen (und weniger effizienten) Bitoperationen verwenden, bei denen die Bits von einem Byte in einen Teil eines Bytes und einen Teil eines anderen Bytes kopiert werden müssen.

Gestalten von Charakteren

Das Übersetzen von visuellen Symbolen in LCD-kompatible Daten ist ein ernsthaft nicht intuitiver Prozess: Wer könnte den Buchstaben G zeichnen, indem er einem Byte-Array eine Reihe von hexadezimalen Werten zuweist "// www.getpaint.net/index.html" target = "_ blank" > Paint.NET, eine leistungsstarke und kostenlose Anwendung zur Bild- und Bildbearbeitung.

Erstellen Sie eine leere Leinwand und ändern Sie die Größe auf 10 Pixel hoch und 8 Pixel breit, und zoomen Sie vollständig hinein. Verwenden Sie das Stiftwerkzeug, um einzelne Pixel einzufügen, bis der Buchstabe nach rechts zeigt, und speichern Sie das Bild dann als Graustufen-BMP-Datei.

Jetzt ist es Zeit für Scilab, die Sie hier herunterladen können. Scilab ist eine freie numerische Berechnungssoftware ähnlich MATLAB. Wie bei MATLAB ist Scilab nützlich für mehr als nur Zahlen. In diesem Projekt werden wir die Zeichenbilder analysieren und in C-Code umwandeln, den wir kopieren und in unsere EFM8-Quelldateien einfügen können. Zusätzlich zu Scilab selbst müssen Sie die Image Processing Design Toolbox installieren. Dies wird mit dem ATOMS-Modul-Manager von Scilab problemlos erreicht:

Die einfachste Art, Scilab zu verwenden, besteht darin, einzelne Befehle in das Konsolenfenster einzugeben. Spannend wird es jedoch, wenn Sie diese Befehle mit dem SciNotes-Texteditor kombinieren und organisieren, der es Ihnen ermöglicht, Scilab-Anweisungen in eine kohärente Quellcodedatei zu integrieren, die wie eine in einer höheren Programmiersprache geschriebene Anwendung ausgeführt wird. Hier ist ein Teil des SciNotes-Skripts (LCD_image_handler.sce), das für dieses Projekt verwendet wurde:

Code

 ImageFilename = uigetfile(("*.bmp")); if(length(ImageFilename) == 0) break end CurrentImage = ReadImage(ImageFilename); CurrentImage = SegmentByThreshold(CurrentImage, 100); CurrentImage = flipdim(CurrentImage, 2); PixelData = uint8(zeros(10, 1)); for row = 1:10 for column = 1:8 if (CurrentImage(row, column) == %T) PixelData(row) = bitset(PixelData(row), column, 1); else PixelData(row) = bitset(PixelData(row), column, 0); end end end 

Code herunterladen

LCD_image_handler.sce wird wie folgt ausgeführt: Zuerst öffnet es einen Dateidialog; Wählen Sie die BMP-Datei aus, die Sie verarbeiten möchten.

Das Bild wird in Schwarz-Weiß konvertiert (falls irgendwelche Pixelwerte nicht genau 0 oder 255 sind) und jedes Bit in einem 10-Byte-Array wird gesetzt oder gelöscht, abhängig davon, ob das entsprechende Pixel schwarz oder weiß ist. Das 10-Byte-Array repräsentiert die Größe eines Zeichens (dh 10 vertikale Pixel mal 8 horizontale Pixel): Ein Byte stellt die 8 horizontalen Pixelwerte bereit, und somit enthält ein 10-Byte-Array 10 Zeilen mit jeweils 8 horizontalen Pixeln. Schließlich werden der Array-Name (der aus dem Dateinamen stammt) und die Pixeldaten mit den printf () - Routinen an die Scilab-Konsole ausgegeben. Dieser Vorgang wird wiederholt, bis Sie im Dateidialog auf "Abbrechen" klicken.

Diese Variablendefinitionen können direkt in Quelldateien in unserem EFM8-Projekt kopiert und eingefügt werden. Das Skript generiert auch Code, mit dem diese Variablen in der Headerdatei des Projekts deklariert werden, sodass die endgültige Ausgabe wie folgt aussieht:

Wie Sie sehen können, ist dieser Prozess effizient und vollständig flexibel. Mit diesem SciNotes-Skript können Sie schnell LCD-kompatible Pixeldaten für jedes Symbol erstellen, das Sie in ein 10-Zeilen-auf-8-Spalten-Bild zeichnen können.

Port I / O

Die Port-I / O-Konfiguration ist identisch mit der, die wir im vorherigen SPI-Projekt verwendet haben.

Die SPI-Signale werden auf die entsprechenden Port-Pins abgebildet, mit Ausnahme des Chip-Select-Signals, das wir manuell über P0.1 ansteuern.

Peripheriegeräte und Interrupts

Die Einrichtung der Peripherie und des Interrupts ist ähnlich wie zuvor: SPI ist für die Kommunikation mit dem LCD-Modul konfiguriert, Timer2-Interrupts regeln die Bildrate und Timer4 wird für kurze Verzögerungen verwendet. Der einzige Unterschied besteht darin, dass Timer2 für eine Interrupt-Frequenz von 5 Hz anstelle von 60 Hz konfiguriert ist. In diesem Projekt wird jedes Mal, wenn Timer2 überläuft, ein neuer Buchstabe auf den LCD-Bildschirm gedruckt, und eine langsamere Aktualisierungsfrequenz erleichtert das Beobachten der Zeichen, bevor sie überschrieben werden.

Firmware

Im vorherigen Projekt verwendeten wir den Single-Line-Update-Modus des LCDs: Nach dem Ansteuern der Chip-Auswahl auf logisch hoch sendet das EFM8 das Modus-Auswahl-Byte, dann die Zeilenadresse und dann die 128 Bit Pixeldaten. Die Übertragung wird mit zwei Dummy-Bytes abgeschlossen, und die Chipauswahl kehrt auf logisch niedrig zurück. Dieser Modus ist für nicht ambitionierte Anwendungen geeignet, aber die neue Firmware ist anders. Die Pixelwerte für das gesamte LCD werden in einem einzigen zweidimensionalen Array gespeichert, und alle diese Datenbits werden immer dann zum LCD übertragen, wenn der Timer2-Interrupt der Firmware befiehlt, das Display zu aktualisieren. Mit anderen Worten, wir senden viel mehr Daten an das LCD. ( Anmerkung: In dieser speziellen Implementierung steuert der Mikrocontroller nur die ersten 60 LCD-Leitungen und nicht alle 128, da nur 1024 Byte On-Chip-RAM für die Anwendung verfügbar sind; ein Array, das groß genug für das gesamte LCD ist, würde 2048 Byte benötigen Diese Einschränkung kann in einem benutzerdefinierten Design leicht behoben werden, indem eines der codekompatiblen EFM8-Geräte mit 4352 Byte RAM ausgewählt wird.

Wenn all diese zusätzlichen Daten auf das LCD-Display gehen, ist es sinnvoll, den "Mehrfachzeilen-Aktualisierungsmodus" zu verwenden. Wie der Name schon sagt, erlaubt dieser Modus, die Pixelwerte für mehrere Zeilen während einer SPI-Übertragung zu aktualisieren. Dies bedeutet, dass wir eine neue Zustandsmaschine in der SPI-Interrupt-Routine benötigen:

Die andere wichtige Ergänzung der Firmware ist die Funktion, bei der die Pixeldaten von den von Scilab erzeugten Arrays in das zweidimensionale Array eingefügt werden, das die Pixeldaten für das gesamte LCD enthält:

Code

 void InsertCharacter(unsigned char *LCD_Character) //the input to this function is a pointer to a pixel data array { unsigned char n; unsigned char row_pixel; unsigned char column_byte; //rows are handled on a pixel-by-pixel basis row_pixel = LCDCursor(ROW); //columns are handled on a byte-by-byte basis, because one character width is 8 bits column_byte = LCDCursor(COL); /*each byte from the pixel data array is copied to LCDDisplayData, starting with the current cursor position*/ for(n = 0; n < CHAR_HEIGHT; n++) { LCDDisplayData(row_pixel)(column_byte) = *LCD_Character; LCD_Character++; //point to the next byte in the array row_pixel++; //the next byte corresponds to pixel data for the next line } LCDCursor(COL)++; //move the cursor one character width to the right /*if the cursor has reached the end of the line, return the cursor to the far left and move it down by one character height*/ if(LCDCursor(COL) == NUM_LINE_DATA_BYTES) { LCDCursor(COL) = 0; LCDCursor(ROW) = LCDCursor(ROW) + CHAR_HEIGHT; if(LCDCursor(ROW) == NUM_LINES) //if the cursor has reached the end of the display area, LCDCursor(ROW) = 0; //return the cursor to the top line } while(UPDATE_LCD == FALSE); //wait here until Timer2 initiates an LCD update UPDATE_LCD = FALSE; UpdateAllLCDLines(); } 

Code herunterladen

Wenn Sie den obigen Code einsehen und die Kommentare lesen, sollten Sie eine gute Vorstellung davon bekommen, wie das funktioniert. Beachten Sie, dass diese Routine sowohl das LCD-Pixeldatenfeld aktualisiert als auch die Cursorposition verwaltet.

Die Gesamtfunktionalität dieses Projekts besteht darin, wiederholt alle Großbuchstaben von A bis Z, dann von A bis Z usw. zu drucken. Der grundlegende Programmablauf ist der folgende:

  • Der Mikrocontroller löscht das LCD.
  • Timer2 ist aktiviert.
  • Das Programm tritt in eine Endlosschleife ein und verwendet die Funktion InsertCharacter (), um A, dann B, dann C und so weiter zu Z und dann wieder zu A zu drucken.
  • Die Funktion InsertCharacter () (siehe obigen Codeausschnitt) aktualisiert das LCD-Pixeldatenfeld, verwaltet den Cursor, wartet, bis Timer2 das Flag für eine LCD-Aktualisierung setzt, und initiiert dann eine Aktualisierung über die Funktion UpdateAllLCDLines ().
  • Der Timer2-ISR setzt das Aktualisierungsflag nur dann, wenn die SPI-Statusvariable angibt, dass die SPI-Schnittstelle im Leerlauf ist. Dies stellt sicher, dass die Funktion InsertCharacter () nicht versucht, eine neue SPI-Übertragung einzuleiten, bevor die vorherige Übertragung abgeschlossen ist.

Video

Nächster Artikel in der Serie: Kommunizieren mit einem EFM8 Microcontroller über USB

Gib diesem Projekt einen Versuch für dich selbst! Holen Sie sich die Stückliste.