Wie kann ich mehrere Anzeigetexte auf 16x2 lCD anzeigen

Hallo Arduino Gemeinde. Ich bin noch ziemlich neu auf dem Gebiet und lerne seit ein paar Wochen täglich hinzu. Ich arbeite gerade an einem Projekt wo ich den Arduino als Aquarium PC einsetzte. Er wird verwendet um die strömungspumpen zu steuern, Temperatur, pH und Leitwert zu messen. Die ermittelten Status-/Messwerte sollen auf einem 16x2 LCD Display ausgegeben werden. Und hier steh ich vor einem Problem: Wie kann ich das realisieren, dass in einem gewissen Abstand (z.B. drei Sekunden Rythmus) die Anzeigen wechseln? Ich hab mir das in etwa so vorgestellt: in der ersten Zeile wird die Uhrzeit angezeigt (ist realisiert und klappt). In der zweiten Zeile soll in einem gewissen zeitabstand die Anzeige wechseln (Status Strömungspumpe 1, Status Strömungspumpe 2, pH Wert, Leitwert, Temperatur, usw). Wie kann ich das am besten realisieren dass die Anzeigen automatisch (nicht durch Knpfdruck) wechseln?

Wie wär's mit einm programmierten Timer?
Der schreibt einfach di vorhandenn Werte in die zweite Zeile.

http://forum.arduino.cc/index.php?topic=165552.0
zum wechseln der Anzeige.

http://forum.arduino.cc/index.php?topic=73816.0
Fals ein Menü erwünscht ist, sehr zu empfehlen!

Und wie mach ich das? Sorry, bin absoluter Neueinsteiger. :astonished:

Leon8380:
Wie kann ich das realisieren, dass in einem gewissen Abstand (z.B. drei Sekunden Rythmus) die Anzeigen wechseln?

void loop()
{
 if ((millis()/3000)%2==1)
    AnzeigenEins();
  else 
    AnzeigenZwei();  
}

Und wie kann ich das in meinem Sketch einfügen bzw wie muss ich ihn umbauen?

#include <LiquidCrystal.h>
#include <Time.h>
#include <Wire.h>
#include <DS1307RTC.h>
unsigned long prev;

//******************** Schaltzeit 1 Pumpe 1**************************************************

                    //Stunde *60 + Minuten = Schaltzeit
int pump_1_ON = 1411; //
int pump_1_OFF = 735; //

//******************** Schaltzeit 2 Pumpe 1**************************************************
int pump_1_2_ON = 763;
int pump_1_2_OFF = 764;

//******************** Schaltzeit 1 Pumpe 2**************************************************
int pump_2_ON = 00;
int pump_2_OFF = 00;

//******************** Schaltzeit 2 Pumpe 2**************************************************
int pump_2_2_ON = 00;
int pump_2_2_OFF = 00;


//*************************************Relais**************************************************************************
//                    
const int Pumpe_1 = 13;      // Strömungspumpe 1 
//const int Pumpe_1 = 13;      // Strömungspumpe 2

//**********************************************Futterpause************************************************************


const int Taster_1 = 2;      // Taster Start Futterpause
int buttonState_1 = 0;      // Tasterstatus für Futterpause
long interval = 300;      //Intervall für Futterpause in Sekunden


//**********************************************LCD Display************************************************************
LiquidCrystal lcd(12, 11, 10, 7, 6, 5, 4);
//*********************************************************************************************************************


void setup() {
  
  digitalWrite(Pumpe_1, LOW);
  //digitalWrite(Pumpe_2, LOW);
  
 
  lcd.begin(16, 2);

  pinMode(Pumpe_1, OUTPUT);
  //pinMode(Pumpe_1, OUTPUT);
  pinMode(Taster_1, INPUT);

  setSyncProvider(RTC.get);
  prev = millis();

}

void loop() {
  
  Futterpause();
  digitalUhrAnzeige();
  S_Pumpe_1();
}


//********************************************************************************************************************

//********************************************************************************************************************
 void digitalUhrAnzeige() // definieren Subroutine
{
   // digitale Anzeige der Zeit
   lcd.setCursor(8, 0); // positionieren LCD-Cursor, 1. Zeile, 1. Spalte
   printZiffernGenulltOhnePunkt(hour()); // rufen Subroutine auf
   printZiffernGenulltmitPunkt(minute()); // rufen Subroutine auf
   printZiffernGenulltmitPunkt(second()); // rufen Subroutine auf
   Serial.print(" "); // fuegen Freizeichen ein
   lcd.print(" "); // fuegen Freizeichen ein
 }
//***********************************************************************************************
void printZiffernGenulltOhnePunkt(int zahl) // definieren Subroutine
{
  // verschoenern Anzeige, indem wir ...
  if(zahl < 10) // wenn kleiner als 10 ...
   {
     Serial.print(""); // fuehrende 0 einfuegen
     lcd.print("");  // fuehrende 0 einfuegen
   }
   Serial.print(zahl); // Ausgabe auf serieller Konsole
   lcd.print(zahl); // Ausgabe auf LCD     
}
//***************************************************************************************************
void printZiffernGenulltmitPunkt(int zahl) // definieren Subroutine
{
  // verschoenern Anzeige, indem wir ...
  Serial.print(":"); // trennende ":" einfuegen
  lcd.print(":"); // trennende ":" einfuegen
  if(zahl < 10) // wenn kleiner als 10 ...
  {
     Serial.print('0'); // fuehrende 0 einfuegen
     lcd.print('0');
  }
  Serial.print(zahl); // Ausgabe auf serieller Konsole
  lcd.print(zahl);
}
//***************************************************************************************************
void S_Pumpe_1()
{
  RTC.get;
  int Minutenuhrzeit = hour() * 60 + minute(); 
  
  if( ((pump_1_OFF < pump_1_ON) && (Minutenuhrzeit < pump_1_OFF)) || ((pump_1_OFF > pump_1_ON) && (Minutenuhrzeit < pump_1_OFF)&& (Minutenuhrzeit >= pump_1_ON)  ) || ((pump_1_2_OFF < pump_1_2_ON) && (Minutenuhrzeit < pump_1_2_OFF)) || ((pump_1_2_OFF > pump_1_2_ON) && (Minutenuhrzeit < pump_1_2_OFF)&& (Minutenuhrzeit >= pump_1_2_ON))  )
  {
    digitalWrite (Pumpe_1, HIGH);
    lcd.setCursor(0, 1);
    lcd.print("S_PUMPE_1: EIN");
  }
  else
  {
    digitalWrite(Pumpe_1, LOW);
    lcd.setCursor(0, 1);
    lcd.print("S_PUMPE_1: AUS");
  }
}
//***************************************************************************************************

void Futterpause()
{
  buttonState_1 = digitalRead(Taster_1);
  long startTime = millis();
  
  if(buttonState_1 == HIGH)
  {
    while(millis() / 1000 - startTime / 1000 < interval) 
    {
      digitalWrite (Pumpe_1, LOW);
      digitalUhrAnzeige();
      lcd.setCursor(0, 1);
      lcd.print("FUTTERPAUSE    ");
    }
  }
  else
  S_Pumpe_1();
  
}

Leon8380:
Und wie kann ich das in meinem Sketch einfügen bzw wie muss ich ihn umbauen?

Für eine Wechselanzeige, die alle drei Sekunden umspringt und mal drei Sekunden dies und drei Sekunden das anzeigt, mußt Du Dir zwei Anzeigefunktionen machen. Ich habe sie bei mir “AnzeigenEins()” und “AnzeigenZwei()” genannt. Da müssen jeweils die LCD.print Befehle drinstehen, für das, was jeweils angezeigt werden soll.

Hmm, okay leuchtet mir ein. Nur ich weiß jetzt grad nicht wie ich das umsetzten soll. Die LCD.print Befehle sind bei mir ja im jeweiligen void drinn. Wie kann ich da jetzt eine Verknüpfung zur anzeigefunktion herstellen?

Leon8380:
Hmm, okay leuchtet mir ein. Nur ich weiß jetzt grad nicht wie ich das umsetzten soll. Die LCD.print Befehle sind bei mir ja im jeweiligen void drinn. Wie kann ich da jetzt eine Verknüpfung zur anzeigefunktion herstellen?

Du mußt beim Programmdesign darauf achten, dass Du Verarbeitungsfunktionen und Ausgabefunktionen nicht in derselben Funktion vermischst, sondern trennst.

Es muß getrennte Funktionen für die Ausgabe von Daten geben und andere Funktionen zur Verarbeitung von Daten.

Deine Funktion “void digitalUhrAnzeige()” scheint eine reine Ausgabefunktion zu sein, die kannst Du so direkt verwenden.

Andere Deiner Funktionen, in denen Du Verarbeitung und Ausgabe vermischt hast, müßtest Du aufteilen in zwei getrennte Funktionen. Z.B. die Funktion “void S_Pumpe_1()” in eine Funktion zum Schalten:

void S_Pumpe_1_Verarbeiten()
{
  RTC.get;
  int Minutenuhrzeit = hour() * 60 + minute(); 
  if( ((pump_1_OFF < pump_1_ON) && (Minutenuhrzeit < pump_1_OFF)) || ((pump_1_OFF > pump_1_ON) && (Minutenuhrzeit < pump_1_OFF)&& (Minutenuhrzeit >= pump_1_ON)  ) || ((pump_1_2_OFF < pump_1_2_ON) && (Minutenuhrzeit < pump_1_2_OFF)) || ((pump_1_2_OFF > pump_1_2_ON) && (Minutenuhrzeit < pump_1_2_OFF)&& (Minutenuhrzeit >= pump_1_2_ON))  )
  {
    digitalWrite (Pumpe_1, HIGH);
  }
  else
  {
    digitalWrite(Pumpe_1, LOW);
  }
}

Und eine andere Funktion zum Anzeigen des Pumpenstatus:

void S_Pumpe_1_Anzeigen()
{
  lcd.setCursor(0, 1);
  if (digitalRead(Pumpe_1)==HIGH)
    lcd.print("S_PUMPE_1: EIN");
  else
    lcd.print("S_PUMPE_1: AUS");
}

In der loop rufst Du dann die Funktion “S_Pumpe_1_Verarbeiten()” in jedem loop-Durchlauf auf.
Und die Funktion “S_Pumpe_1_Anzeigen()” eben nur alle drei Sekunden im Wechsel mit irgendwas anderem.

void loop()
{
 S_Pumpe_1_Verarbeiten();
 if ((millis()/3000)%2==1)
 {
    digitalUhrAnzeige(); // Uhrzeit in 1. Zeile
    S_Pumpe_1_Anzeigen(); // Status Pumpe-1 in 2. Zeile
 }
  else 
    IrgendwasAnderesAnzeigen();  
}

Hallo Leon8380;

ich bin auch neuer Arduino-Forscher und habe etwas Ähnliches gebaut wie du.

Ich wähle über ein Potentiometer 6 verschiedene Anzeigemodi über eine map- und eine switch-case-Funktion aus.
Im letzten Modus werden alle Daten nacheinander für 2 Sekunden angezeigt.
Der Code ist gut kommentiert, Datenberechnung und Datenausgabe sind sauber getrennt.
Den letzten Modus könnte man noch eleganter über eine Schleife programmieren, die die ersten Module einfach nacheinander durchläuft, aber es funktioniert und der Code ist gut verstehbar.
Wenn du Berechnung und Ausgabe auftrennst, kannst du meinen Ausgabecode in deinen Code reinkopieren und anpassen.
Der Code ist zu lang für dies Posting, daher als Anhang.

Gruß
Taquino

Cavair1.1.rtf (16.2 KB)

@jurs
Danke für den Tipp, der hat mich schon weitergebracht aber entweder bin ich zu blöd und Check es nicht oder mein arduino macht nicht das was ich will. Hab jetzt diemstatusmeldungen (Pumpe: ein, Pumpe:aus) in einen eigenen void gesetzt mit der if Bedingung dass er auf digitalread(Pumpe) mit der entsprechenden StTusmeldung reagieren soll. Er gibt mir aber immer nur eine Statusmeldung aus. Und zwar immer dass die Pumpe aus ist. Irgendwie reagiert er nicht darauf dass er digitalread(Pumpe machen soll. Ich kann doch einen Pin der als Ausgang fungiert gleichzeitig auch lesen (digitalread) oder nicht?

@Taquino
Danke für deinen Vorschlag, würde mir auch gerne mal deinen Sketch anschauen, aber an deinem post ist leider kein Anhang dran.

Gruß, Leon

Hab’s gefunden. :slight_smile:
So wie es aussieht kann ich einen Kanal der als OUTPUT geschalten ist nicht digitalRead machen.
Hab den digitalRead jetzt auf nen anderen Pin gelegt der als INPUT definiert istund schon geht’s.

Ahoj allerseits,

sorry Leon8380, das war mein erstes Posting hier und ich schreibe nur alle paar Jahre was in Foren, muß mich erst einfuchsen.

Ist dein Anzeigeproblem jetzt eigentlich insgesamt gelöst?

Gruß
Taquino

Cavair1.1.rtf (16.2 KB)

Hallo Taquino,
Es sei dir verziehen. :wink:
Ja, so halbwegs. Hab es jetzt so gemacht wie jurs geschrieben hat. Funktioniert wunderbar. Allerdings muss ich noch schauen ob es auch mit mehr als zwei statusanzeigen funktioniert.

Leon8380:
Ja, so halbwegs. Hab es jetzt so gemacht wie jurs geschrieben hat. Funktioniert wunderbar. Allerdings muss ich noch schauen ob es auch mit mehr als zwei statusanzeigen funktioniert.

Natürlich kannst Du eine Wechselanzeige aus beliebig vielen Anzeigen nacheinander ablaufen lassen.

Z.B. mit einer switch-case Abfrage im Beispiel für eine Anzeige mit fünffachem Wechsel alle drei Sekunden:

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
}

void AnzeigenNull()
{
  Serial.println("NULL");
}

void AnzeigenEins()
{
  Serial.println("EINS");
}

void AnzeigenZwei()
{
  Serial.println("ZWEI");
}

void AnzeigenDrei()
{
  Serial.println("DREI");
}

void AnzeigenVier()
{
  Serial.println("VIER");
}


void Wechselanzeige()
{
  switch ((millis()/3000)%5)
  {
    case 0: AnzeigenNull();break;
    case 1: AnzeigenEins();break;
    case 2: AnzeigenZwei();break;
    case 3: AnzeigenDrei();break;
    case 4: AnzeigenVier();break;
    default: Serial.println("Error");
  }  
}

void loop() {
  // put your main code here, to run repeatedly: 
  Wechselanzeige();  
}

Falls sich da immer noch jemand fragt, wieso die Anzeige alle drei Sekunden wechselt, hier eine Erläuterung:

"(millis()/3000)" ist der Millis-Zähler durch 3000 geteilt, d.h. da kommt als Ergebnis eine Zahl heraus, die sich alle 3000 Millisekunden (= 3 Sekunden) um eins erhöht. Und mit dieser Zahl wird eine Modulo(Ganzzahl)-Division durch 5 durchgeführt und der Rest davon ermittelt, Modulo-Operator "%". Der Rest bei der geteilt durch 5 Operation ist immer 0, 1, 2, 3 oder 4. D.h. heraus kommt bei der Rechnung ((millis()/3000)%5) immer nach 3 Sekunden wechselnd:
0 1 2 3 4 0 1 2 3 4 0 1 2 3 4.
Und je nachdem wird im obigen Code dann eine von fünf verschiedenen Ausgabefunktionen aufgerufen.

Macht man das auf LCD statt auf Serial, bekommt man eine schöne Wechselanzeige im Dreisekundentakt.

Wenn man den Wechsel stattdessen im 5-Sekundentakt möchte, nimmt man eben "(millis()/5000)".

Und wenn man statt 2 verschiedener Anzeigen ("%2") oder 5 verschiedener Anzeigen ("%5") z.B. 3 verschiedene Anzeigen möchte, rechnet man mit "%3".

Im Endeffekt lassen sich sogar Anzeigen realisieren, die unterschiedlich lange angezeigt werden. Möchte man z.B. eine Anzeige, die 4 Sekunden lang das eine und 2 Sekunde lang etwas anderes anzeigt, teilt man das Intervall in Sekundenabschnitte ein "(millis()/1000)" und beim Divisionsrest macht man es so, dass bei "%6" und 0,1,2,3 die eine Anzeigefunktion aufruft und bei 4,5 die andere. So lassen sich auch Wechselanzeigen realisieren, die einzelne Werte kürzer oder länger anzeigen als andere.

Hallo jurs,
Viele vielen dank für deine supergute Erklärung (und auch deine Geduld) :wink:
Werde dein genanntes Beispiel gleich morgen mal ausprobieren.
Danke auch für die Erklärung was es mit dem "%..." Auf sich hat. Stand nämlich schon mit nem großen Fragezeichen im Gesicht da Was das für ne Funktion hat.
Ein großes "Daumen hoch" für dich, du hast mir nämlich sehr weiter geholfen.
Gruß, Leon

yippie, sehr geil, jurs!
das meinte ich damit, daß das alles noch eleganter geht.
werd ich morgen gleich ausprobiern.

grüßle
taq