Arduino Uno und Menü für LCD Keypad Shield

Musikhai:
Möchte den Arduino nämlich zu Temperaturerfassung verwenden und die Daten dann auf SD-Karte spreichern um sie später per Excel auszuwerten.

Eine Zeiteinstellfunktion ist dazu natürlich nicht falsch.

Aber damit der Arduino nach dem Einschalten schon "eine ziemlich genaue Zeit" bekommt, macht man es normalerweise so, daß wie bei einem PC eine kleine Echtzeituhrenplatine mit Pufferbatterie angeschlossen wird. Beim Starten holt sich der Arduino dann die aktuelle Uhrzeit aus dem Uhrenmodul.

/******************************************************************
 * Clock and clock adjust demo by "jurs" for German Arduino Forum *
 * Hardware required: keypad shield
 * Additional library required: Time library must be installed 
 ******************************************************************/

#include <LiquidCrystal.h>
#include <Time.h>  

// Select the pins used on the LCD panel:
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

// Define some values used by the LCD panel and buttons:
enum keypadButtons {btnNONE, btnSELECT, btnLEFT, btnRIGHT, btnDOWN, btnUP };

int readPadButtons()
// read the buttons from analog interface:
// returns the key currently pressed
// do not call this function directly from the sketch!
{
  int adc_key_in = analogRead(0);      // read the value from the sensor
  // my buttons when read are centered at these valies: 0, 144, 329, 504, 741
  // we add approx 50 to those values and check to see if we are close
  if (adc_key_in > 1000) return btnNONE;
  if (adc_key_in < 50)   return btnRIGHT; 
  if (adc_key_in < 195)  return btnUP;
  if (adc_key_in < 380)  return btnDOWN;
  if (adc_key_in < 555)  return btnLEFT;
  if (adc_key_in < 790)  return btnSELECT;  
  return btnNONE;  // when all others fail, return this...
}


#define DEBOUNCETIME 10

int buttonPressed()
// this function returns true only once per single button pressed
// use this function in your program sketch
{
  static boolean buttonFired;
  static long buttonDownSince;
  int State=readPadButtons();
  if (State==btnNONE)  
  { // this button is not pressed at this time
    buttonFired=false;
    buttonDownSince=0;
  }
  else if (buttonDownSince==0)
  { // button is pressed but DEBOUNCETIME did not yet started counting
    buttonFired=false;
    buttonDownSince=millis();
  }
  if (millis()-buttonDownSince>=DEBOUNCETIME && buttonFired==false)
  { // button is pressed and DEBOUNCETIME passed, so fire the button
    buttonFired=true;
    return(State); // return button 
  }  
  return(btnNONE); // no button fired this time
}




void setup()  
{
  Serial.begin(9600);           // set serial interface to 9600 baud
  lcd.begin(16, 2);             // starts the LCD display (2 lines by 16 chars)
  setTime(1357002000);          // set some initial time
}


boolean inMenu; // global variable to hold the menu status

void  updateDisplay()
// this function updates the display (time and menu status)
{
  char time[10];
  sprintf(time,"%02d:%02d:%02d",hour(),minute(),second());
  lcd.setCursor(0,0);
  lcd.print(time);
  lcd.setCursor(0,1);
  if (inMenu)
    lcd.print(F("Zeit einstellen"));
  else  
    lcd.print(F("Normalbetrieb  "));
}


void checkForNewSecond()
// function will update the display once per second
{
  static long lastsecond;
  if (lastsecond!=now())
  {
    updateDisplay();
    lastsecond=now();
  }  
}


void handleMenuButton(int button)
// we are in time setting menu and react on pressed button
// by changing the time
{
  switch (button)
  {
    case btnRIGHT:
    {
      setTime(now()+3600);
      break;
    }
    case btnLEFT:
    {
      setTime(now()-3600);
      break;
    }
    case btnUP:
    {
      setTime(now()+60);
      break;
    }
    case btnDOWN:
    {
      setTime(now()-60);
      break;
    }
  }
}

void handleNormalButton(int button)
{
  // nothing yet
}


void handleButtons()
// Abfrage ob eine Taste gedrückt wurde
// Umschaltung des Menüstatus
// Falls im Zeiteinstellmenü, Funktion zur Behandlung der Tasten im Einstellmenü aufrufen
// Falls im Normalbetrieb, Funktion zur Behandlung der Tasten im Normalbetrieb aufrufen
{
  int curButton;
  curButton=buttonPressed();
  if (curButton==btnNONE) return; // nothing to do if no button is pressed
  else if (curButton==btnSELECT) inMenu=!inMenu;  // switch menu status
  else if (inMenu) handleMenuButton(curButton); // gedrückte Tasten im Einstellmenü behandeln
  else handleNormalButton(curButton); // gedrückte Tasten sonst behandeln
  updateDisplay();  
}


void loop()
{
  checkForNewSecond();      // einmal pro Sekunde das Display updaten
  handleButtons();
}

Per "Select" Button wird zwischen Zeiteinstellung und Normalbetrieb umgeschaltet.

Reicht es Dir, nur die Zeit einstellen zu können und das Datum ist egal und kann irgendwann sein? Oder brauchst Du auch noch erweiterte Möglichkeiten, um nicht nur Stunden und Minuten, sondern auch noch Tag, Monat und Jahr einstellen zu können?

Danke schon mal an dich!

Nur die Zeit reicht mir leider nicht. Ich möchte die Zeit (Stunden, Minuten, Sekunden) und das Datum (Tag, Monat, Jahr) einstellen können, damit wie ich schon beschrieben habe, das komplett auf der SD karte gespeichert werden kann wegen der Auswertung im Nachhinein.

Musikhai:
Danke schon mal an dich!

Nur die Zeit reicht mir leider nicht. Ich möchte die Zeit (Stunden, Minuten, Sekunden) und das Datum (Tag, Monat, Jahr) einstellen können, damit wie ich schon beschrieben habe, das komplett auf der SD karte gespeichert werden kann wegen der Auswertung im Nachhinein.

Dann hier eine erweiterte Version, mit der Du nacheinander mit dem SELECT Button umschalten kannst zwischen:

  • Normalbetrieb
  • Zeit einstellen (rechts/links Stunde, up/down Minute)
  • Datum einstellen (rechts/links Monat, up/down Tag)
  • Jahr einstellen
/******************************************************************
 * Clock and clock adjust demo by "jurs" for German Arduino Forum *
 * Hardware required: keypad shield
 * Additional library required: Time library must be installed 
 ******************************************************************/

#include <LiquidCrystal.h>
#include <Time.h>  

// Select the pins used on the LCD panel:
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

// Define some values used by the LCD panel and buttons:
enum keypadButtons {btnNONE, btnSELECT, btnLEFT, btnRIGHT, btnDOWN, btnUP };
enum menuStates {menuNONE, menuTIME, menuDATE, menuYEAR};

int readPadButtons()
// read the buttons from analog interface:
// returns the key currently pressed
// do not call this function directly from the sketch!
{
  int adc_key_in = analogRead(0);      // read the value from the sensor
  // my buttons when read are centered at these valies: 0, 144, 329, 504, 741
  // we add approx 50 to those values and check to see if we are close
  if (adc_key_in > 1000) return btnNONE;
  if (adc_key_in < 50)   return btnRIGHT; 
  if (adc_key_in < 195)  return btnUP;
  if (adc_key_in < 380)  return btnDOWN;
  if (adc_key_in < 555)  return btnLEFT;
  if (adc_key_in < 790)  return btnSELECT;  
  return btnNONE;  // when all others fail, return this...
}


#define DEBOUNCETIME 10

int buttonPressed()
// this function returns true only once per single button pressed
// use this function in your program sketch
{
  static boolean buttonFired;
  static long buttonDownSince;
  int State=readPadButtons();
  if (State==btnNONE)  
  { // this button is not pressed at this time
    buttonFired=false;
    buttonDownSince=0;
  }
  else if (buttonDownSince==0)
  { // button is pressed but DEBOUNCETIME did not yet started counting
    buttonFired=false;
    buttonDownSince=millis();
  }
  if (millis()-buttonDownSince>=DEBOUNCETIME && buttonFired==false)
  { // button is pressed and DEBOUNCETIME passed, so fire the button
    buttonFired=true;
    return(State); // return button 
  }  
  return(btnNONE); // no button fired this time
}




void setup()  
{
  Serial.begin(9600);           // set serial interface to 9600 baud
  lcd.begin(16, 2);             // starts the LCD display (2 lines by 16 chars)
  setTime(1357002000);          // set some initial time
}


int menuState; // global variable to hold the menu status

void  updateDisplay()
// this function updates the display (time and menu status)
{
  char lcdline[17];
  sprintf(lcdline,"%02d:%02d:%02d",hour(),minute(),second());
  lcd.setCursor(0,0);
  lcd.print(lcdline);
  lcd.setCursor(0,1);
  if (menuState==menuTIME)
    lcd.print(F("Zeit einstellen "));
  else if (menuState==menuDATE)
  {
    lcd.print(F("Datum: "));
    sprintf(lcdline,"%02d.%02d.   ",day(),month());
    lcd.print(lcdline);
  }  
  else if (menuState==menuYEAR)
  {
    lcd.print(F("Jahr: "));
    sprintf(lcdline,"%04d      ",year());
    lcd.print(lcdline);
  }  
  else  
    lcd.print(F("Normalbetrieb   "));
}


void checkForNewSecond()
// function will update the display once per second
{
  static long lastsecond;
  if (lastsecond!=now())
  {
    updateDisplay();
    lastsecond=now();
  }  
}


void handleMenuTimeButton(int button)
// we are in time setting menu and react on pressed button
// by changing the time
{
  switch (button)
  {
    case btnRIGHT:
    {
      setTime(now()+3600);
      break;
    }
    case btnLEFT:
    {
      setTime(now()-3600);
      break;
    }
    case btnUP:
    {
      setTime(now()+60);
      break;
    }
    case btnDOWN:
    {
      setTime(now()-60);
      break;
    }
  }
}

void handleMenuDateButton(int button)
// we are in time setting menu and react on pressed button
// by changing the time
{
  switch (button)
  {
    case btnRIGHT:
    {
      setTime(hour(),minute(),second(),day(),month()+1,year());
      break;
    }
    case btnLEFT:
    {
      setTime(hour(),minute(),second(),day(),month()-1,year());
      break;
    }
    case btnUP:
    {
      setTime(hour(),minute(),second(),day()+1,month(),year());
      break;
    }
    case btnDOWN:
    {
      setTime(hour(),minute(),second(),day()-1,month(),year());
      break;
    }
  }
}

void handleMenuYearButton(int button)
// we are in time setting menu and react on pressed button
// by changing the time
{
  switch (button)
  {
    case btnRIGHT:
    case btnUP:
    {
      if (year()<2038)
        setTime(hour(),minute(),second(),day(),month(),year()+1);
      break;
    }
    case btnLEFT:
    case btnDOWN:
    {
      if (year()>2000)
        setTime(hour(),minute(),second(),day(),month(),year()-1);
      break;
    }
  }
}



void handleNormalButton(int button)
{
  // nothing yet
}


void handleButtons()
// Abfrage ob eine Taste gedrückt wurde
// Umschaltung des Menüstatus
// Falls im Zeiteinstellmenü, Funktion zur Behandlung der Tasten im Einstellmenü aufrufen
// Falls im Normalbetrieb, Funktion zur Behandlung der Tasten im Normalbetrieb aufrufen
{
  int curButton;
  curButton=buttonPressed();
  if (curButton==btnNONE) return; // nothing to do if no button is pressed
  else if (curButton==btnSELECT) // switch menu status
  {
    if (menuState==menuNONE) menuState=menuTIME;  
    else if (menuState==menuTIME) menuState=menuDATE;  
    else if (menuState==menuDATE) menuState=menuYEAR;
    else menuState=menuNONE;
  }
  else if (curButton!=btnNONE) // falls eine Taste gedrückt wurde
  {
    if (menuState==menuTIME) handleMenuTimeButton(curButton);  // Zeit einstellen
    else if (menuState==menuDATE) handleMenuDateButton(curButton);  // Datum einstellen
    else if (menuState==menuYEAR) handleMenuYearButton(curButton);  // Jahr einstellen
    else handleNormalButton(curButton); // gedrückte Tasten sonst behandeln
  }
  updateDisplay();  
}


void loop()
{
  checkForNewSecond();      // einmal pro Sekunde das Display updaten
  handleButtons();
}

Vielleicht nützt es Dir auch was, falls Du zum Zwischenpuffern der Zeit bei ausgeschaltetem Arduino doch noch ein Uhrenmodul installierst und die Einstellmöglichkeit dann nur zum Nachstellen der Zeit benötigst.

Und er tut es schon wieder... eine komplexe Lösung für ein simples Problem - super sauber ausgeführt und dokumentiert, allerdings mit Null Eigenleistung des Threadstarters

Simples Problem?

Dann gibt's vielleicht auch eine simplere Lösung als das, was ich gepostet habe?

Immer her mit den simplen Lösungen für "simple" Probleme, ich lerne selbst gerne noch was!

Ich finde, die Shield-Anbieter lassen Programmieranfänger ganz schön im Regen stehen, indem sie für ihre von der Hardware her eigentlich recht leistungsfähigen Shields teilweise nur dümmlichste und kaum für irgendwas brauchbare Demoprogramme anbieten. Zum Keypad-Shield wird nicht mal eine Funktion wie die oben von mir gepostete "buttonPressed()" Funktion gezeigt, die bei laufender Abfrage immer genau zu einem Tastendruck auch einmal einen Rückgabecode zurückliefert.

Das ist eine absolute Schande.

Meine Meinung: Wenn Anfänger überhaupt keine Ahnung haben, wie irgendein Problem angepackt werden kann und Hardwareanbieter zu ihren Shields keine brauchbaren Demoprogramme mitliefern, dann kann ein Anfänger aus dem funktionierendem Code eines erfahreneren Programmierers sicher mindestens genau so viel lernen als wenn er sich selbst völlig planlos irgendwas zusammenstümpert, das dann vielleicht oder vielleicht auch nicht funktioniert.

hi,

musikhai wollte eine fertige lösung, jurs hat's spaß gemacht, sie zu liefern.
wo ist das problem?
wir sind doch hier nicht die lehrer einer schule, die jemandem etwas beibringen müssen.

traurig an der sache find' ich viel mehr, daß jurs unbedingt englisch dokumentieren will.
"Clock and clock adjust demo by "jurs" for German Arduino Forum" ist doch jenseitig.

gruß stefan

Eisebaer:
traurig an der sache find' ich viel mehr, daß jurs unbedingt englisch dokumentieren will.
"Clock and clock adjust demo by "jurs" for German Arduino Forum" ist doch jenseitig.

Hi Eisebaer,

das finde ich nicht. Wer sich auch nur halbwegs ernsthaft mit Arduino und programmieren beschäftigt, kommt früher oder später um ein bissl Englisch nicht drumrum. Und so kann jurs ggf. auch im englischen Forum weiterhelfen, ohne den Code neu kommentieren zu müssen.
Ich finde das legitim und mache es selbst auch so.

Beste Grüße

Helmuth

Wer sich auch nur halbwegs ernsthaft mit Arduino und programmieren beschäftigt kommt früher oder später um ein bissl Englisch nicht drumrum.

Seh ich genauso. Ich habe durch das Programmieren mit Xcode etwas English gelernt. Natürlich gehts auch ohne English, nur sehr mühsam.

Hallo an Alle.

Vielen dank an dich Jurs. Ich bin zwar heute noch nicht zum ausprobieren gekommen, doch das werde ich morgen sofort nachholen.
Ich stimme dir voll zu, dass man von den Shiel-Anbietern total im Regen stehen gelassen wird. So toll wie die Shields sind, bleibt man als Neuling im Regen stehen.
Es wäre schön, wenn ich zu gegebner Zeit noch einmal deine Hilfe in Anspruch nehmen könnte, denn das nächste Problem wird sicherlich die Speicherung der Daten auf SD Karte werden. Doch eins nach dem anderen. wie gesagt werde morgen dein Programm testen.

Also vielen Dank noch mal und bis Morgen dann

Hallo Jurs,

habe gerade dein Script ausprobiert und funktioniert gut. Nun habe ich es etwas verändert. Z.B. das dort wo du "normalbetrieb" stehen hast , ich jetzt das Datum stehen habe. Desweiteren habe ich dein Script so verändert, dass 2 Dallas Themperatursensoren DS18B20 ausgelesen werden und gleichzeitig mit der Uhrzeit und dem Datum angezeigt werden.

Wie bekomme ich jetzt das Script hier reinkopiert, so dass du es auch sehen kannst?

Könntest du das Script dann so verändern, dass beim einschalten des Arduino ich in ein Menü komme, wo ich zwischen Anzeige ( Anzeige von Zeit, Datum, Werte der Temperturfühler) (sollte so aussehen wie es jetzt läuft) und Setup (Einstellen der Uhr und des Datums) wählen kann. Wäre ganz toll, wenn du mir bei der Programierung wieder behilflich sein könntest.

Danke schon mal im voraus.

Musikhai

Musikhai:
Wie bekomme ich jetzt das Script hier reinkopiert, so dass du es auch sehen kannst?

Code kannst Du hier im Forum zwischen zwei Code-Tags einkopieren. Schema:

(code)
Hier Dein Code
(/code)

Nur mußt Du dafür die ECKIGEN Klammern [] anstelle der runden Klammern verwenden.

Musikhai:
Könntest du das Script dann so verändern, dass beim einschalten des Arduino ich in ein Menü komme, wo ich zwischen Anzeige ( Anzeige von Zeit, Datum, Werte der Temperturfühler) (sollte so aussehen wie es jetzt läuft) und Setup (Einstellen der Uhr und des Datums) wählen kann. Wäre ganz toll, wenn du mir bei der Programierung wieder behilflich sein könntest.

Na ja, ich gebe ja gerne Schwimmhilfe, aber irgendwann müßtest Du auch selbst den Freischwimmer machen. Oder wenigstens das Seepferdchen.

In das Einstellmenü kommst Du nicht nur beim Programmstart, sondern JEDERZEIT durch Drücken des SELECT Buttons auf dem Shield. Falls Du eine Merkhilfe benötigst, dass nach dem Start die Zeit noch nicht gestellt wurde, kannst Du dafür eine globale Variable deklarieren, z.B.:
boolean timeIsSet=false;

Diese Variable könntest Du nutzen, um z.B. eine modifizierte Normalanzeige zu machen, aus der man erkennt, dass die Zeit noch nicht gesetzt wurde. Z.B.
if (!timeIsSet) ==> Code zum Ausgeben der Zeit als ##:##:## statt 11:23:47

Und sobald die Zeiteinstellroutine verlassen wird, setzt Du timeIsSet für den Rest des Programmablaufs auf true.
Dann kannst Du bei einem Datenlogger auch vermeiden, dass schon Datenzeilen geloggt werden, während die Zeit noch gar nicht gestellt worden ist. Also den Datenlogger erst ab dem Zeitpunkt loggen lassen, ab dem eine eingestellte Zeit vorliegt:
if (timeIsSet) ==> Code zum Loggen von Daten

Die genaue Programmlogik richtet sich nach dem, was der Sketch können soll.

Und wie gesagt: Normalerweise bekommt ein autonomes Gerät ein kleines Uhrenmodul mit Knopfzelle, so dass die Zeit auch bei ausgeschaltetem Gerät weiterläuft. beim Programmstart wird die Zeit aus dem Uhrenmodul gelesen, und eine Einstellroutine wird nur benötigt, wenn Gangabweichungen der Uhr ausgeglichen werden sollen (bei DS1307 durchaus bis zu 2 Minuten pro Monat). Oder wenn man keine vernünftige Sommer-/Winterzeitumstellung programmiert bekommt, beim Umstellen von Winter- auf Sommerzeit und umgekehrt.

Wie genau Arduino-Boards mit ihrem 16 MHz Takt laufen, das hängt von der Bauweise des Boards ab und ob ein Schwingquarz oder nur ein Resonator verbaut ist, sowie von den Temperaturbedingungen beim Betrieb. Mit dem 16 MHz Systemtakt und der Time-Library kann es ohne Nachstellen der Uhr durchaus zu deutlich höheren Gangabweichungen kommen als mit einem DS1307 Uhrenmodul.

Hier mein Sketch vom Menü. Da kann man zwar auch Zeit/Datum einstellen, habs aber nicht fertig bekommen. http://pastebin.com/34trMagQ

Hier mal mein Script. Bitte Jurs schau mal drüber und vielleicht macht es ja keine große Mühe das umprogramieren:

(code)
/******************************************************************

  • Clock and clock adjust demo by "jurs" for German Arduino Forum *
  • Hardware required: keypad shield
  • Additional library required: Time library must be installed
    ******************************************************************/

#include <LiquidCrystal.h>
#include <Time.h>
#include <OneWire.h>
#include <DallasTemperature.h>

#define ONE_WIRE_BUS 2

// Select the pins used on the LCD panel:
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

// Define some values used by the LCD panel and buttons:
enum keypadButtons {btnNONE, btnSELECT, btnLEFT, btnRIGHT, btnDOWN, btnUP };
enum menuStates {menuNONE, menuTIME, menuDATE, menuYEAR};

int readPadButtons()
// read the buttons from analog interface:
// returns the key currently pressed
// do not call this function directly from the sketch!
{
int adc_key_in = analogRead(0); // read the value from the sensor
// my buttons when read are centered at these valies: 0, 144, 329, 504, 741
// we add approx 50 to those values and check to see if we are close
if (adc_key_in > 1000) return btnNONE;
if (adc_key_in < 50) return btnRIGHT;
if (adc_key_in < 195) return btnUP;
if (adc_key_in < 380) return btnDOWN;
if (adc_key_in < 555) return btnLEFT;
if (adc_key_in < 790) return btnSELECT;
return btnNONE; // when all others fail, return this...
}

#define DEBOUNCETIME 10

int buttonPressed()
// this function returns true only once per single button pressed
// use this function in your program sketch
{
static boolean buttonFired;
static long buttonDownSince;
int State=readPadButtons();
if (State==btnNONE)
{ // this button is not pressed at this time
buttonFired=false;
buttonDownSince=0;
}
else if (buttonDownSince==0)
{ // button is pressed but DEBOUNCETIME did not yet started counting
buttonFired=false;
buttonDownSince=millis();
}
if (millis()-buttonDownSince>=DEBOUNCETIME && buttonFired==false)
{ // button is pressed and DEBOUNCETIME passed, so fire the button
buttonFired=true;
return(State); // return button
}
return(btnNONE); // no button fired this time
}

void setup()
{
Serial.begin(9600); // set serial interface to 9600 baud
lcd.begin(16, 2); // starts the LCD display (2 lines by 16 chars)
setTime(1357002000); // set some initial time
}

int menuState; // global variable to hold the menu status

void updateDisplay()
// this function updates the display (time and menu status)
{
char lcdline[17];
sprintf(lcdline,"%02d:%02d:%02d",hour(),minute(),second());
lcd.setCursor(0,0);
lcd.print(lcdline);
lcd.setCursor(0,1);
if (menuState==menuTIME)
lcd.print(F("Zeit einstellen "));
else if (menuState==menuDATE)
{
lcd.print(F("Datum: "));
sprintf(lcdline,"%02d.%02d. ",day(),month());
lcd.print(lcdline);
}
else if (menuState==menuYEAR)
{
lcd.print(F("Jahr: "));
sprintf(lcdline,"%04d ",year());
lcd.print(lcdline);
}
else
// lcd.print(F("Normalbetrieb "));
printZiffernGenulltOhnePunkt(day());
lcd.print(".");
printZiffernGenulltOhnePunkt(month());
lcd.print(".");

}

void checkForNewSecond()
// function will update the display once per second
{
static long lastsecond;
if (lastsecond!=now())
{
updateDisplay();
lastsecond=now();
}
}

void handleMenuTimeButton(int button)
// we are in time setting menu and react on pressed button
// by changing the time
{
switch (button)
{
case btnRIGHT:
{
setTime(now()+3600);
break;
}
case btnLEFT:
{
setTime(now()-3600);
break;
}
case btnUP:
{
setTime(now()+60);
break;
}
case btnDOWN:
{
setTime(now()-60);
break;
}
}
}

void handleMenuDateButton(int button)
// we are in time setting menu and react on pressed button
// by changing the time
{
switch (button)
{
case btnRIGHT:
{
setTime(hour(),minute(),second(),day(),month()+1,year());
break;
}
case btnLEFT:
{
setTime(hour(),minute(),second(),day(),month()-1,year());
break;
}
case btnUP:
{
setTime(hour(),minute(),second(),day()+1,month(),year());
break;
}
case btnDOWN:
{
setTime(hour(),minute(),second(),day()-1,month(),year());
break;
}
}
}

void handleMenuYearButton(int button)
// we are in time setting menu and react on pressed button
// by changing the time
{
switch (button)
{
case btnRIGHT:
case btnUP:
{
if (year()<2038)
setTime(hour(),minute(),second(),day(),month(),year()+1);
break;
}
case btnLEFT:
case btnDOWN:
{
if (year()>2000)
setTime(hour(),minute(),second(),day(),month(),year()-1);
break;
}
}
}

void handleNormalButton(int button)
{
// nothing yet
}

void handleButtons()
// Abfrage ob eine Taste gedrückt wurde
// Umschaltung des Menüstatus
// Falls im Zeiteinstellmenü, Funktion zur Behandlung der Tasten im Einstellmenü aufrufen
// Falls im Normalbetrieb, Funktion zur Behandlung der Tasten im Normalbetrieb aufrufen
{
int curButton;
curButton=buttonPressed();
if (curButton==btnNONE) return; // nothing to do if no button is pressed
else if (curButton==btnSELECT) // switch menu status
{
if (menuState==menuNONE) menuState=menuTIME;
else if (menuState==menuTIME) menuState=menuDATE;
else if (menuState==menuDATE) menuState=menuYEAR;
else menuState=menuNONE;
}
else if (curButton!=btnNONE) // falls eine Taste gedrückt wurde
{
if (menuState==menuTIME) handleMenuTimeButton(curButton); // Zeit einstellen
else if (menuState==menuDATE) handleMenuDateButton(curButton); // Datum einstellen
else if (menuState==menuYEAR) handleMenuYearButton(curButton); // Jahr einstellen
else handleNormalButton(curButton); // gedrückte Tasten sonst behandeln
}
updateDisplay();
}

void printZiffernGenulltOhnePunkt(int zahl) // definieren Subroutine
{
// verschoenern Anzeige, indem wir ...
if(zahl < 10) // wenn kleiner als 10 ...
{
Serial.print("0"); // fuehrende 0 einfuegen
lcd.print("0"); // 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 loop()
{
sensors.requestTemperatures();
lcd.setCursor(11, 0);
//lcd.print("0: ");
lcd.print(sensors.getTempCByIndex(0));
// lcd.print("C");

lcd.setCursor(11, 1);
// lcd.print("1: ");
lcd.print(sensors.getTempCByIndex(1));
// lcd.print("C");

checkForNewSecond(); // einmal pro Sekunde das Display updaten
handleButtons();
}

(/Code)

Danke dir schon mal.

Musikhai

skorpi08:
Hier mein Sketch vom Menü. Da kann man zwar auch Zeit/Datum einstellen, habs aber nicht fertig bekommen. http://pastebin.com/34trMagQ

Fast 1000 Zeilen Code, eine extra Menü-Library eingebunden, trotzdem haufenweise leere Codeblöcke ohne Funktion im Sketch und das ganze funktioniert nicht?

Ich habe den Code mal überflogen, das soll wohl offenbar ein full-featured mehrstufiges Menü werden, angelehnt an die Hauptmenüs wie sie unter grafischen Betriebssystemen auf großen Bildschirmen laufen: Hauptmenüpunkte "nebeneinander", darunter gestuft die Stufen der Untermenüs. Ob das die einfachste und bedienerfreundlichste Möglichkeit ist, das zu machen, was Du machen möchtest, da bin ich überfragt. Allerdings scheint es nicht die speichersparendste Art der Implementierung zu sein: Die ganzen Texte der Menüs sind ja nicht im Flash abgelegt, sondern im RAM. Sieht mir sehr aufwändig aus. Und ich kapiere es auch im Detail nicht, wie es funktionieren soll.

Den Unterschied zu meinem Ansatz im groben Ablauf mal kurz erklärt:
Bei meinem Ansatz gibt es ein "sequentielles Einstellmenü", das beim Drücken eines Buttons gestartet und dann Punkt für Punkt durchgegangen wird. Jeder Druck auf "Select" führt zum nächsten einstellbaren Parameter. Die Variation der Einstellwerte erfolgt durch die übrigen vier Tasten. Drückt man beim letzten Einstellwert wieder auf "Select", landet man wieder im Normalbetrieb.

Das ganze ließe sich natürlich noch aufbohren. Statt der fest programmierten Einstellung von Uhrzeit und Datum könnte man natürlich auch allgemeiner gehaltene Routinen vorsehen, mit denen ganz allgemein Zahlenwerte oder sogar Texte bearbeitet/eingestellt werden können oder mit denen aus Listen ein Wert ausgewählt werden kann, so dass man es einfach in eigenem Code verwenden kann.

Und im "Normalbetrieb" könnte man auch noch Modifikationen vorsehen, z.B. Umschaltung von Anzeigewerten. Außer der "Select"-Taste sind die übrigen Tasten im Normalbetrieb ja ohne Funktion, die könnte man so programmieren, dass mit Up, Down, Left, Right zwischen vier verschiedenen Normalbetrieb-Anzeigen umgeschaltet werden kann.
Up ==> Normalbetrieb, Anzeigewerte 1 (z.B. Temperaturen)
Doiwn ==> Normalbetrieb, Anzeigewerte 2 (z.B. Schaltzustände)
Left ==> Normalbetrieb, Anzeigewerte 3 (Uhrzeit, Datum, Sonnenaufgang, Sonnenuntergang)
Right ==> Normalbetrieb, Anzeigewerte 4 (keine Ahnung was, Reserve)
Select ==> Start des sequentiellen Einstellmenüs

Ich könnte mir vorstellen, dass man mit einem Keypad-Shield (oder LCD + 5 digitalen Buttons) schon eine ganze Menge an Einstellungen und Anzeigen auf diese Weise realisieren kann, wenn man ein sequentielles Einstellmenü und zusätzlich vier umschaltbare Normalbild-Anzeigen zur Verfügung hat.

Ich finde jedenfalls: Es muß auf einem kleinen 16x2 LCD mit einigen Buttons nicht unbedingt versucht werden, dieselbe Menüsteuerung nachzubauen, wie man sie auf grafischen Betriebssystemen mit großen Monitoren benutzt.

@Musikhai:
Wie bereits geschrieben, mußt Du Code-Tags in ECKIGE Klammern setzen. Die runden Klammern hatte ich nur für die schematische Darstellung gesetzt, damit Du siehst, wie das mit den Code-Tags geht. Hätte ich da eckige statt runde Klammern verwendet, hättest Du eine Code-Sektion gesehen.

Und wo ist jetzt das Problem mit Deinem Code? Natürlich muß die tatsächlich Ausgabe in der Funktion "updateDisplay()" erfolgen, d.h. Du mußt Deine Ausgabeanweisungen "lcd.setCursor" und "lcd.print" aus der Loop entfernen und in die Funktion "updateDisplay" einbauen. Stattdessen mußt Du globale Variablen zur Aufnahme der Temperaturen deklarieren, und diese Temperaturen in der loop zuweisen. Also oben im Programm:
float tempS0, tempS1;
In der loop dann:
tempS0=sensors.getTempCByIndex(0);
tempS1=sensors.getTempCByIndex(1);
Und in der updateDisplay-Funktion dann die Temperaturen tempS0 und tempS1 auf dem Display ausgeben lassen.

Bei Deinem System muss man alle 20 Menüs abackern bis man wieder zum ersten gelangt. Bei meinem System kann ich vor und zurück gehen und ich find es übersichtlicher.
Natürlich sind da Lücken, haufenweise codes die nicht benötigt werden, deswegen hatte ich ja geschrieben dass ichs nicht fertig bekommen hab.
Ob in RAM oder Flash, stört mich momentan nicht.

Binäre Sketchgröße: 12.826 Bytes -> meiner mit Uhrzeit Einstellen

Binäre Sketchgröße: 8.072 Bytes -> Deiner

Hallo, so bin jetzt zum lesen gekommen. Werde morgen mal dein Script ausprobieren skorpi. Vielen dank auch an dich jurs.

Mit deinem Vorschlag jurs, was man alles mit den Tasten machen könnte klingt sehr gut. Wobei ich noch nicht dahinter gestiegen bin, wie ich das programmieren soll. Deine Hilfe wäre echt von Vorteil.

Sagt mal , gibt es eigentlich Lecktüre, wo ich die Erstellung von Menüs nachlesen kann?

Skorpio habe mir gerade mal deinen Script angesehen. Habe aber leider die lcdmenu2.h Liberty nicht. Wo bekomme ich sie denn zum downloaden?

Hallo Marcus, vielen Dank für den Link, doch wie mache ich daraus eine library?

Musikhai:
Skorpio habe mir gerade mal deinen Script angesehen. Habe aber leider die lcdmenu2.h Liberty nicht. Wo bekomme ich sie denn zum downloaden?

Hatte ich doch schon gepostet: http://arduino.cc/forum/index.php/topic,73816.0.html
Unter dem ersten Post ist der Download Link.
Hier ein Direkter Link Arduino Forum für Version 1.0.1

Hier der Menü Sketch mit dem Sketch von jurs vereint: http://pastebin.com/8WMxsNpL
Binäre Sketchgröße: 11.782 Bytes

Wie man es ohne int readPadButtons() und int buttonPressed() macht, hab ich im moment keine Ahnung :blush:
Die Buttons sind da ja schon vom Menü Library definiert.