Stoppuhr

Guten morgen allerseits,

ich habe eine kleine Frage bzgl. eines Programmaufbaus. Ich werde ersteinmal erklären was ich genau vorhabe.

Ich möchte gerne eine Stoppuhr bauen die von 00:00 (ss:msms) bis 99:99 (ss:msms) zählt. Diese soll über eine Lichtschranke gestartet werden und über ein Stoppsignal eines anderen Sensors gestoppt werden. Ebenfalls soll es möglich sein den Counter wieder zu reseten um die Anzeige auf 00:00 zu bringen. Die Anzeige soll über 4 x 7-Segmentanzeigen (100mm) erfolgen.

Da ich mich mit der Welt der Programmierung nur ansatzweise auskenne, suche ich nun hier ein wenig hilfe bzw. anregungen.

Meine ersten Überlegungen waren einen Timer so zu programmieren das ich alle 100ms ein Signal bekomme. Da bin ich auf die TimerOne-library gestoßen. Mit dieser kann ich ja alle 100ms einen Interrupt auslösen. Ist dies für dieses Projekt sinnvoll?

Weiterhin beschäftigt mich das Problem wie ich dem uC sage, ab wann bzw. bis wann er mir meinen Counter hochzählt und wie ich diesen wieder löschen kann, ohne das ich das komplette Board resete.

Wäre es möglich parallel zu den 7-Segmentanzeigen ein 2x16 LCD-Display mit Daten zu speisen? Es würde auch noch ein paar andere Funktionen geben die ich evtl. benötigen würde, jedoch lasse ich die jetzt erst mal außer betracht.

Über ein paar Tipps, Anregungen und gute Literaturhinweise wäre ich sehr erfreut. Ich danke im Voraus.

Liebe Grüße

Christian

Meine ersten Überlegungen waren einen Timer so zu programmieren das ich alle 100ms ein Signal bekomme. Da bin ich auf die TimerOne-library gestoßen. Mit dieser kann ich ja alle 100ms einen Interrupt auslösen. Ist dies für dieses Projekt sinnvoll?

Nein, denn der Arduino hat dies bereits vorinstalliert und Du kannst es mit millis() abfragen. Wieso Du nur jede Zehntelsekunden einen Interrupt haben wolltest, aber dann Hundertstelsekunden (ist meine Interpretation aus der Anzeige, Du redest von ms, was dann Tausendstelsekunden wären) anzeigen willst, bleibt mir schleierhaft.

Wenn Du das halbwegs genau haben willst, nimm einen Ardiuno mit Quartz und nicht Resonator (also Duemillanove oder einen Clone, wie z.B. Seeeduino oder Iteaduino), dann kriegst Du halbwegs genaue Werte.

Weiterhin beschäftigt mich das Problem wie ich dem uC sage, ab wann bzw. bis wann er mir meinen Counter hochzählt und wie ich diesen wieder löschen kann, ohne das ich das komplette Board resete.

Ich würde einen Taster vorschlagen. Wie Du den (sogar entprellt) einlesen kannst, findest Du zu Tausenden im Netz.

Wäre es möglich parallel zu den 7-Segmentanzeigen ein 2x16 LCD-Display mit Daten zu speisen?

Ja. Hängt natürlich noch davon ab, wie Du die 7-Segment-Anzeigen ansteuern willst, aber grundsätzlich ist das relativ einfach möglich.

Da ich mich mit der Welt der Programmierung nur ansatzweise auskenne, suche ich nun hier ein wenig hilfe bzw. anregungen.

Beginne mit einem einfacheren Beispiel, nicht gleich mit Deinem Stoppuhren-Projekt. Wenn Du die blinkende LED mal hast, musst Du Dich sicher mit dem BlinkWithoutDelay-Beispiel auseinandersetzen, damit Du lernst, wie man die delay()-Funktion vermeidet (wirst Du in Deinem Projekt brauchen) und dann solltest Du die Taster in Angriff nehmen. Wenn Du das alles im Griff hast, kannst Du mit Lichtschranken und dergleichen starten.

Ich denke, du kannst problemlos auf die Funktion millis() zurückgreifen, mit kannst du dich später noch beschäftigen. ;) Die Anzeige sollte kein großes Problem darstellen, 4 Siebensegment-Anzeigen lassen sich recht einfach über 4 kaskadierte Schieberegister ansprechen (ggf. erforderlichen Treiberstufen), ein LCD ist zusätzlich möglich. Dazu ein paar digitale Eingänge für die Lichtschranken, ein paar Taster um einen neuen Stopp-Vorgang zu starten usw.. Schönes Einsteigerprojekt, wo man eine Menge bei lernen kann!

Hallo,

schon einmal vielen Dank vorab für die Hilfe.

Hatte erst jetzt Zeit auf die Post zu Antworten. Ich habe mich jetzt ein wenig mit der der millis-Funktion beschäftigt und habe mir mal einen Counter zusammengebastelt.

void loop()
  {
    if((millis() - prev) > 9)
      {
        prev = millis();
        timer_hundert++;                
      }
      
    if(timer_hundert > 9)
      {
        timer_zehner++;
        timer_hundert = 0;              
      }
    
    if(timer_zehner > 9)
      {
        timer_1sekunde++;
        timer_zehner = 0;
      }
    
    if(timer_1sekunde > 9)
      {
        timer_2sekunde++;
        timer_1sekunde = 0;
      }
    
    if(timer_2sekunde > 9)
      {        
        timer_2sekunde = 0;
      }
  }

Kann man denn diesen Ansatz für meine Zwecke verwenden, oder gibt es da eine elegantere Methode?

Beste Grüße

Kann man denn diesen Ansatz für meine Zwecke verwenden, oder gibt es da eine elegantere Methode?

Ja, beides ;)

-- Wenn du es so haben willst ( für jede Dezimalziffer eine Variable ), ok.

-- Der Arduino ist schnell genug, da bringt es nichts, den Sketch schneller zu machen. Ansonsten: Wenn timer_hundert sich nicht ändert, brauchst du den Rest auch nicht. Wenn du z.B. die ``` if ``` ineinander schachtelst, wird in 9 von 10 Fällen auf die Ausführung von 4 sicher unzutreffenden if verzichtet, und in 99 von 100 Fällen sparst du immerhin 3 if. Aber wie gesagt, das stört vorerst nicht wirklich.

-- Elegant kann auch ein klares Programm mit wenig Verschachtelung sein, Geschmackssache. Mach erstmal weiter und bring deine LCD und/oder die 7-Segment-Anzeigen in Gang. Wenn da etwas unschön flackern sollte, kannst du nochmal über unnötigen Code nachdenken.

Ok, danke...

Nun habe ich aber noch eine weiterführende Frage bzgl. des 74HC595. Ich habe ja die Möglichkeit mithilfe des shiftOut-Befehls die Werte der Variablen in das Register zu schieben. Kann ich diese 4 byte auch als HEX reinschicken oder muss ich alle einzelnen Bits aneinanderketten? Sollte ich die Bits aneinanderketten müssen, wie stelle ich das am besten an? Da ich ja 4 Variablen habe.

Was schreibt denn die Online-Sprachreferenz?

shiftOut(dataPin, clockPin, bitOrder, value) .... value: the data to shift out. (byte)

Du musst also einzelne Bytes übergeben - bei 4 Schieberegistern also 4 Bytes hintereinander.

Ah, wer lesen kann ist klar im Vorteil. ;)

So, ich bin jetzt zum. schon mal soweit, dass meine Stoppuhr auf dem LCD einwandfrei hochzählen tut. Nun habe ich aber einen kleinen hänger bei dem Übertragen in das Register vom IC.

Angenommen ich habe die Zeit 11:11. Meine 4 Variablen haben also jeder eine 1. Wie kann ich diese 4 Werte am einfachsten zusammenfügen, so das ich am Ende eine 4byte große Zahl habe, die ich mit dem shiftOut-Befehl übertragen kann?

Wie kann ich diese 4 Werte am einfachsten zusammenfügen, so das ich am Ende eine 4byte große Zahl habe, die ich mit dem shiftOut-Befehl übertragen kann?

Du kannst dem shiftOut-Befehl keine 4 Byte übergeben, sondern nur ein Byte. Das kannst Du aber 4 Mal hintereinander machen.

Achtung Pseudocode:

for (int i=0; i<4; i++) shiftOut(DataPin, clockPin, bitOrder, bitmuster[i]);

Nicht zusammenfügen, sondern shiftOut viermal ausführen mit dem zugehörigen Bitmuster für jede Stelle.

...eine 4byte große Zahl habe, die ich mit dem shiftOut-Befehl übertragen kann

Du denkst evtl. an sowas:

byte timer_2sekunde;
byte timer_1sekunde;
byte timer_zehner;
byte timer_hundert;
// ... werden langsam hochgezählt 


digitalWrite(latchPin,LOW); 
shiftOut(dataPin, clockPin, LSBFIRST, timer_hundert); 
shiftOut(dataPin, clockPin, LSBFIRST, timer_zehner); 
shiftOut(dataPin, clockPin, LSBFIRST, timer_1sekunde); 
shiftOut(dataPin, clockPin, LSBFIRST, timer_2sekunde);
digitalWrite(latchPin,HIGH);

Aber, pylons Kommentar ganz zu Anfang:

Hängt natürlich noch davon ab, wie Du die 7-Segment-Anzeigen ansteuern willst, aber grundsätzlich ist das relativ einfach möglich.

... ist noch offen (für mich). Insbesondere denke ich, dass du keine 4 Stück Binär->7Segment Codierer-ICs oder so vorschalten willst, wenn du einen so schönen Arduino und Schieberegister hast.

Da gäbe es z.B. im Playground einiges zu 7Seg und Schieberegister zu finden. Und Lesen natürlich ... ;)

Mit den angenommenen 4 Schieberegistern ist das Codieren von 4 Zahlen 0 .. 9 in 32 bit Ausgabe für 4*7Segmente auch eine schöne Aufgabe ... sth77 hat es dir erstmal überlassen, wie bitmuster[0] bis [bitmuster[3] zu füllen sind...

Hallo,

die Stoppuhr läuft mittlerweile einwandfrei. Vielen Dank an die bisherigen Hilfestellungen. Ohne euch wäre ich noch nicht soweit. Ich muss sth77 zustimmen, ich habe viel gelernt bei dem Aufbau des Programms. Ich dachte eigentlich das hierfür ein großes Programm von Nöten wäre. Wie man sich irren kann ;).

Jetzt füge ich noch die Start/Stop/Reset-Bedingungen ein und dann wird es an die Schönheits-OP gehen. Schauen was ich so alles verbessern kann und welche Programmabschnitte ich verändern kann.

Nur so zum Nachdenken: woher weisst Du, daß Deine Stoppuhr einwandfrei läuft? Wenn Du 1/100s auflöst, und bis zu 100s messen willst, dann brauchst Du eine Zeitbasis die auf 100ppm genau ist. Ein Arduino mit Quarz schafft das, einer mit Resonator nicht. Der Uno hat im Gegensatz zu den älteren Modellen einen Resonator :(

einwandfrei ist, wenn längere Zeiten größere Werte anzeigen, wenn das Ganze mit einer anderen Stoppuhr übereinstimmt, also vernünftige Werte liefert. Wie genau werden denn die Lichtschranken positioniert ? Ob 34:56 "eigentlich" 34:55 oder 34:57 ist, sollte nicht so kritisch sein, dass der Arduino ungeeignet ist.

Viel größer ist der Fehler, der durch den Code

    if((millis() - prev) > 9)
      {
        prev = millis();

reinkommt.

Selbst das wird kaum einer merken ;)

Das habe ich mir schon halber gedacht - der Klassiker - Displayauflösung 10ms tatsächliche Genauigkeit hoffentlich 100ms. Nur die Analyse ist falsch, der Fehler durch einen Resonator ist größer als der durch den Code.

Einwandfrei ist bei mir wenn sich das Teil erwartungskonform verhält. Bei mir wäre das: maximal 1.5 LSB Abweichung vom angezeigten Wert. Das Übereinstimmen mit einer "anderen Stoppuhr" ist so eine Sache. Er nimmt vermutlich eine Handstoppuhr als Vergleich. Das ist die Arduinolösung selbstverständlich besser. Ich würde einen Frequenzzähler als Referenzstoppuhr nehmen.

Nur die Analyse ist falsch, der Fehler durch einen Resonator ist größer als der durch den Code.

Richtig.

Wer's noch nicht gemerkt hat: man sollte mir nicht alles glauben, aber schon bedenken, bitte sehr ;)

Den Code kann man leicht korrigieren.

Beim Vergleich meines Resonator-Arduinos (Original UNO-R3) mit einer Referenz-Frequenz ( 50 Hz-Netz ) habe ich beispielweise. 9986 millis / 10 sekunden, bei 23° Raumtemperatur und einer Versorgungsspannung von 5.3V via USB ( wenn mein Messgerät stimmt ) .

Das zu kompensieren erfordert allerdings einen anderen Ansatz

Ja, vor allem weil der Resonator abhängig von der Temperatur mal mehr mal weniger wegläuft.