Arduino LCD-Display am I2C-Bus

Den Testaufbau vom Beitrag „Arduino PCF8574 lesen und schreiben“ haben wir erweitert und die I2C-LCD-Anzeige mit an den Bus angeschlossen.

Das Beispiel soll zeigen wie leicht es ist unser Textdisplay über den I2C-Bus anzusprechen und Texte auszugeben.

Beim Testen des Programms haben wir jedoch mit ein paar Eigenheiten des Arduino festgestellt.

  1. Unsere Kommandos für die Anzeige beginnen mit einem Backslash-Zeichen (\).
    Die Arduino-IDE hat ein Problem mit dem \-Zeichen im Code. Es erscheint die Fehlermeldung:
    error: unknown escape sequence ‚\B‘
  2. Die maximale Anzahl der zu übertragenden Bytes auf dem Bus ist auf 32 begrenzt.
    Es können nur 32 Bytes in einem Rutsch auf dem Bus verschickt werden.
    Die angeschlossene LCD-Anzeige hat 4*20 Zeichen also 80 Bytes was die Kommunikation etwas schwieriger macht.
  3. Der Befehl Wire.endTransmission() überträgt noch einmal die Slaveadresse mit einem I2C-Stop.
    Das bringt momntan leider ein zusätzliches Zeichen auf das Display „`“ = 60hex

Hier die Lösungen

  1. Statt das Backslash-Zeichen im Code zu schreiben übertragen wir mit dem Befehl Wire.write(92); das Zeichen als ASCII-Wert.
  2. Dieses Problem kann man lösen indem die Zeilen des Displays einzeln geschrieben werden.
    Dazu muss vorher der Cursor auf der Anzeige, z.B. mit dem Befehl \GO:01,01;, positioniert werden.
    Das Kommando hat 10 Bytes, der Text für eine Zeile hat 20 Bytes.  In Summe also unter 32 Bytes – Problem gelöst 🙂
  3. Unsere Anzeige interpretiert alle Zeichen die ohne Pause von 5 ms zur Anzeige geschickt werden als zusammengehörig.
    Wenn also innerhalb 5ms die Slave-Adresse noch einmal geschickt wird interpretiert die Anzeige dieses Byte als Zeichen.
    Wir werden das Problem in den nächsten Tagen durch einen neuen Firmwarestand lösen.

Im Beitrag Sniffer Funktion funktioniert können Sie sehen wie man mit dem I2C-USB-Modems den Datenverkehr auf dem Bus „belauschen“ kann. Die gesendeten Bytes zum Slave werden wie mit einem Datenlogger erfasst und angezeigt.

Hier das Demo-Programm für den ARDUINO

/* 
 ==============================================
Test I2C-LCD-Anzeige über I2C am ARDUINO
==============================================
*/

#include <Wire.h>

#define I2C_IN_ADDR 112 >> 1 // I2C-INPUT-Addresse als 7 Bit
#define I2C_OUT_ADDR 64 >> 1 // I2C-OUTPUT-Addresse als 7 Bit
#define I2C_LCD_ADDR 96 >> 1 // I2C-LCD-Addresse als 7 Bit


byte WERT=0;
byte OUT_INV=0;
byte ALTWERT=0;

String Text="";              // 4x20 zeichen definieren
char OutArray[80] = { };     // Out-Array mit 80 zeichen definieren

void setup() {
  Serial.begin(9600);       // Serielle Schnittstelle konfigurieren
  Wire.begin();             // I2C-Pins definieren

  // setzten aller Bits der Eingabekarte auf 1
  // -----------------------------------------
  Wire.beginTransmission(I2C_IN_ADDR);   // Start Übertragung zum PCF8574
  Wire.write(0xFF);                      // Alle Bits sind Eingänge
  Wire.endTransmission();                // Ende
}

void loop() { 

  // Einlesen der Bits aus der I2C-INPUT Karte
  // ------------------------------------------
  Wire.requestFrom(I2C_IN_ADDR, 1);    // Ein Byte (= 8 Bits) vom PCF8574 lesen
  while(Wire.available() == 0);        // Warten, bis Daten verfügbar   
  WERT = 255 - Wire.read();            // in invertierte Eingabe wandlen     
  Wire.endTransmission(true);
  
  // Ausgeben der gleichen Bits an die I2C-OUTPUT Karte
  // --------------------------------------------------   
  OUT_INV = 255 - WERT;                 // in invertierte Ausgabe wandlen 
  Wire.beginTransmission(I2C_OUT_ADDR); // Start Übertragung zum PCF8574
  Wire.write(OUT_INV);                  // Wert schreiben
  Wire.endTransmission();               // Ende


  if (WERT == 0) {
    ALTWERT = 0;
  }
    
  if (WERT > ALTWERT){
    delay(100);                          // Taste entprellen
    ALTWERT = WERT;                      // Kommandos nur einmal absetzen
    Serial.print(WERT);
    
    
    // =========== Hintergrundbeleuchtung EIN ===========
    if (WERT & B00000001) {                  // Eingang 0 = Licht EIN
      Wire.beginTransmission(I2C_LCD_ADDR);  // Start Übertragung
      Wire.write(92);                        // Backslash-Zeichen
      Wire.write("BL:ON");                   // Kommando absetzen
      Wire.endTransmission();                // Ende
    }

    // =========== Hintergrundbeleuchtung AUS ===========
    if (WERT & B00000010) {                 // Eingang 1 = Licht AUS
      Wire.beginTransmission(I2C_LCD_ADDR); // Start Übertragung
      Wire.write(92);                       // Backslash-Zeichen
      Wire.write("BL:OFF");                 // Kommando absetzen
      Wire.endTransmission();               // Ende
    }

    // ================ Display löschen ================
    if (WERT & B00000100) {                 // Eingang 2 = CLR
      Wire.beginTransmission(I2C_LCD_ADDR); // Start Übertragung
      Wire.write(92);                       // Backslash-Zeichen
      Wire.write("CLR");                    // Kommando
      Wire.endTransmission();               // Ende
    }

    // ================ Text auf Display ausgeben ================
    if (WERT & B00001000) {                 // Eingang 3 = langen Text ausgeben

      Wire.beginTransmission(I2C_LCD_ADDR); // Start Übertragung
      Wire.write(92);                       // Backslash-Zeichen
      Wire.write("CLR");                    // Kommando LCD löschen
      Wire.endTransmission();               // Ende   
      delay(15);    
    
      Wire.beginTransmission(I2C_LCD_ADDR);  // Start Übertragung
      Wire.write(92);                        // Backslash-Zeichen
      Wire.write("GO:01,01;");               // Springe in die 1 . Zeile
      Wire.write(" Hallo LCD-Display  ");    // Text 1. Zeile
      Wire.endTransmission();                // Ende    
      delay(15); 

      Wire.beginTransmission(I2C_LCD_ADDR);  // Start Übertragung
      Wire.write(92);                        // Backslash-Zeichen
      Wire.write("GO:02,01;");               // Springe in die 2. Zeile
      Wire.write("====================");    // Text 2. Zeile
      Wire.endTransmission();                // Ende   
      delay(15);      
      
      Wire.beginTransmission(I2C_LCD_ADDR);  // Start Übertragung
      Wire.write(92);                        // Backslash-Zeichen
      Wire.write("GO:03,01;");               // Springe in die 3. Zeile
      Wire.write("Text in der Zeile 3 ");    // Text 3. Zeile    
      Wire.endTransmission();                // Ende     
      delay(15);      
      
      Wire.beginTransmission(I2C_LCD_ADDR);  // Start Übertragung
      Wire.write(92);                        // Backslash-Zeichen
      Wire.write("GO:04,01;");               // Springe in die 4. Zeile
      Wire.write("Text in der Zeile 4 ");    // Text 4. Zeile    
      Wire.endTransmission();                // Ende      
    }
  }
}

Wenn man die Adresse des Displays auf 98dez = 62hex ändert wird ein anderes Zeichen geschrieben. Bis die neue Firmware da ist kann man das Problem umgehen indem man ein Kommando z.B. „Display ON“ nach der letzten Textausgabe schickt. Das Programm würde dann so aussehen

      Wire.beginTransmission(I2C_LCD_ADDR);  // Start Übertragung
      Wire.write(92);                        // Backslash-Zeichen
      Wire.write("CLR");                     // Kommando
      Wire.endTransmission();                // Ende
      delay(15);
      
      Wire.beginTransmission(I2C_LCD_ADDR);  // Start Übertragung
      Wire.write(" Hallo LCD-Display");    // Text 1. Zeile
      Wire.endTransmission();
      delay(15);
      
      Wire.beginTransmission(I2C_LCD_ADDR);  // Start Übertragung
      Wire.write(92);                        // Backslash-Zeichen
      Wire.write("DI:ON");                   // Kommando
      Wire.endTransmission();                // Ende

Im Datenlogger-Fenster vom I2C-USB-Modem sieht man die einzelnen Befehle:

USB-Modem_Listen_2

  • Kommando \CLR 
    Blauer Kasten
  • Textausgabe  „Hallo LCD-Display“
    grüner Kasten
  • Kommando \DI:ON
    gelber Kasten

 Rot eingekreist die Slaveadresse (62hex) die vom ARDUINO am Ende verschickt wird.

 

 

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.