2004 LCD + PCF8574A + PCA9685

Seit Jahr und Tag wird die i2c-Anbindung von zeichenbasierenden LCDs mit zwei bzw. vier Zeilen mit dem PCF8574A erledigt: ein 8-Bit I/O Expander.

Technisch werden von den 8 Bit die Displayleitungen wie folgt bedient: D0-D3, RS, RW und EN. Damit bleibt ein Bit übrig, üblicherweise geht das auf einen Transistor und kann das LED am Display an- und ausschalten.

Damit ist Dimmen nur sehr eingeschränkt möglich: ständiges Schalten via i2c-Bus. Nicht gut, es ergibt einen vollbeschäftigter Bus und Prozessor…

Lösung: einen PCA9685 16-channel 12-bit PWM LED Controller nehmen. Der kostet zirka 2 Euro und ist beim Chinaman bereits auf einer PCB zu kaufen.

Die Steckverbinder wurden komplett entfernt, die PCB mit Isopropyl gereinigt und mit der Displaycontroler-PCB verklebt. Auf der Rückseite sind die entsprechenden Verdrahtungen vorgenommen worden, alles total einfach. Die Stromversorgungsleitung ruhig kräftig ausführen, SDA und SCL kann in CUL erstellt werden.

Eine kleine Schraube mit dem Kopf auf dem Display aufgeklebt gibt die notwendige Halterung.

Die Steckleiste zum Anschluß wird um zwei Beine gekürzt, das LCD wird direkt zum PWM-Modul verdrahtet. Ich habe Port 4 gewählt, weil da wenig im Weg war. Die Lötbrücken A1 und A2 sind geschlossen, um die Adresse einzustellen.

Später, wenn nachdem alles funktionierte, wurden noch die beiden Power-LED entfernt.

Als Code könnte eine der vielen Bibliotheken für den PCA9685 gewählt werden. Ich habe stattdessen die direkte Implementation gewählt:

Select
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
const byte PCA9685addr = 0x46;
const byte PCA9685_MODE1 = 0x00;
const byte PCA9685_MODE2 = 0x01;
const byte PCA9685_PRESCALE = 0xfe;
const byte LED0_ON_L = 0x6;
const byte LCDdisplayport = 4; // verdrahtungsspezifisch

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void PCA9685write(uint8_t addr, uint8_t data) {
  Wire.beginTransmission(PCA9685addr);
  Wire.write(addr);
  Wire.write(data);
  Wire.endTransmission();
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void SetPWMHelligkeit(uint8_t num, byte prozent) {
  // reset
  static boolean needreset = true;

  if (needreset) {
    // reset the device
    PCA9685write(PCA9685_MODE1, (byte)0x01);
    delay(2);
    // set up for auto increment
    PCA9685write(PCA9685_MODE1, (byte)0x20);
    delay(2);
    PCA9685write(PCA9685_MODE2, (byte)B00000100);

    needreset = false;
  }

  int on = 4096.0 / 100.0 * prozent;
  int off = 4096.0 / 100.0 * (100 - prozent);

  Wire.beginTransmission(PCA9685addr);
  Wire.write(LED0_ON_L + 4 * num);
  Wire.write(on);
  Wire.write(on >> 8);
  Wire.write(off);
  Wire.write(off >> 8);
  Wire.endTransmission();
}

Im Übrigen haben die Module alle die gleiche Problematik: jedes Modul bringt seine eigenen Pullup-Widerstände mit, meist 10k. Somit liegen bereits 2 × 10K Pullup, also 5k an.

Wer den i2c-Bus vernünftig betreiben will, sollte also auch die entfernen.

Ansonsten bleibt: kein Fortschritt. Theoretisch gibt es kombinierte LED-Treiber plus I/O-Bit-Port-Expander in einem i2c-IC. Praktisch am Markt jedoch nicht.