RPi-Pico am LCD-Modul              

von Ralph Maas                       

Elektronik-Labor  Projekte  Mikrocontroller  Raspberry            




Motivation

Ich möchte ein (5V) LCD-Modul über einen I2C-Adapter am RPi-Pico betreiben. Mit einem Gehäuse und einem Taster soll daraus ein „Minimalaufbau“ für diverse Anwendungen werden.

Vorgehensweise
    • Die Bibliothek LiquidCrystal_I2C funktioniert bei mir mit dem RPi-Pico nicht. Mit der Bibliothek LiquidCrystal_PCF8574 geht es.
    • Diese Bibliothek verwendet die Wire-Bibliothek als Abstraktionsebene.
      In der Pico-Arduino-Boarderweiterung von Earle Philhower sind dort zwei Objekte Wire und Wire1 definiert, die die jeweilige I2C-Hardware-Einheit auswählen.
      Damit sind beliebige GPIO-PIN für I2C verwendbar.
    • Der Author von LiquidCrystal_PCF8574 - Matthias Hertel – hat auch eine weitere Bibliothek OneButton erstellt, die die Auswertung von Tastern vereinfacht.
    • Taster, Display und Logic-Level-Converter kommen in ein gemeinsames Gehäuse. Dazu muss ins Gehäuse ein Ausschnitt gesägt/gebohrt/geschnitten werden.
    • In das Gehäuse passen auch „Keystone-Module“, die externe Anschlüsse zur Verfügung stellen

Material
    • RPi-Pico
    • SparkFun Logic Level Converter Bi-Directional oder ähnliches von Adafruit
    • I2C-Modul (5V), 16x2 Zeichen
    • Gehäuse 1593NTBU 75 x 110 x 25 mm (aus ABS)
    • Gehäusereste (vom Ausschnitt Display) und Aceton für Abstandshalter und „einkleben“ des Tasters
    • Taster
    • Eine Lochrasterplatine
    • Zum Beispiel: Keystone Modul DELOCK 86468 RJ12-Buchse auf LSA (Schneid-Klemm-Technik)
      
Aufbau:
Offen:



Zusammengeklappt:



Seitlich:



Schaltplan
Der I2C-Converter ist für jeden der 4 Kanäle mit einem MOSFET und zwei Widerständen aufgebaut, nicht isolierend wie im Schaltplan:



Code

/ Ansteuerung eines 16x2 LCD-Displays über I2C auf dem RPi-Pico und Steuerung mit einem Taster
// beispielhaft werden 3 Seiten alternativ angezeigt, ein langes Drücken schaltet das Display dunkel
//
// Dieses Beispiel verwendet die Pico-Arduino Boarderweiterung von Earle Philhower (Version 2.6.3)
// nach Anregung des Buches "RPi Pico Schaltungen und Projekte" von Burkhard Kainka, Seite 5
// Einbindung über die Boardverwalter-URL https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json
// unter "Datei | Voreinstellungen" in der Arduino-IDE
//
// Die Library LiquidCrystal_I2C habe ich mit dem RPi-Pico nicht zum laufen bekommen. Mit dieser klappt es:
//
// Die Library LiquidCrystal_PCF8574 wird mit beliebigen I2C-PIN verwendet. Die Funktionen dazu sind beschrieben in:
// /home/username/.arduino15/packages/rp2040/hardware/rp2040/2.6.3/libraries/Wire/src/Wire.h
// /home/username/Arduino/libraries/LiquidCrystal_PCF8574/src/LiquidCrystal_PCF8574.h
// Die Library OneButton ist beschrieben in
// /home/username/Arduino/libraries/OneButton/src/OneButton.h

#include <Arduino.h>

#include <Wire.h> // Die Wire-Bibliotek stellt zwei Objekte zur Verfügung: Wire nutzt i2c0, Wire1 nutzt i2c1
#define WIRE Wire // Wire nutzt i2c0
//#define WIRE Wire1 // Wire1 nutzt i2c1
#define PIN_SDA 4 // mit i2c0 bzw. Wire geht: 0, 4, 8, 12, 16, 20, 24, 28
// i2c1 bzw. Wire1 geht: 2, 6, 10, 14, 18, 22, 26
#define PIN_SCL 5 // SCL-pin immer eine Nummer höher als SDA, also 1, 3, 5,...

#include <LiquidCrystal_PCF8574.h>
LiquidCrystal_PCF8574 lcd(0x27); // Adresse der PCF8574-Chips ist 0x27
#define LCD_LINES 2 // Anzahl Zeilen
#define LCD_CHARS 16 // Anzahl Spalten
#define BACKLIGHT 255 // Wert für Hintergrundbeleuchtung an (jeder Wert ungleich null möglich)

#include "OneButton.h"
#define PIN_INPUT 14
OneButton button(PIN_INPUT, true, true); // 2.Parameter: activeLow = true, weil von Taster gegen GND geschalten
// 3.Parameter: pullupActive = true, weil wir einen Pullup wollen

bool show = true; // show = true - Hintergrundlicht an, Anzeige sichtbar
int seite = 1, alt_seite = 2; // Erst Seite 1 anzeigen
const int seite_max = 3; // Im Beispiel gibt es 3 Seiten

void setup() {
Serial.begin(115200);
setupDisplay();
button.attachClick(myClickFunction); // Einfacher Klick --> blättert durch die Seiten oder schaltet hell
button.attachLongPressStart(myLongClickFunction); // Langer Klick --> nur zum Dunkel schalten
button.setClickTicks(50); // Default erkennt einzelnen Klick erst nach 400ms, jetzt schon nach 50ms

} // setup()

void loop() {
if (show)
lcd.setBacklight(BACKLIGHT); // Hintergrundlicht anschalten
else
lcd.setBacklight(0); // Hintergrundlicht ausschalten

if (seite != alt_seite) {
lcd.home();
lcd.clear();
if (seite ==1) {
Serial.println("in loop - Seite 1 wird angezeigt");
lcd.print("Seite 1");
}
else if (seite == 2) {
Serial.println("in loop - Seite 2 wird angezeigt");
lcd.print("Seite 2");
} else {
Serial.println("in loop - Seite 3 wird angezeigt");
lcd.print("Seite 3");
} // if
alt_seite = seite;
}
button.tick(); // Überwacht den Button
} // loop()


// this function will be called when the button was pressed 1 time and them some time has passed.
void myClickFunction() {
if (!show) {
show = true;
Serial.println("in myClickFunction. Hintergrundlicht war aus, jetzt an");
} else {
seite+=1;
if (seite > seite_max) seite=1;
Serial.print("in myClickFunction. Hintergrundlicht war an, Seite jetzt = ");
Serial.println(seite);
}
} // myClickFunction

void myLongClickFunction() {
Serial.println("in myLongClickFunction. Show jetzt false ");
show = false;
} // myLongClickFunction

void setupDisplay () {
int error;
bool WireSucess = true;

Serial.println("I2C...");
sleep_ms(5000); // 5 Sekunden warten auf Serielles Display
WireSucess = WIRE.setSDA(PIN_SDA); // Das muss vor Wire.beginn() aufgerufen werden
if (!WireSucess) Serial.println("Fehler bei SDA"); // Dies wird nie aufgerufen, bei Fehler hängt sich Prozess auf (wohl wegen panic())
WIRE.setSCL(PIN_SCL); // Das muss vor Wire.beginn() aufgerufen werden
WIRE.begin();
Serial.print("initialisiert auf PIN SDA=");
Serial.print(PIN_SDA);
Serial.print(" und PIN SCL=");
Serial.println(PIN_SCL);

Serial.print("Probing for PCF8574 on address 0x27...");
WIRE.beginTransmission(0x27);
error = WIRE.endTransmission();

if (error == 0) {
Serial.println(": LCD found.");
show = true;
lcd.begin(LCD_CHARS, LCD_LINES, WIRE); // WIRE wird definiert als Wire oder Wire1, für i2c0 bzw. i2c1

} else {
Serial.println(": LCD not found.");
} // if
} // setupDisplay
---------------