Programmierbarer Timer

Hey Leute,

ich muss für die arbeit (Kartbahn) einen Programmierbaren Timer basteln. Dachte das mach ich mit nem Arduino Uno. Das Teil soll so aussehen, dass man es mittels 4 Knöpfen einstellen kann (+1 min, +10 min, reset, start) und es die Zeit auf einer großen LCD-Zeitanzeige ausgibt. (4 Ziffern).
Jetzt die frage: Wie stell ich das am blödsten an? Hab schon bisschen erfahrung mit c und dachte, eine int variable zu benennen, welche per knopfdruck (testweise mit scanf in c) bestimmt werden kann, also im muster minuten und dann gestartet wird. Nur ich weiß nicht genau wie ich das umsetzten kann....

könnt ihr mir helfen?
Danke schonmal!

Ich versteh dein Problem nicht.
(Wofür soll das scanf gut sein ?)

An einer oder zwei "int Variablen" musst du nicht sparen.
Kannst evtl. auch gleich an dein Display denken und 4 Variable für die 4 Ziffern nehmen.

Gönn dir noch eine bool(ean) Variable, die zwischen reset und gestartet unterscheidet.

Wie wird deine "goße LCD Anzeige (4 Ziffern)" angesteuert?

michael_x:
Ich versteh dein Problem nicht.
(Wofür soll das scanf gut sein ?)

An einer oder zwei "int Variablen" musst du nicht sparen.
Kannst evtl. auch gleich an dein Display denken und 4 Variable für die 4 Ziffern nehmen.

Gönn dir noch eine bool(ean) Variable, die zwischen reset und gestartet unterscheidet.

Wie wird deine "goße LCD Anzeige (4 Ziffern)" angesteuert?

scanf sollte das kommando einlesen (hatte die idee bei c, aber gibts ja bei arduino nicht so)

kannst mir das mit der bool mal erklären?

das weiß ich noch nicht so genau. dachte an bcd code und nem übersetzter

Wenn du was von Serial Einlesen und Parsen willst, geht das anders:
http://forum.arduino.cc/index.php?topic=359203.msg2486412#msg2486412
http://forum.arduino.cc/index.php?topic=364658.msg2513488#msg2513488

scanf() gibt es auf dem Arduino schon. Aber das ist standardmäßig nicht mit einem Input Stream verknüpft.

Eine primitive Alternative ist auch parseInt(). Das blockiert, weshalb es in den meisten richtigen Programmen Schrott ist, aber als Test kann es ok sein.

Das hat mit scanf überhaupt nichts zu tun! scanf (wobei auch nicht in normalen Programmen zu empfehlen) kümmert sich um die formatierte Eingabe. Das hat mit dem hier geschilderten Ablauf nichts zu tun. Du liest einen Eingang, nicht einen String etc.

Er will als Test die Tasteneingabe durch Serial ersetzen. Kann man machen. Geht aber auch erst mal am Problem vorbei.

Meinst du mit Timer einen Countdown? Also Zeit einstellen und dann gegen Null zählen?

scanf gibt es schon, aber...

Du programmierst einen µController, der hat 20 Pins, aber erstmal keinen Monitor und keine Tastatur.

Wenn du die Hardware für deine 4 Taster noch nicht hast, nimm ein Stück Draht. Das ist einfacher als
Serial Texteingaben auszuwerten.

Das war jetzt etwas zu überspitzt, natürlich gibt es auf dem Arduino Serial und das ist auch sinnvoll um zu sehen, was überhaupt passiert.


kannst mir das mit der bool mal erklären?

// Taster Pin - Belegung
#define START  2
#define RESET  3
#define ZT_1   4
#define ZT_10 5

bool running; // true : Zeit läuft
              // false: nach Reset wird erstmal auf den Start - Taster gewartet.

unsigned long letzteZeit;  // damit nur einmal pro Sekunde die Zeit runtergezählt wird

void setup() {
   pinMode(START, INPUT_PULLUP);  // LOW wenn gedrückt
   pinMode(RESET, INPUT_PULLUP);
   pinMode(ZT_1, INPUT_PULLUP);
   pinMode(ZT_10, INPUT_PULLUP);
}

void loop() {
  if (digitalRead(START) == LOW) running = true;
  if (digitalRead(RESET) == LOW) running = false;
  unsigned long now = millis(); 
  if ( now - letzteZeit > 1000 && running ) {
     letzteZeit = now;
     // Timer runterzählen und anzeigen  ( TODO )
  }
  
}

Schau dir dazu die Beispiele zu INPUT_PULLUP an.
Zum Prellen hast du hier Glück, da START gerne mehrfach als gedrückt (LOW) erkannt werden kann.
Wenn du das für das Hochstellen der Timers erweiterst, musst du mehr machen...

Aber schliess erstmal die Anzeige an, da hast du mehr Spass.

Terrawr:
... Programmierbaren Timer basteln ...

Was Du schreibst klingt, als hättest Du noch keinen Arduino.

Falls das der Fall ist, kommt hier mein Senf zur Sache: Leg’ Dir erstmal so ein Ding zu und lerne es kennen. Wenn Du ein bisschen Basiswissen hast, ist der Rest keine sooo wilde Angelegenheit.

Gruß

Gregor

Terrawr:
könnt ihr mir helfen?

Der Sketch hier ist für so etwas ähnliches und für ein Text-Display als Anzeigehardware geschrieben.

Drei Buttons (Plus, Minus, Start) werden verwendet, für eine Zeiteinstellung bis max. 10 Minuten (in Sprüngen von 10 Sekunden) und einem zusätzlichen Relais-Schaltausgang, das war wohl für eine Blichtungssteuerung zur Belichtung von Fotoplatinen. Anzeige der Einstellzeit und des Countdowns auf einem Text-LCD.

Die loop()-Funktion brauchst Du dabei glaube ich nicht verändern, auch wenn Dein Programm etwas anders laufen soll:

#include <LiquidCrystal.h>
// LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
LiquidCrystal lcd(8,9,4,5,6,7);

struct button_t{byte pin; byte val; boolean pressed;};

const byte NUMBUTTONS=3;
button_t buttons[NUMBUTTONS]={ 
  {2},  // Pin-Nummer für Minus-Button
  {A3},  // Pin-Nummer für Plus-Button
  {3}, // Pin-Nummer für Start-Button
};

const long defaultZeit=30000L;
long zeit=defaultZeit; // in Millisekunden

enum {EINSTELLEN, COUNTDOWN};
byte mode=EINSTELLEN;

void eingabe()
{
  static unsigned long lastTime;
  long now=millis();
  for (int i=0;i<NUMBUTTONS;i++) buttons[i].pressed=false;
  if (now-lastTime<5) return;
  lastTime=now;
  byte val;
  for (int i=0;i<NUMBUTTONS;i++)
  {
    val=!digitalRead(buttons[i].pin);
    if (val==HIGH && buttons[i].val==LOW) buttons[i].pressed=true;
    buttons[i].val=val;
  }
}

void verarbeitungEinstellen()
{
  if (buttons[0].pressed)
  {
    zeit-=10000L; // 10 Sekunden abziehen
    if (zeit<0) zeit=0;
  }
  if (buttons[1].pressed)
  {
    zeit+=10000L; // 10 Sekunden draufschlagen
    if (zeit>600000L) zeit=600000L;
  }
}


unsigned long countDownStart;

void verarbeitungCountDown()
{
  long diff=millis()-countDownStart;
  if (diff==0) return;
  countDownStart+=diff;
  zeit-=diff;
  if (zeit>0) return;
  zeit=defaultZeit;
  mode=EINSTELLEN;
}

void verarbeitung()
{
  if (buttons[2].pressed) // Start-Button gedrückt: Wechsel zwischen EINSTELLEN und COUNTDOWN
  {
    if (mode==EINSTELLEN)
    {
      countDownStart=millis();
      mode=COUNTDOWN;
    }
    else mode=EINSTELLEN;
  }
  else if (mode==EINSTELLEN) verarbeitungEinstellen();
  else if (mode==COUNTDOWN) verarbeitungCountDown();
}



void ausgabe()
{
  int seconds=zeit/1000;
  int minutes=seconds/60;
  seconds=seconds%60;
  char buf[17];
  snprintf(buf,sizeof(buf),"%02d:%02d",minutes,seconds);
  lcd.setCursor(0,0);
  lcd.print(buf);
  lcd.setCursor(0,1);
  if (mode==EINSTELLEN) lcd.print("Einstellen");
  else if (mode==COUNTDOWN) lcd.print("Countdown ");
}

void setup() 
{
  lcd.begin(16, 2);
  lcd.clear();
  lcd.print(" Zeitsteuerung");
  lcd.setCursor(0, 1);
  lcd.print("   Belichtung");  
  delay(3000);
  lcd.clear();
  for (int i=0;i<NUMBUTTONS;i++)
  {
    pinMode(buttons[i].pin,INPUT_PULLUP);
  }
  eingabe();
}

void loop() 
{
  eingabe();
  verarbeitung();
  ausgabe();
}

Und der Code is soweit modular gehalten, dass Du beispielsweise nur die Funktion "ausgabe()" umschreiben brauchst, wenn Du anstelle eines Text-LCD irgendwas anderes als Einstell- und Countdown-Anzeige verwenden möchtest.

gregorss:
Was Du schreibst klingt, als hättest Du noch keinen Arduino.

Falls das der Fall ist, kommt hier mein Senf zur Sache: Leg’ Dir erstmal so ein Ding zu und lerne es kennen. Wenn Du ein bisschen Basiswissen hast, ist der Rest keine sooo wilde Angelegenheit.

Gruß

Gregor

nope... ich hab n board hier, hab aber bisher noch nicht so viel gemacht.

jurs:
Der Sketch hier ist für so etwas ähnliches und für ein Text-Display als Anzeigehardware geschrieben.

Drei Buttons (Plus, Minus, Start) werden verwendet, für eine Zeiteinstellung bis max. 10 Minuten (in Sprüngen von 10 Sekunden) und einem zusätzlichen Relais-Schaltausgang, das war wohl für eine Blichtungssteuerung zur Belichtung von Fotoplatinen. Anzeige der Einstellzeit und des Countdowns auf einem Text-LCD.

Die loop()-Funktion brauchst Du dabei glaube ich nicht verändern, auch wenn Dein Programm etwas anders laufen soll:

#include <LiquidCrystal.h>

// LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
LiquidCrystal lcd(8,9,4,5,6,7);

struct button_t{byte pin; byte val; boolean pressed;};

const byte NUMBUTTONS=3;
button_t buttons[NUMBUTTONS]={
  {2},  // Pin-Nummer für Minus-Button
  {A3},  // Pin-Nummer für Plus-Button
  {3}, // Pin-Nummer für Start-Button
};

const long defaultZeit=30000L;
long zeit=defaultZeit; // in Millisekunden

enum {EINSTELLEN, COUNTDOWN};
byte mode=EINSTELLEN;

void eingabe()
{
  static unsigned long lastTime;
  long now=millis();
  for (int i=0;i<NUMBUTTONS;i++) buttons[i].pressed=false;
  if (now-lastTime<5) return;
  lastTime=now;
  byte val;
  for (int i=0;i<NUMBUTTONS;i++)
  {
    val=!digitalRead(buttons[i].pin);
    if (val==HIGH && buttons[i].val==LOW) buttons[i].pressed=true;
    buttons[i].val=val;
  }
}

void verarbeitungEinstellen()
{
  if (buttons[0].pressed)
  {
    zeit-=10000L; // 10 Sekunden abziehen
    if (zeit<0) zeit=0;
  }
  if (buttons[1].pressed)
  {
    zeit+=10000L; // 10 Sekunden draufschlagen
    if (zeit>600000L) zeit=600000L;
  }
}

unsigned long countDownStart;

void verarbeitungCountDown()
{
  long diff=millis()-countDownStart;
  if (diff==0) return;
  countDownStart+=diff;
  zeit-=diff;
  if (zeit>0) return;
  zeit=defaultZeit;
  mode=EINSTELLEN;
}

void verarbeitung()
{
  if (buttons[2].pressed) // Start-Button gedrückt: Wechsel zwischen EINSTELLEN und COUNTDOWN
  {
    if (mode==EINSTELLEN)
    {
      countDownStart=millis();
      mode=COUNTDOWN;
    }
    else mode=EINSTELLEN;
  }
  else if (mode==EINSTELLEN) verarbeitungEinstellen();
  else if (mode==COUNTDOWN) verarbeitungCountDown();
}

void ausgabe()
{
  int seconds=zeit/1000;
  int minutes=seconds/60;
  seconds=seconds%60;
  char buf[17];
  snprintf(buf,sizeof(buf),"%02d:%02d",minutes,seconds);
  lcd.setCursor(0,0);
  lcd.print(buf);
  lcd.setCursor(0,1);
  if (mode==EINSTELLEN) lcd.print("Einstellen");
  else if (mode==COUNTDOWN) lcd.print("Countdown ");
}

void setup()
{
  lcd.begin(16, 2);
  lcd.clear();
  lcd.print(" Zeitsteuerung");
  lcd.setCursor(0, 1);
  lcd.print("  Belichtung"); 
  delay(3000);
  lcd.clear();
  for (int i=0;i<NUMBUTTONS;i++)
  {
    pinMode(buttons[i].pin,INPUT_PULLUP);
  }
  eingabe();
}

void loop()
{
  eingabe();
  verarbeitung();
  ausgabe();
}




Und der Code is soweit modular gehalten, dass Du beispielsweise nur die Funktion "ausgabe()" umschreiben brauchst, wenn Du anstelle eines Text-LCD irgendwas anderes als Einstell- und Countdown-Anzeige verwenden möchtest.

danke, soll aber kein lcd sondern n 4x7segment buastein am ende sein

michael_x:
scanf gibt es schon, aber...

Du programmierst einen µController, der hat 20 Pins, aber erstmal keinen Monitor und keine Tastatur.

Wenn du die Hardware für deine 4 Taster noch nicht hast, nimm ein Stück Draht. Das ist einfacher als
Serial Texteingaben auszuwerten.

Das war jetzt etwas zu überspitzt, natürlich gibt es auf dem Arduino Serial und das ist auch sinnvoll um zu sehen, was überhaupt passiert.


// Taster Pin - Belegung

#define START  2
#define RESET  3
#define ZT_1   4
#define ZT_10 5

bool running; // true : Zeit läuft
             // false: nach Reset wird erstmal auf den Start - Taster gewartet.

unsigned long letzteZeit;  // damit nur einmal pro Sekunde die Zeit runtergezählt wird

void setup() {
  pinMode(START, INPUT_PULLUP);  // LOW wenn gedrückt
  pinMode(RESET, INPUT_PULLUP);
  pinMode(ZT_1, INPUT_PULLUP);
  pinMode(ZT_10, INPUT_PULLUP);
}

void loop() {
 if (digitalRead(START) == LOW) running = true;
 if (digitalRead(RESET) == LOW) running = false;
 unsigned long now = millis();
 if ( now - letzteZeit > 1000 && running ) {
    letzteZeit = now;
    // Timer runterzählen und anzeigen  ( TODO )
 }
 
}




Schau dir dazu die Beispiele zu INPUT_PULLUP an.
Zum Prellen hast du hier Glück, da START gerne mehrfach als gedrückt (LOW) erkannt werden kann.
Wenn du das für das Hochstellen der Timers erweiterst, musst du mehr machen...

Aber schliess erstmal die Anzeige an, da hast du mehr Spass.

ok danke für den quellcode... aber kann ich den jetzt einfach so verwenden? und die variable letzte zeit kann einfach als ergebnis fürs signal verwendent werden?

Terrawr:
danke, soll aber kein lcd sondern n 4x7segment buastein am ende sein

Aus dem Grund trennt man ja Eingabe, Verarbeitung und Ausgabe. Dann kann man jeden der Teile für sich ändern ohne die anderen zu Beeinflussen

die variable letzte zeit kann einfach als ergebnis fürs signal verwendent werden?

Guck dirs an und versuche zu verstehen, wie die Variablen now, letzteZeit und das Ergebnis der Funktion millis() zusammenhängen. Vergleiche das mit dem berüchtigten BlinkWithoutDelay Beispiel :wink:

Wenn (running != true) wird letzteZeit zur Zeit nicht angefasst (weil da noch gar nichts passiert) und du könntest es für was auch immer missbrauchen, aber warum?

Was verstehst du unter "ergebnis fürs signal" ?