Probleme eines Anfängers :)

Ice-Man:
ich weis das ich mein problem mit debounce und nem interrupt in den griff bekomme ABER
das mit dem interrupt habe ich im bascom nichtmal richtig verstanden :sweat_smile: ....

Das mit dem Interrupt ist einfach. Bei einem Interrupt wird der abgearbeitet Kode unterbrochen und ein Interruptprogramm abgearbeitet. Nach Beendigung des Interruptprogramms wird das unterbrochene Programm an der unterbrochenen Stelle weiter abgearbeitet. Ein Interrupt kann von verschiedenen Ereignissen ausgelöst werden: Extern an Pins 2 und 3, durch Timer und Counter und anderes mehr.
Es gibt einige Dinge zu beachten.
http://arduino.cc/en/Reference/AttachInterrupt
http://arduino.cc/en/Reference/Interrupts
Grüße Uwe

Ich vertrete ja die Meinung, dass händische Eingaben in den seltensten Fällen einen Interrupt erfordern. Meist ist das dann einem schlechten Programmierstil geschuldet. Denkst du wirklich, du könntest einen Mikrocontroller, der mit 16 MHz getaktet ist mit einer RTC überfordern? XD
Mein Vorredner hats ja schon als Beispiel gebracht.

des stimmt ... hmm

ok ich gebe zu mein problem ist ich bin zu doof/unerfahren :frowning:

wenn ich jetzt in den cases switchen will bleibt er in case 1 bei der temperatur hängen und bekomme ihn dort nicht mehr wech .... dachte jetzt bint einer interrupt routine könne ich das problem lösen aber vllt kannst du mir einen anderen weg zeigen und mir ein paar tipps geben.

Am ende soll es eigendlich eine wetterstation ergeben die aus 2 atmegas besteht die via funk miteinander komunizieren sollen draussen werden temperatur, luftdruck, windgeschwindigkeit, windrichtung usw ermittelt und an die arduino drinnen gesendet die diese sachen erstmal auf einem 16x2lcd ausgeben soll und später auf nem glcd 128x64.

hier mal mein code bitte net lachen vermute mal das es im groben ganz großer bock mist ist aber es ist mein erstes projekt mit einem arduino ....

#include <LiquidCrystal.h>
float tempC = 0;  // variable for holding Celcius temp (floating for decimal points precision)
float tempf = 0;  // variable for holding Fareghneit temp
int tempPin = 0;  // Declaring the Analog input to be 0 (A0) of Arduino board.
float samples[8]; // array to hold 8 samples for Average temp calculation
float maxi = 0,mini = 100; // max/min temperature variables with initial values. LM35 in simple setup only measures Temp above 0.
int i;
int ButtonDown = 8;
int backLight = 13;    // pin 13 schaltet die hintergrundbeleuchtung
int page;

  // Connections:
  // rs (LCD pin 4) to Arduino pin 12
  // rw (LCD pin 5) to Arduino pin 11
  // enable (LCD pin 6) to Arduino pin 10
  // LCD pin 15 to Arduino pin 13
  // LCD pins d4, d5, d6, d7 to Arduino pins 5, 4, 3, 2
LiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2);

void setup()
  {
    pinMode(ButtonDown, INPUT); 
    pinMode(backLight, OUTPUT);
    digitalWrite(ButtonDown, LOW);  
    digitalWrite(backLight, HIGH);  //LCD Licht an
    lcd.begin(16,2);              
    lcd.clear();                 
    lcd.setCursor(0,0);           
    lcd.print("Wetterstation");    
    lcd.setCursor(0,1);           
    lcd.print("Version 1.0");
    delay(2000);                  //Wartet 2 Sekunden
    lcd.clear(); 
  }

void loop(){

  if (digitalRead(ButtonDown) == HIGH)
    page = (page+1)%3; // Dreiseitiges Menue. '%' ('modulo') sorgt dafuer dass nach '2' wieder '0' kommt...

  switch (page) {
    case 0:                    // erste Seite
              lcd.setCursor(0,0);           
              lcd.print("Case0");    
              lcd.setCursor(0,1);           
              lcd.print("Zeit Datum");
          break;
    case 1:                  //zweite Seite
              
              for(i = 0;i<=7;i++){ // gets 8 samples of temperature
              samples[i] = ( 4.4 * analogRead(tempPin) * 100.0) / 1024.0;
              lcd.clear();           
              lcd.setCursor(0, 0); // set LCD cursor position
              lcd.print("Innen: "); // print to LCD
              lcd.setCursor(12, 0); 
              lcd.print(samples[i]);  // print current Temp sample to LCD
              lcd.setCursor(0,1);           
              lcd.print("Aussen:");
              lcd.setCursor(12, 1);
              lcd.print("N/A");
              delay(1000);
            
          
        }
          break;
    case 2:                // dritte Seite
              lcd.setCursor(0,0);           
              lcd.print("Case2");    
              lcd.setCursor(0,1);           
              lcd.print("Luft Wind");
          break;
  }
}

Ice-Man:
ok ich gebe zu mein problem ist ich bin zu doof/unerfahren :frowning:

Das "doof" gefällt mir nicht. Bin für "unerfahren".

Ice-Man:
wenn ich jetzt in den cases switchen will bleibt er in case 1 bei der temperatur hängen und bekomme ihn dort nicht mehr wech ....

 if (digitalRead(ButtonDown) == HIGH)

Wiederholt sich solange Du den Taster drückst. Da Du ein langes Delay in der Temperaturausgabe hast arbeitest Du die verschiedenen case durch bis Du in der Temperaturausgabe hängen bleibst

Gib mal die Variable "page" über die Seriele Schnittstelle an das Terminal im IDE aus. Da wirst Du es sehen.

Wenn Du willst daß bei jedem Tastendruck die Zahl um 1 erhöt wird dann brauchst
Du eine andere Programmierlogik. Du mußt zuerst kontrollieren ob eine Taste gedrückt ist und dann ob sie losgelassen wurde um dann zu wissen daß die Variable zu erhöhen ist oder nicht. Außerdem mußt Du den Taster entprellen.

Viele Grüße Uwe

hallo uwe

danke für deine schnelle und ausführliche antwort ....

ich werde mal schauen ob ich da etwas lese stoff zu finde und mich dann mal dran versuchen :slight_smile:

so nu ist es spät hab mir einiges übers entprellen und vergleichen durchgelesen und hab mich jetzt glaube ich mal total verklammert wobei ich dachte das ich auf dem richtigen weg bin .....

#include <LiquidCrystal.h>
float tempC = 0;     // variable for holding Celcius temp (floating for decimal points precision)
float samples[8];    // array to hold 8 samples for Average temp calculation
int tempPin = 0;     // Temperatursensor LM35 an Analogpin 0
int i;
int ButtonDown = 8;       // Taster an Digitalpin 8
int backLight = 13;       // pin 13 schaltet die hintergrundbeleuchtung
int page;
int buttonVal = 0;        // wert des Tasters
int buttonValprell = 0;   // entprellt den Taster
int buttonstatus;

  // Connections:
  // rs (LCD pin 4) to Arduino pin 12
  // rw (LCD pin 5) to Arduino pin 11
  // enable (LCD pin 6) to Arduino pin 10
  // LCD pin 15 to Arduino pin 13
  // LCD pins d4, d5, d6, d7 to Arduino pins 5, 4, 3, 2
LiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2);

void setup()
  {
    pinMode(ButtonDown, INPUT); 
    pinMode(backLight, OUTPUT);
    digitalWrite(ButtonDown, LOW);  
    digitalWrite(backLight, HIGH);  //LCD Licht an
    lcd.begin(16,2);              
    lcd.clear();                 
    lcd.setCursor(0,0);           
    lcd.print("Wetterstation");    
    lcd.setCursor(0,1);           
    lcd.print("Version 1.0");
    delay(2000);                  //Wartet 2 Sekunden
    lcd.clear(); 
  }

void loop(){
   buttonVal = digitalRead(ButtonDown);  // Taster auslesen
   delay(10);  // 10 Millisekunden warten
   buttonValprell = digitalRead(ButtonDown);  // nochmal Taster auslesen
   if (buttonVal == buttonValprell)  // wenn gleich dann schwingt nichts mehr
 {
   if(buttenVal != buttonstatus)  // veränderung des Tasters abfragen
 {
    if (ButtonVal == HIGH) 
    page = (page+1)%3; // Dreiseitiges Menue. '%' ('modulo') sorgt dafuer dass nach '2' wieder '0' kommt...
 }
 
  switch (page) {
    case 0:                    // erste Seite
              lcd.setCursor(0,0);           
              lcd.print("Case0");    
              lcd.setCursor(0,1);           
              lcd.print("Zeit Datum");
          break;
    case 1:                  //zweite Seite
              
              for(i = 0;i<=7;i++){ // gets 8 samples of temperature
              samples[i] = ( 4.4 * analogRead(tempPin) * 100.0) / 1024.0;
              lcd.clear();           
              lcd.setCursor(0, 0); // set LCD cursor position
              lcd.print("Innen: "); // print to LCD
              lcd.setCursor(12, 0); 
              lcd.print(samples[i]);  // print current Temp sample to LCD
              lcd.setCursor(0,1);           
              lcd.print("Aussen:");
              lcd.setCursor(12, 1);
              lcd.print("N/A");
              delay(1000);
            
          
        }
          break;
    case 2:                // dritte Seite
              lcd.setCursor(0,0);           
              lcd.print("Case2");    
              lcd.setCursor(0,1);           
              lcd.print("Luft ind");
          break;
  }
}

Du mußt buttonstatus irgendwo, bei jedem Zustandswechsel den Status des buttonVal geben
Grüße Uwe

so nachdem ich meine tippfehler und verklammerungen entfernt habe läuft mein code wieder und er nimmt jeden einzelnen tastendruck wenn ich den taster gedrückt halte zählt er trozdem nur einen druck 1a :

if (ButtonVal == HIGH)
page = (page+1)%3; // Dreiseitiges Menue. '%' ('modulo') sorgt dafuer dass nach '2' wieder '0' kommt...
}
{
buttonstatus = buttonVal;
}
switch (page) {

ABER .....

in Case1 bleibt er trozdem noch wegen dem delay(1000); hängen

wenn ich es entferne flackert mein display wie hulle und die stelle nach dem komma ist nichtmehr erkennbar

wie bekomme ich es gelöst das er troz meinem wait von einer sekunde sauber durch die cases switcht ????

Mach im case eine millis-Abfrage
if(currentMillis - previousMillis > interval) {
und in der IF schreibst du den Wert neu.
dadurch kannst du delay weg lassen, er aktualisiert dann immer nur wenn zb eine Sekunde um ist

Schau dir dazu mal blink without delay an

okay also ....

ähm .... das klingt sehr gut nur irrgedwie will bei mir der funke net überspringen ...

bzw. ich verstehe das prinzip das program arbeitet weiterhin das ganze program ab und überprüft einfach nur ob es schon an der zeit ist meinen wert im case 1 neu auszugeben

nur ich hab noch ein dickes fragezeichen zur umsetzung ....

    case 1:                  //zweite Seite
              
              for(i = 0;i<=7;i++){ // gets 8 samples of temperature
              samples[i] = ( 4.4 * analogRead(tempPin) * 100.0) / 1024.0;
              lcd.clear();           
              lcd.setCursor(0, 0); // set LCD cursor position
              lcd.print("Innen: "); // print to LCD
              lcd.setCursor(12, 0); 
              lcd.print(samples[i]);  // print current Temp sample to LCD
              lcd.setCursor(0,1);           
              lcd.print("Aussen:");
              lcd.setCursor(12, 1);
              lcd.print("N/A");
              delay(1000);
        }

das würde doch dann heißen das ich in meinem gesammten code niergendwo ein delay nutzen darf .... da ich noch eine rtc uhr mit einbinden will und andere kleinigkeiten müsste ich ja für jedes delay einen interval schreiben oder kann ich den mehrmals verwenden ohne ihn jedesmal neu zu schreiben????

Du brauchst Dir nicht mal die Zeit merken

   case 1:                  //zweite Seite
              if ((millis() % 1000) == 0){              
                for(i = 0;i<=7;i++){ // gets 8 samples of temperature
                samples[i] = ( 4.4 * analogRead(tempPin) * 100.0) / 1024.0;
                lcd.clear();           
                lcd.setCursor(0, 0); // set LCD cursor position
                lcd.print("Innen: "); // print to LCD
                lcd.setCursor(12, 0); 
                lcd.print(samples[i]);  // print current Temp sample to LCD
                lcd.setCursor(0,1);           
                lcd.print("Aussen:");
                lcd.setCursor(12, 1);
                lcd.print("N/A");
              }
        }

So aktualisiert sich das Display nur, wenn millis() einem vielfachen von 1000 entspricht, also 1x pro Sekunde.

Nicht gut! Wenn er zu der entsprechenden Millisekunde nicht an der Stelle ist wird das Display nicht aktualisiert.

Würde mir auch einfach den letzten Wert merken (also die Sekunde) und wenn der aktuelle davon abweicht das Display refreshen und den neuen Wert merken.

Ungefähr was in der Richtung:

  int lastSecond;
...
  if (lastSecond != millis()/1000) {
    lastSecond = millis()/1000;
    ... // Update Display
  }

Du kannst trotzdem weiterhin delays verwenden solltest es aber wo es geht vermeiden!
Du kannst hin gehen und deine Fühler ja abfragen lassen wenn du magst aber nur das Display im sekundentakt aktualisieren.
Du kannst eine oldmillis-Variable für alle Screens verwenden da ja immer nur einer angezeigt wird.
Wenn du aber die RTC auch darüber abfragen willst musst du eine neue Variable nehmen.

Du kannst, du kannst hihi

long previousMillis = 0;        // will store last time LED was updated
long interval = 1000;           // interval at which to blink (milliseconds)
unsigned long currentMillis = millis();

case 1:                  //zweite Seite
  if(currentMillis - previousMillis > interval) {
        previousMillis = currentMillis;
              for(i = 0;i<=7;i++){ // gets 8 samples of temperature
              samples[i] = ( 4.4 * analogRead(tempPin) * 100.0) / 1024.0;
              lcd.clear();           
              lcd.setCursor(0, 0); // set LCD cursor position
              lcd.print("Innen: "); // print to LCD
              lcd.setCursor(12, 0); 
              lcd.print(samples[i]);  // print current Temp sample to LCD
              lcd.setCursor(0,1);           
              lcd.print("Aussen:");
              lcd.setCursor(12, 1);
              lcd.print("N/A");
              delay(1000);
        }

}

So werden wenn ich mich nicht irre jede Sekunde die temps ausgelesen und angezeigt.

Joghurt:
Nicht gut! Wenn er zu der entsprechenden Millisekunde nicht an der Stelle ist wird das Display nicht aktualisiert.

Ich hab mir schon gedacht, dass der Einwand kommt. Ich hab es extra aussen vor gelassen, weil ich wissen wollte, wer es als Erster bemängelt ]:smiley:

Ich würde den ganzen switch/case Block für die Anzeige in eine Funktion auslagern (nennen wir sie mal Ausgabe()).
für die sekündliche Anzeige erfolgt dann der Aufruf so:

  if ((millis() % 1000) == 0)
    Anzeige();

Und beim Seitenwechsel aufgrund eines Buttondrucks wird Anzeige() einfach zusätzlich aufgerufen.
Dass dabei unter Umständen die Anzeige zweimal kurz nacheinander aktualisiert wird ist ja egal.

nun hab ich das mit dem interval usw. richtig verstanden und kann es auch anwenden :slight_smile: ich hätte nicht gedacht das es für ein problem 10 verschiedene lösungswege gibt ... unglaublich

so alles in allem funktioniert nun das switch case und auc die saubere ausgabe meiner temperatur ginial

ihr seit der hammer .... :slight_smile:

bekomm ich eigendlich auch probleme wenn ich delay ausserhalb der switch case anweisung verwende???

und

kann ich meine prozesse auch ausserhalb der cases bearbeiten so das ich im case nur noch print befehle nutze?

Nein, Du kannst das Auslesen des Sensors auch außerhalb des switch/case Blocks machen. Aktuell wird der Sensor nur ausgelesen, wenn die Temperatur auch angezeigt wird, verlagerst Du den Teil nach "Außen", wird die Temperatur bei jedem Durchlauf gemessen. Das hätte z.B. den Vorteil das Du Dir immer den höchsten und den niedrigsten Wert merken kannst, auch wenn die Temperatur gerade nicht angezeigt wird.

Evtl. findest Du ja was hilfreiches bei meinem Min-Max Thermometer: Maintenance - Wartungsmodus

Grüße,
Mario.

klasse danke für deinen link ..
das dht11 wollte ich mir auch für meine aussen einheit besorgen :slight_smile:

ffür den aussenbereich finde ich auch die aufzeichnung des min max wertes sehr interessant den würde ich später auch sehr gerne mit uhrzeit loggen um ihn am pc auszuwerten z.b. in diagrammen
aber das ist im mom noch zukunfftsmusik xD

An einer Wetterstation baue ich auch gerade. Für Temperatur und Luftfeuchtigkeit würde ich aber den DHT22 empfehlen. Der ist zwar etwas teurer, aber dafür genauer. Der DHT11 hat bis zu 2°C Abweichung, kann nur 0°C bis 50°C Temperatur und 20%-90% relative Luftfeuchte messen.
Der DHT22 hat eine Genauigkeit von 0,5°C und misst von -40°C bis 80°C, wichtig bei Minusgraden im Winter. Außerdem kann der DHT22 von 0% bis 100% relative Luftfeuchte messen.

Nachteil der DHT22 ist, er kann nur alle 2 Sekunden statt jede Sekunde wie der DHT11 abgefragt werden, was ich persönlich nicht so schlimm finde. Man muss es nur in seinem Programm berücksichtigen.

Zusätzlich verwende ich noch den Drucksensor BMP085 der zusätzlich auch nochmal die Temperatur misst.

Meine aktuell noch freihand verdrahtete Station basiert auf dem Arduino Ethernet. Die Software auf dem Arduinoboard arbeitet dabei als Webclient, die jede Minute die aktuellen Daten (zur Zeit Innentemperatur, Außentemperatur, Luftfeuchte innen und außen, Luftdruck sowie zusätzlich die Temperatur die der BMP085 misst) an einen Webserver überträgt. Die Daten landen in einer Datenbank und werden über ein PHP-Script aufbereitet. Die Ausgabe erfolgt bei uns auf ein Netbook, bzw. ein Tablet. (siehe Anhang)
Evtl. ist die Tablet-Lösung auch was für Dich? Ein Arduino mit Grafikdisplay und ggf. einem Funkmodul kostet vermutlich nicht viel weniger als ein einfaches Android Tablet. Die billigen Teile sind zwar meistens nicht super verarbeitet, aber besser als ein kleines Display allemal und bei Ebay bekommt man die Dinger schon um die 100 Euro.

Aktuell kämpfe ich noch mit einem Windsensor (TX20) der eigentlich für eine fertige Wetterstation gedacht ist. Sobald ich dem die richtigen Daten entlocken kann, will ich alles zusammenbauen und in ein Gehäuse verfrachten. Das wird aber wohl noch bis Weihnachten dauern.

Viele Grüße,
Mario.

hallo summary

also den dht22 kann ich auch nehmen hast recht an die minus grade hab ich net so schnell gedacht :slight_smile:

das mit dem tablet wäre auf dauer divinitiv eine sehr gute lösung

jetzt such ich aber erstmal nach einer vernünftigen ausseneinheit windsensor windrichtung regen usw.

dazu wollte ich eigendlich noch protokolieren ab wann es draussen hell wird und ab wann es wieder dunkel wird wobei das noch zweitrangig ist

Windrichtung und -geschwindigkeit ist spannend, da bin ich auch gerade dran. Schau mal bei wetterladen24.de, dort gibt es die Windsensoren und einen Regensensor als Ersatzteil für die "großen" Wetterstationen. Sogar recht billig mit 20 Euro. Der Regensenor ist einfach, der hat einen kleinen Schalter (Reed-Kontakt) der bei einer bestimmten Regenmenge kurz geschlossen wird. Das kann man einfach via Interrupt abfangen und zählen.
Der Windsensor ist da schon schwieriger, der hat eine eigene Elektronik und sendet in einem proprietären One-Wire Protokoll codiert die Messdaten.
An einem eigenen Windsensor hab ich testweise auch schon gebastelt: Maintenance - Wartungsmodus.
In dem dazugehörigen Sketch findest Du auch Code zum Zählen von Ereignissen via Interrupt.

ich hab damals mal für sompfy rolladentechnik die messestände gebaut die haben auch sehr nette windsensoren die arbeiten ganz simpel mit 2 reedkontakten sowas wäre meiner meinung nach einfacher ...

hab bei den führenden auktionshäusern auch schon sehr tolle kombinationen (wingeschwindigkeit und richtung) gefunden
die aber auch alle wieder spizielle kodierungen haben ...

da ich nen totaler neuling bin wie man sicher schon in diesem thread bemerkt hat, habe ich noch meine bedenken ob ich es auch wirklich schaffe sowas ans laufen zu bekommen :((