Frage zum Timer

Hallo, Freunde, habe Verständnisproblem mit Timer. Mit folgendem Sketchauschnitt habe ich vor die Drehzahl eines DC Motors zu regeln. X-Werte sind Pulse, die die Lichtschranke liefert und zwar vor dem Timer und danach.

void setup() { ... Timer.initialize(500000); // Timer soll alle 500ms gestartet werden

void loop ()

{ Timer.start(); int x1=x; Timer.stop(); int x2=x; if ( x2-x1==0){ // Differenz=0=> Motorstop pwm=0; } if ( x2-x1==2){ pwm++ ; } // Differenz zu klen=> Motor soll schneller laufen

if ( x2-x1==5){ // Differenz zu groß=> Motor langsamer machen

pwm--;} }

Die Frage: Soll ich den Timerinterrupt einbauen, also die Funktion ( Timer.attachInterrupt() ) oder reicht Timer.start() und Timer.stop() aus? Außerdem will angeben wie lang der Timer laufen soll und nicht nur wie oft. Wie macht man das? Habe schon zwar einiges über Timer gelesen, aber ist noch nicht ganz angekommen. Ich meine gelesen zu haben, dass Timer nicht mit analogWrite() verwendet werden können. Freue mich über Tipps und wünsche allen guten Rutsch.

Ich meine gelesen zu haben, dass Timer nicht mit analogWrite() verwendet werden können.

Das kommt darauf an auf welchen Pins du bist. Ein Timer macht immer 2-3 PWM Pins. Wenn man dann den entsprechenden Timer verwendet, gehen diese nicht mehr. Die anderen schon.

Siehe hier:
http://playground.arduino.cc/Main/TimerPWMCheatsheet

Mit attachInterrupt() kannst du eine Funktion alle x ms aufrufen. Das ist glaube ich nicht was du hier willst.

Timer.start();
int x1=x;
Timer.stop();

Damit zählst du wie lange die Zuweisung braucht :slight_smile:

Aber das brauchst du alles gar nicht. Auf dem Arduino läuft immer im Hintergrund Timer0. Den Wert erhält man mit millis():
http://arduino.cc/en/Reference/Millis
Oder bei einer Lichtschranke willst du vielleicht eher micros():
http://arduino.cc/en/Reference/Micros

Wenn man das zweimal macht und die Differenz bildet hat man die Zeit in ms (oder µs mit micros()). Wenn du die Differenz zwischen zwei Ereignissen messen willst geht das:

unsigned long time1, time2;
boolean triggered = false;

void loop()
{
      if(Bedingung1 && !triggered)
      {
           time1 = millis();
           triggered = true;
      }

     if(Bedingung2 && triggered)
     { 
         time2 = millis();
         triggered = false;
     }

Bedingung1/2 ist dabei nur Pseudo Code. Statt dessen musst du dein Ereignis abfragen

Wenn es das nicht ist, beschreibe deine Aufgabenstellung mal genauer in Worten :slight_smile:

Danke schon mal für die Antwort. So wie ich das verstehe gibt millis () die Zeit, die seit dem Start des Programms verstrichen wurde. Für die initialisierung und setup() wird doch Einiges auch an millisekunden benötigt oder? Das kann doch zu Ungenauigkeiten führen in der Bedienung 1 und 2.

Genaue Aufgabenstellung: Bin an einem Projekt dran. Das Hauptprogramm soll einen Temperaursensor, eine SD-Karte, einen Motor und eine LCD Display steuern. Falls, ein Problem auftaucht ( SD-Karte nicht schreibt, Sensor liefert nicht erlaubte Werte, Motor sich nicht dreht usw.) soll das Programm gestoppt oder gegebenfalls gar nicht gestartet werden. Auf die SD-Karte sollen Drehzahl des Motors, Zyklenzahl und Temperatur geschrieben werden.

Bin erstmal bei Motorsteuerung. Das Ziel ist wie folgt: Der Motor soll sich konstant mit 400 U/min drehen. Die Drehzahl soll geregelt werden. Wenn die Lichtschranke keine Pulse mehr zählt, soll das Programm beendet (gestoppt) werden. Wie gesagt dies wollte ich wie oben realisieren. Habe eine Funktion attachInterrupt (0, count, RISING), void count macht x++; setze dafür eine Scheibe mit fehlendem Segment ein. Um die Drehzahl zu regeln habe ich vor die Anzahl der Pulse pro bestimmte Zeit zu vergleichen, deswegen der Code aus dem ersten Post. Wie schon gesagt wollte dafür einen Timer ( so gesehen eine Stoppuhr) nehmen, habe nur Problem wie man den realisiert. Sorry für so viel Text, aber vielleicht ist die Aufgabenstellung damit klarer geworden.

So wie ich das verstehe gibt millis () die Zeit, die seit dem Start des Programms verstrichen wurde. Für die initialisierung und setup() wird doch Einiges auch an millisekunden benötigt oder? Das kann doch zu Ungenauigkeiten führen in der Bedienung 1 und 2.

Das einzige was an millis() interessiert, ist die Differenz zu einem vorangegangenen Wert.

Ob setup() meher oder weniger als 1 ms braucht, sollte egal sein. Du solltest auch in loop damit rechnen, dass a) zwei loop - Durchläufe den gleichen millis() Wert haben *) b) nicht jeder millis() Wert erwischt wird.

400 Upm sind übigens 150 ms / Umdrehung ... Interrupt-Behandlung kann das Ganze bequemer machen, erforderlich ist es wohl nicht. Bei jedem Interrupt kannst du feststellen, ob seit dem letzten Mal mehr oder weniger als deine Soll-Zeit (150 ms) verstrichen ist und entsprechend evtl. den PWM Wert für deinen Motor ändern.


*) loop() sollte in der Regel nur erkennen, dass nichts zu tun ist. Das dauert weit weniger als 1 ms.

Was meinst du mit b)? Interrupt kann aber nur eine Sache machen? Milisekunden und Zyklenzahl gleichzeitig zählen wird nicht funktionieren? Also beispielsweise : void count () { x++; y=millis(); }

In deiner ISR brauchst du millis() glaube ich nicht

Wie man mit millis() Code alle x ms aufruft steht hier:

Du kannst da immer schön deinen Interrupt laufen lassen und fragst den Wert alle x ms in der loop() ab, vergleichst, setzt in wieder zurück, etc. Dabei vielleicht mit cli() kurz die Interrupts sperren und mit sei() am Ende wieder freigeben, damit dass nicht unterbrochen wird.

Denke auch daran dass du deine Zählvariable als volatile deklarieren musst

Wenn du jetzt deine loop lange braucht oder keine konstante Zeit hat, kann es vielleicht sein, dass das zu ungenau ist. Dann kann man einen Timer Interrupt nehmen. Damit lagst du schon richtig. Das steht mal hier als Beispiel (sollte mit deiner Lib (für Timer1 ?) analog gehen:
http://playground.arduino.cc/Main/MsTimer2

Du würdest den Timer dann ständig laufen lassen. Kein stopp(), und mit timer.attachInterrInterrupt() alle x ms eine Funktion aufrufen die die Zählvariable ausliest.

Was meinst du mit b)?

Dass ein loop Durchlauf auch länger als eine ms dauern kann, du also nie sicher sein kannst, dass so was wie

if ( millis() == Start + Dauer) { }

jemals erwischt wird.

const unsigned long _1sec = 1000;
void loop()
{
  static unsigend long Start;
  unsigned long Dauer = millis() - Start;
  if ( Dauer >= _1sec ) { Start += _1sec; SekundenFunktion(); }
}

Eine Interrupt-Routine könnte sogar noch ein bisschen mehr machen als dein Beispiel ;) (z.B. die ganze "Regelung" (incl. analogWrite !) ist kein Problem, wenn die Interrupte nur alle paar msec kommen. Was gar nicht geht ist Serial.print, delay, pulseIn und solche Sachen)