Arduino Intervalometer: Einschaltknopf entprellen?

Hi,

Als mein erstes Arduino Projekt habe ich mir den Bau eines Intervalometers für meine DSLR vorgenommen. Die erste Version funktioniert soweit auch ganz gut. Der Intervall wird mit drei Codierschaltern eingestellt (Das soll sich auch noch ändern, da dadurch nur 8 Intervalle möglich sind... Vielleicht wird irgendwann mal ein LCD Bildschirm zur freien Einstellung des Intervalls mit Tasten eingebaut) Die Intervallaufnahme lässt/ließ sich durch einen Taster starten, welcher aber oft prelllt, dadurch wird das Ganze sofort wieder gestoppt. Ich habe versucht den Taster so wie es in der Referrenz (http://www.arduino.cc/en/Tutorial/Debounce) steht zu entprellen, aber jetzt funktioniert garnichts mehr :drooling_face:...

Hier das Sketsch:

#include <MsTimer2.h>

// Kameraausloeser
#define kameraPin 13

// Laenge des Ausloesesignals
#define ausloeseZeit 500

// Codierschalter Eingänge
const int schalter1Pin = 2;
const int schalter2Pin = 3;
const int schalter3Pin = 4;

// Variablen für Codierung
int schalter1State;
int schalter2State;
int schalter3State;

// Intervall-Variable
long intervall;

// Pin's für Start & Stopp
int on_offPin = 8;
int on_offval;
int on_offState;
int on_off = 0;

// Codierung
boolean codierung = false;

unsigned long last_tm = 0;
boolean belichten = false;

long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 50;    // the debounce time; increase if the output flickers


void setup(){

  // Pin's definieren
  pinMode(schalter1Pin, INPUT);
  pinMode(schalter2Pin, INPUT);
  pinMode(schalter3Pin, INPUT);
  pinMode(kameraPin, OUTPUT);

  // Debugging 
  Serial.begin(9600);

  // Grundwert beim Einschalten
  on_offState = digitalRead(on_offPin);

}

void loop() {

  // Zustand des Startknopfes speichern
  on_offval = digitalRead(on_offPin);

  // Start-Taste gedrückt?
  if(on_offval != on_offState){ // Weicht der Zustand des Knopfes vom Grundwert beim Einschalten ab?
    lastDebounceTime = millis(); // aus der Refernz übernommen
    if(on_offval == LOW){ // Wenn ja, und er LOW ist und...
      if ((millis() - lastDebounceTime) > debounceDelay) { // aus der Refernz übernommen
      if(on_off == 0){ // ...nicht schon eingeschaltet wurde, dann...
        on_off = 1; // ...Modus auf "ein" setzen!
        Serial.println("an!");
      }
      else{
        on_off = 0; // Sonst Modus auf "aus" setzen!
        codierung = false; // Codierung zurücksetzen
        Serial.println("aus!");
      }
      }
    }
  }

  // Zustand des Knopfes während des Starts der Aufnahmesequenz mit dem Grundwert gleichsetzen
  on_offState = on_offval;

  // Wenn der Einschaltknopf gedrückt wurde...
  if(on_off == 1){

    // ...und die Codierung noch nicht vorgenommen wurde:
    if (codierung == false){
      intervall_bestimmung();
    }

    if(belichten == false && millis() - last_tm > intervall){
      MsTimer2::set(ausloeseZeit, camera_off);

      MsTimer2::start();

      // Intervall für Debugging ausgeben
      Serial.println(intervall);

      belichten = true;

      digitalWrite(kameraPin, HIGH);
    }
  }
}


void camera_off(){
  digitalWrite(kameraPin, LOW);

  MsTimer2::stop();

  last_tm = millis();

  belichten = false;
}

void intervall_bestimmung(){

  // Codierung auslesen
  schalter1State = digitalRead(schalter1Pin);
  schalter2State = digitalRead(schalter2Pin);
  schalter3State = digitalRead(schalter3Pin);

  // Codierung ausgeben für Debugging

  Serial.println(schalter1State);
  Serial.println(schalter2State);
  Serial.println(schalter3State);

  //Intervall ermitteln
  if(schalter1State == HIGH){
    if(schalter2State == HIGH){
      if(schalter3State == HIGH){  //HHH
        intervall = 1000;
      }
      if(schalter3State == LOW){   //HHL
        intervall = 2000;
      }
    }
    if(schalter2State == LOW){
      if(schalter3State == HIGH){  //HLH
        intervall = 3000;
      }
      if(schalter3State == LOW){   //HLL
        intervall = 5000;
      }
    }
  }
  else if(schalter1State == LOW){
    if(schalter2State == HIGH){
      if(schalter3State == HIGH){  //LHH
        intervall = 8000;
      }
      if(schalter3State == LOW){   //LHL
        intervall = 10000;
      }
    }
    if(schalter2State == LOW){
      if(schalter3State == HIGH){ //LLH
        intervall = 15000;
      }
      if(schalter3State == LOW){  //LLL
        intervall = 20000;
      }
    }
  }

  // Codierung auf wahr setzen
  codierung = true;
}

Was mache ich falsch? Habe schon viele andere Anleitungen für Debouncing angeschaut, hat aber allles nicht funktioniert oder war zu kompliziert für mich
Könnt ihr mir vielleicht einen Tipp geben? Ich bin natürlich immer für Verbesserungsvorschläge am Script offen :wink:

Lg Bofrie

hi Bofrie,

wäre es nicht einfacher 3 schalter zu nehmen?
die dann beim initialisieren auslesen und dann je nach stellung (da sind ja acht möglich) den auslösetimer zu setzen.
dann wenn du was ändern willst, einfach schalter umstellen und reset drücken. schon läufts mit der neuen einstellung.
da die schalter ja dann auch stehen sollte es mit dem entprellen keine probleme geben.

also so in der art:

int long TIMER = 500; // Basisverzoegerung

void setup() {
//Start Serielles Interface
Serial.begin(9600);
  
// Camera Pin
pinMode(13, OUTPUT);

// Schalter
pinMode(2, INPUT);
pinMode(3, INPUT);
pinMode(4, INPUT);

// interne Pullup Widerstände aktivieren
digitalWrite(2, HIGH);
digitalWrite(3, HIGH);
digitalWrite(4, HIGH);

// Schalterstellung lesen (Schalter schliessen auf Masse)
if ( digitalRead(2) == HIGH ) { TIMER = TIMER + 500; }  // Zusatz-Verzoegerung Schalter 2
if ( digitalRead(3) == HIGH ) { TIMER = TIMER + 1000; } // Zusatz-Verzoegerung Schalter 3
if ( digitalRead(4) == HIGH ) { TIMER = TIMER + 2000; } // Zusatz-Verzoegerung Schalter 4

// Ausgabe was nun eingestellt wurde
/*
5 4 3 - Arduino-Pin
L L L =  500 ms
L L H = 1000 ms
L H L = 1500 ms
L H H = 2000 ms
H L L = 2500 ms
H L H = 3000 ms
H H L = 3500 ms
H H H = 4000 ms
*/
Serial.print("Auslese-Verzoegerung = "); Serial.print(TIMER/1000); Serial.println(" sek.");
}

void loop() {
Serial.println("Klick");
// Bild machen
digitalWrite(13, HIGH);
delay(250);
digitalWrite(13, LOW);
delay(TIMER-250); //das ausloesen abziehen und warten bis zum naechsten bild
}

Die Werte der einzelnen Schalter kannst einfach abändern, da ich nicht genau weis welche Werte Du da möchtest.
Alternativ kannst auch komplett freie Werte für die einzelnen Schalterstellungen einstellen mit z.B. sowas:

if ( digitalRead(2) == LOW && digitalRead(3) == LOW && digitalRead(4) == LOW ) { TIMER = 5; } // 5 Sekunden
if ( digitalRead(2) == HIGH && digitalRead(3) == LOW && digitalRead(4) == LOW ) { TIMER = 30; } // 30 Sekunden 
if ( digitalRead(2) == LOW && digitalRead(3) == HIGH && digitalRead(4) == LOW ) { TIMER = 60; } // 1 Minute
if ( digitalRead(2) == HIGH && digitalRead(3) == HIGH && digitalRead(4) == LOW ) { TIMER = 90; } // 1,5 Minuten
if ( digitalRead(2) == LOW && digitalRead(3) == LOW && digitalRead(4) == HIGH ) { TIMER = 300; } // 5 Minuten
if ( digitalRead(2) == HIGH && digitalRead(3) == LOW && digitalRead(4) == HIGH ) { TIMER = 1800; } // 1/2 Stunde
if ( digitalRead(2) == LOW && digitalRead(3) == HIGH && digitalRead(4) == HIGH ) { TIMER = 3600; } // 1 Stunde
if ( digitalRead(2) == HIGH && digitalRead(3) == HIGH && digitalRead(4) == HIGH ) { TIMER = 86400; } // 1 Tag
TIMER=TIMER*1000; // Umrechnung der Sekunden in Millisekunden für den delay-Befehl

Oder war es was ganz anderes was Du wolltest?

grüße...
...eok

hi eok,

vielen Dank für deine ausführliche Antwort. Dadurch ist mir einiges klar geworden (Endlich die Sache mit den intigrierten Pullup Wiederständen kapiert ;)) Leider besteht mein eigentliches Problem immernoch: Debouncing. Ich möchte in das Intervalometer einen Startknopf, der die aufnahmesequenz startet, einbauen. Dieser ist an Pin 8 des UNO angeschlossen und funktioniert soweit auch, nur ich bekomme es nicht hin wie es in der Referenz steht zu entprellen :frowning:

In diesem Abschnitt ist das Problem:

  // Start-Taste gedrückt?
  if(on_offval != on_offState){ // Weicht der Zustand des Knopfes vom Grundwert beim Einschalten ab?
    lastDebounceTime = millis(); // aus der Refernz übernommen
    if(on_offval == LOW){ // Wenn ja, und er LOW ist und...
      if ((millis() - lastDebounceTime) > debounceDelay) { // aus der Refernz übernommen
      if(on_off == 0){ // ...nicht schon eingeschaltet wurde, dann...
        on_off = 1; // ...Modus auf "ein" setzen!
        Serial.println("an!");
      }
      else{
        on_off = 0; // Sonst Modus auf "aus" setzen!
        codierung = false; // Codierung zurücksetzen
        Serial.println("aus!");
      }
      }
    }
  }

Wenn ich die Sachen an denen "aus der Referenz übernommen" steht zum Entprelllen in das Sketch einfüge, funktioniert der Startknopf garnicht mehr...

Gruß Bofrie

Ich würde das anders lösen:

void blaaa() {
  static unsigned long lastDebounce = 0;

  if (lastDebounce == 0) {
    //wir schaun, ob wir bereits im debounce sind. wenn nicht, schaun wir, ob der button sich geändert hat
    on_offval = digitalRead(BUTTON_PIN);
    if (on_offval != on_offState) {
      //button geändert, wir starten den debounce
      lastDebounce = millis();
    }
  } else if (millis() > lastDebounce + 50) {
    //wir sind jetzt bereits im debounce und die wartezeit ist vergangen. wir testen nochmal den pin und übernehmen den jetzigen zustand als wert
    lastDebounce = 0;  //wichtig, wir müssen resetten, damit der debounce das nächste mal wieder gestartet werden kann.
    on_offval = digitalRead(BUTTON_PIN);
    if (on_offval == on_offState) {
      //da hat sich nix geändert, also muss auch nix ausgeführt werden
      return;
    }
    on_offState = on_offval;
    //tu hier, was mit dem neuen state getan werden soll (if on_offState = low u.s.w.)
  }
}

keine Gewähr, dass das sofort so kompiliert, oder funktioniert. Ich kann das halt nicht testen. Aber es geht ja auch primär um die Idee dahinter.

Vielen Dank für den Code, werde mich bald mal reinfuchsen und auf mein gerät übertragen :smiley: