I2CScanner Adressrückgabe

Hallo,
ich möchte wahlweise ein I2C Display LCD 2004 oder ein LCD 1602 in meinem Projekt nutzen.

Da ich nur ein I2C-Objekt habe - nämlich das Display könnte der
I2CScanner die Adresse ermitteln und eine gefundene Adresse als Rückgabewert bereitstellen.

Es würde auch reichen die Adressen 0x27 = 39dez und 0x3F = 63dez zu testen.

Dann könnte ich die Adresse in der Initialisierung eintragen.

#include <LiquidCrystal_I2C.h>

I2CScanner();  // Originalsketch in TAB

// LCD2004
//LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); //=39dez
// LCD1602  
LiquidCrystal_I2C lcd(0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); //=63dez

void setup()
{
    lcd.begin(40,4);
    //lcd.begin(16,2);
    lcd.setCursor(0,0);
    lcd.print("Hello, world!");
    delay(1000);
}
 
void loop()
{
  lcd.setCursor(0,0);
  lcd.print("Sek. seit Start");
  lcd.setCursor(0,1);
  lcd.print(millis()/1000);
  lcd.setCursor(0,2);
  lcd.print("3. Zeile");
  lcd.setCursor(0,3);
  lcd.print ("4. Zeile");
  
}

Hast du auch eine Frage?

Und nein, du kannst da nicht so einfach die vom Scanner ermittelte Adresse automatisch eintragen lassen. Bei einem dynamisch erzeugten Objekt, wäre das einfacher.

Am einfachsten wäre es, die Klasse so weit aufzubohren, daß man die Adresse nachträglich ändern kann.

Danach kämen zwei Objekte, und eine Referenz die auf das gefundene Display zeigt.

Mit Klassen etc. hab ich gar keinen Plan.

Wenn ich aber etwas auf eine I2C-Adresse ausgebe muss es ja eine Rückmeldung geben.

Also quasi ein Lebenszeichen.

Mit einer Ausgabe auf 0x27 würde ich ja wissen ob ein 2004 vorhanden ist.

Andernfalls das 3F - oder gar keins.

Da tut sich für mich eine neue Baustelle auf - das I2C Protokoll.

Du kannst ja nachschauen, wie es der Scanner macht. Ein Verständnis des I2C Protokolls ist nicht unbedingt notwendig, um die Funktionen/Methoden zu verstehen, welche die Bibliotheken zur Verfügung stellen.

Sollte doch funktionieren. Scannen, den Ausgsbewert in die init einfügen und weiter gehts.

Leopoldi: Wenn ich aber etwas auf eine I2C-Adresse ausgebe muss es ja eine Rückmeldung geben.

Richtig, geht so (Quelle):

Wire.beginTransmission(I2CAdd);
fehler = Wire.endTransmission();
if (fehler == 0) {...}

Ich setze Default ein 1602 Display auf 0x3F

Im Setup prüfe ich ob ein 2004 auf 0x27 vorhanden ist - wenn ja versuche ist dies zu überschreiben. Aber da fehlt mir das Knoff hoff :-))

    void setup() {
      
      Serial.begin(9600);   // für Testausgaben

      Wire.begin();
      //    Wire.setClock(400000L);
      Wire.beginTransmission(0x27);
      fehler = Wire.endTransmission();
      if (fehler == 0) {
        I2CAdr = 0x27;  // ja 2004 vorhanden=  Adr setzen
        Serial.println( );
        Serial.print("I2C- 0x");
        Serial.print(0x27, HEX);
        Serial.println(" gefunden!");
        
 //Überschreiben geht nicht !!!!!!!!!!!!!!
        LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

Ein statischer Konstruktor zur Laufzeit ist wenig hilfreich. Das erzeugte Objekt wird beim Verllassen von setup() wieder gelöscht.

So ist es wohl…

Dynamische Objekte sind auf AVR eher böse.
Aber wenn es nur ein mal zu Anfang erstellt wird, mag es gehen.

Man bedenke, der reservierte Speicher wird von der IDE nicht als Ram Verbrauch angezeigt.

Hier mal eine solche Variante:
(völlig ungetestet)

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C *lcd;
byte DisplayAdr = 0;

bool hasI2Cadress(byte adr)
{
  Wire.beginTransmission(adr);
  return !Wire.endTransmission();
}

// LCD2004
// LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); //=39dez
// LCD1602  
// LiquidCrystal_I2C lcd(0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); //=63dez

void setup()
{   
    Wire.begin();
    if(hasI2Cadress(0x27))                DisplayAdr = 0x27;
    if((!DisplayAdr)&&hasI2Cadress(0x3F)) DisplayAdr = 0x3F;

    if(DisplayAdr) lcd = new LiquidCrystal_I2C(DisplayAdr, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
    if(0x27 == DisplayAdr) lcd->begin(16,2);
    if(0x3F == DisplayAdr) lcd->begin(20,4);
    lcd->setCursor(0,0);
    lcd->print("Hello, world!");
    delay(1000);
}
 
void loop()
{
  lcd->setCursor(0,0);
  lcd->print("Sek. seit Start");
  lcd->setCursor(0,1);
  lcd->print(millis()/1000);
  if(0x3F == DisplayAdr)
  {
    lcd->setCursor(0,2);
    lcd->print("3. Zeile");
    lcd->setCursor(0,3);
    lcd->print ("4. Zeile");
  }
  delay(1000);
}

Warum nicht beide Objekte statisch erzeugen, und nur das richtige verwenden?

DrDiettrich: Warum nicht beide Objekte statisch erzeugen, und nur das richtige verwenden?

Naja, kann man halten, wie man will ... Variationen, es gibt! Und je nach Vorliebe/Kontext, wählt man eben die schönere.

Meine Ansicht, zu diesem konkreten Fall: Warum 2 Objekte generieren, wenn man doch sowieso nur eins brauchen wird.

combie:
(völlig ungetestet)

Wenn Du Wire.begin(); ergänzt, könnte es was werden.

Dein Sketch auf mein LCD angepaßt funktioniert prächtig:

// Funktioniert mit Bibliothek http://www.instructables.com/id/How-to-connect-a-serial-LCD-to-an-Arduino-UNO/step2/The-Sketch/   Beschreibung
// https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads   Download

#include <LCD.h>                //NewliquidCrystal
#include <LiquidCrystal_I2C.h>  //NewliquidCrystal
#include <Wire.h>

#define I2C_ADDR     0x27
#define BACKLIGHT_PIN     3
#define En_pin  2
#define Rw_pin  1
#define Rs_pin  0
#define D4_pin  4
#define D5_pin  5
#define D6_pin  6
#define D7_pin  7

LiquidCrystal_I2C *lcd;
byte DisplayAdr = 0;

bool hasI2Cadress(byte adr)
{
  Wire.beginTransmission(adr);
  return !Wire.endTransmission();
}

void setup()
{
  Serial.begin(9600);   // für Testausgaben
  Wire.begin();
  if (hasI2Cadress(0x27))                DisplayAdr = 0x27;
  if ((!DisplayAdr) && hasI2Cadress(0x3F)) DisplayAdr = 0x3F;
  Serial.print("gefundene Adresse: 0x");
  Serial.println(DisplayAdr,HEX);

  if (DisplayAdr) lcd = new LiquidCrystal_I2C(DisplayAdr, En_pin, Rw_pin, Rs_pin, D4_pin, D5_pin, D6_pin, D7_pin, BACKLIGHT_PIN, POSITIVE);
  if (0x27 == DisplayAdr) lcd->begin(16, 2);
  if (0x3F == DisplayAdr) lcd->begin(20, 4);
  lcd->setCursor(0, 0);
  lcd->print("Hallo Welt!");
  delay(1000);
}

void loop()
{
  lcd->setCursor(0, 0);
  lcd->print("Sek. seit Start");
  lcd->setCursor(0, 1);
  lcd->print(millis() / 1000);
  lcd->setCursor(0, 2);
  if (0x3F == DisplayAdr)
  {
    lcd->print("3. Zeile");
    lcd->setCursor(0, 3);
    lcd->print ("4. Zeile");
  }
  delay(1000);
}

Danke, ich habe was gelernt!

Wenn Du Wire.begin(); ergänzt, könnte es was werden.

THX Done!

Danke, ich habe was gelernt!

:o :o :smiling_imp: Hoffentlich nicht das falsche! :smiling_imp: :sunglasses:

Gerne geschehen, und Danke, für den Test.

combie: :o :o :smiling_imp: Hoffentlich nicht das falsche! :smiling_imp: :sunglasses:

Wer weiß das schon ;D

Funktioniert bestens! :)

Vielen Dank.

Hab nochmal ein Foto gemacht.

Ich habe auch beim 1602 lcd->begin(20,4) gelassen und die Zeilen umsortiert.
Die Zeilen 3 und 4 laden dann beim 1602 im Nirwana.

Hier habe mein Projekt eingestellt in dem ich die Displayerkennnung eingebaut habe:

My-SmartRobotCar www.max-mg.de

Ps.: Ich könnte noch einen freien DigitalPin für einen weiteren Linienfolger gebrauchen. Vielleicht findet jemand eine Möglichkeit - ohne Zusatzbeschaltung!