Go Down

Topic: Arduino Uno und Menü für LCD Keypad Shield (Read 13 times) previous topic - next topic

skorpi08

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

Musikhai

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

jurs

#22
Mar 30, 2013, 01:50 pm Last Edit: Mar 30, 2013, 02:22 pm by jurs Reason: 1

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.

skorpi08

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

Nicht Mensch, nicht Tier: Programmierer halt...

Musikhai

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?


Go Up