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.
- 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‘„ - 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. - 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
- Statt das Backslash-Zeichen im Code zu schreiben übertragen wir mit dem Befehl Wire.write(92); das Zeichen als ASCII-Wert.
- 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 🙂 - 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:
- 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.