Forum: Mikrocontroller und Digitale Elektronik Arduino Nano Timer1 capture und overflow interrupt


von Daniel E. (everyday_fun69)


Lesenswert?

Guten Morgen und einen schönen Feiertag.

Ich finde irgendwie verschiedene Schreibweisen, wie der Capture und 
Overflow Interrupt vom Timer1 des Nano geschrieben wird. Vom PIC her bin 
ich das bitweise setzen anders gewöhnt. Ich möchte diese gern auch am 
Arduino Bitweise setzen oder deaktivieren. Laut Datenblatt wären diese 
Bits wie folgt:

TCCR1B       ICES1: Input Capture Edge Select
TIMSK1       ICIE1: Timer/Counter1, Input Capture Interrupt Enable
             TOIE1: Timer/Counter1, Overflow Interrupt Enable

Sind diese Schreibweisen so korrekt ?

TCCR1B &= ~(1<<ICES1) -> Bit setzen für fallende flanke
TCCR1B |= (1<<ICES1)  -> Bit setzen für steigende flanke

TIMSK1 &= ~(1<<TOIE1) -> Bit setzen für Deaktivierung overflow Interrupt
TIMSK1 &= ~(1<<ICIE1) -> Bit setzen für Deaktivierung Capture Interrupt

TIMSK1 |= (1<<TOIE1)  -> Bit setzen für Aktivierung overflow Interrupt
TIMSK1 |= (1<<ICIE1)  -> Bit setzen für Aktivierung Capture Interrupt

Vielen Dank vorab.

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Daniel E. schrieb:
> Arduino

Dann setzt man am besten
TCCR1A und TCCR1B beide auf 0, da Arduino die Timer für PWM vorbereitet

von Daniel E. (everyday_fun69)


Lesenswert?

> Dann setzt man am besten
> TCCR1A und TCCR1B beide auf 0, da Arduino die Timer für PWM vorbereitet

Jup so...

  TCCR1A = 0; // Reset Timer 1 Control Register A
  TCCR1B = 0; // Reset Timer 1 Control Register B

leider ist meine Frage damit nicht beantwortet...

Danke.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Daniel E. schrieb:
> TIMSK1 &= ~(1<<TOIE1) -> Bit setzen für Deaktivierung overflow Interrupt
> TIMSK1 &= ~(1<<ICIE1) -> Bit setzen für Deaktivierung Capture Interrupt

Du setzt damit allerdings kein Bit, sondern löscht es. Der Kommentar 
stimmt also nicht, die Schreibweise zum Löschen ist aber richtig.
Auch die anderen Zeilen sehen richtig aus.

: Bearbeitet durch User
von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Daniel E. schrieb:
> leider ist meine Frage damit nicht beantwortet...

Deine Schreibweisen sind allesamt unnötig/unsinnig in der Situation

von Wastl (hartundweichware)


Lesenswert?

Daniel E. schrieb:
> Sind diese Schreibweisen so korrekt ?

Die Frage riecht nach: "Ich habe keine Lust mich mit
den Operatoren der Sprache C bekannt zu machen bzw.
die Bedeutung dieser Operatoren zu lernen".

von Daniel E. (everyday_fun69)


Lesenswert?

Arduino F. schrieb:
> Daniel E. schrieb:
>> leider ist meine Frage damit nicht beantwortet...
>
> Deine Schreibweisen sind allesamt unnötig/unsinnig in der Situation

Das mag evtl. so erscheinen, ich wollte damit sichergehen, dass der Code 
wenigstens richtig ist, bevor ich ein Problem hier schildere/ draus 
mache.

Ich komme später drauf zurück.

Danke.

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Daniel E. schrieb:
> Das mag evtl. so erscheinen,
Deine Erscheinungen.....

Daniel E. schrieb:
> ich wollte damit sichergehen, dass der Code
> wenigstens richtig ist, bevor ich ein Problem hier schildere/ draus
> mache.
Alles klar, keine Fragen.

von Daniel E. (everyday_fun69)


Lesenswert?

Ich kommen malm zum eigentlichen Problem mit dem ich kämpfe.

Ich habe eine ISR mit Timer 2, welche aller 1 ms eine Zahl erhöht und 
bei 200 ms dann den Capture freigeben soll.
1
ISR(TIMER2_COMPA_vect)                // 1 khz (1 ms Timer)
2
{
3
 
4
  Display_counter ++;
5
6
  if(Display_counter >= 200)        // aller 200 ms Display refresh
7
    {
8
    DisplayUpdate = 1;
9
    Display_counter = 0;
10
11
    if(Wait_RPM_Trigger == 0)
12
      {
13
      Serial.println(TCNT1);
14
      TIMSK1 = (1 << TOIE1);                              // Enable Timer1 overflow interrupt
15
      TIMSK1 |= (1 << ICIE1);                             // Enable Timer1 Input Capture Interrupt
16
      TCNT1 = 0;                                          // Schreibe Timer mit Wert 0
17
      First_Capture = 0;
18
      Overflow = 0;
19
      Serial.println("Timer setzen");
20
      Serial.println(TCNT1);
21
      Wait_RPM_Trigger = 1;
22
      }
23
 }

von Norbert (der_norbert)


Lesenswert?

Daniel E. schrieb:
> Ich kommen malm zum eigentlichen Problem mit dem ich kämpfe.

Mehrere serielle Ausgaben inklusive Konvertierung innerhalb einer ISR.
Du kämpfst noch mit ganz anderen Problemen. ;-)

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Daniel E. schrieb:
> Serial.println(TCNT1);

In einer ISR...
Du hast mehr Probleme, als du glaubst.

Beitrag #7566837 wurde vom Autor gelöscht.
von Daniel E. (everyday_fun69)


Lesenswert?

Ich kommen malm zum eigentlichen Problem mit dem ich kämpfe.

Ich habe eine ISR mit Timer 2, welche aller 1 ms eine Zahl erhöht und 
bei 200 ms dann den Capture freigeben soll.
1
ISR(TIMER2_COMPA_vect)                // 1 khz (1 ms Timer)
2
{
3
 
4
  Display_counter ++;
5
6
  if(Display_counter >= 200)        // aller 200 ms Display refresh
7
    {
8
    DisplayUpdate = 1;
9
    Display_counter = 0;
10
11
    if(Wait_RPM_Trigger == 0)
12
      {
13
      Serial.println(TCNT1);
14
      TIMSK1 = (1 << TOIE1);                              // Enable Timer1 overflow interrupt
15
      TIMSK1 |= (1 << ICIE1);                             // Enable Timer1 Input Capture Interrupt
16
      TCNT1 = 0;                                          // Schreibe Timer mit Wert 0
17
      First_Capture = 0;
18
      Overflow = 0;
19
      Serial.println("Timer setzen");
20
      Serial.println(TCNT1);
21
      Wait_RPM_Trigger = 1;
22
      }
23
 }

in der ISR vom Capture steht
1
 ISR(TIMER1_CAPT_vect)                //Capture Interrupt Drehzahlmessung
2
{
3
Serial.println("ich capture trotzdem");
4
if (First_Capture == 1)
5
    {
6
    ZeitT2 = ICR1; 
7
    NewRPMValue = 1;
8
    First_Capture = 3;                                //Modus gib es nicht
9
    Serial.println("2. Capture routine");
10
    Serial.println(TCNT1);
11
    }
12
13
  if (First_Capture == 0)
14
    {
15
    TCNT1 = 0;                      // Schreibe Timer mit Wert 
16
    Serial.println("1. Capture routine"); 
17
    Serial.println(TCNT1);
18
    First_Capture = 1;                  //Capture 2nd value
19
    }
20
}

das sieht dann wie folgt aus auf dem Serial monitor:

37
ich capture trotzdem
2. Capture routine
12537
ich capture trotzdem
ich capture trotzdem
43979
Timer setzen
26
ich capture trotzdem
1. Capture routine
38
ich capture trotzdem
2. Capture routine
12538
ich capture trotzdem
ich capture trotzdem
43978
Timer setzen
26

Das zweite Capture Ergebnis ist immer 12538 +/-1. Füge ich
in die
1
 
2
if (First_Capture == 1)
3
{
4
TIMSK1 &= ~(1<<ICIE1); // -> Bit setzen für Deaktivierung Capture Interrupt
5
}

zusätzlich ein, weil ich den Capture deaktivieren will kommt bei 
gleicher Frequenz am Eingang folgendes raus:

ich capture trotzdem
1. Capture routine
39
ich capture trotzdem
2. Capture routine
12175
49837
Timer setzen
27
ich capture trotzdem
1. Capture routine
39
ich capture trotzdem
2. Capture routine
12176
49837
Timer setzen
27
ich capture trotzdem
2. Capture routine
12178
49837
Timer setzen
27
ich capture trotzdem
1. Capture routine
39
ich capture trotzdem
2. Capture routine
12179
49837
Timer setzen
27
ich capture trotzdem
1. Capture routine
39
ich capture trotzdem
2. Capture routine
12181

Man sieht, dass alle weiteren Capture nach dem 2ten gesperrt sind, 
soweit so gut. Leider ist der zweite Capture Wert völlig daneben und 
wird sogar mit jeder Routine hochgezählt, bei gleicher 
Eingangsfrequenz..

Was will ich eigentlich? Ich möchte aller 200 ms eine Freigabe der 
Capture und Overflow ISR im Timer 2 ISR machen. Gibt es zwei Flanken, 
werden beide ISR (Capture+ Overflow) gesperrt und es wird auf die 
nächste Freigabe nach 200 ms gewartet. Gibt es nur einen Impuls oder 
garkeinen, dann läuft der Timer über und im Overflow soll dann der 
capture und overflow deaktiviert werden, bis er zur nächsten Freigabe in 
der Timer 2 ISR wieder aktiviert wird. Alles in allem läuft das mit dem 
deaktivieren und aktivieren der zuvor angefragten Befehle bei mir 
überhaupt nicht und ich weiß leider nicht warum..

Danke für den Support

von Mi N. (msx)


Lesenswert?

Norbert schrieb:
> Du kämpfst noch mit ganz anderen Problemen. ;-)

Wie man hier schon sehen konnte: 
Beitrag "Arduino Auslastung Tacho und Drehzahl messen"
Er versteht weder die gestellten Rückfragen noch die Antworten dazu.

von Daniel E. (everyday_fun69)


Lesenswert?

Naja, ich weis selber das die ISR damit sehr lange abgearbeitet wird und 
eigentlich sehr kurz gehalten werden soll. Um das Problem einzugrenzen, 
bietet sich halt der serial Port an, um zu sehen was wo los ist…

Meint ihr etwa, wenn ich das serial rausnehme, dass es dann geht, so wie 
ich die Freigaben und Blockierungen machen will ?

Gegenfrage, warum funktioniert es ohne

TIMSK1 &= ~(1<<ICIE1); // -> Bit setzen für Deaktivierung Capture 
Interrupt

und mit dem Code wird Blödsinn, falsche Werte angezeigt. Wird eigentlich 
ja nur der ISR gesperrt.

Danke.

von Daniel E. (everyday_fun69)


Lesenswert?

Mi N. schrieb:
> Norbert schrieb:
>> Du kämpfst noch mit ganz anderen Problemen. ;-)
>
> Wie man hier schon sehen konnte:
> Beitrag "Arduino Auslastung Tacho und Drehzahl messen"
> Er versteht weder die gestellten Rückfragen noch die Antworten dazu.

Das 15 V Signal geht auf einen Komparator Eingang und der bereitet es 
für den uc auf, der dann ein 5 V Signal bekommt. Ist mir schon klar, 
dass der uC keine 15 V verträgt.

von Axel S. (a-za-z0-9)


Lesenswert?

Daniel E. schrieb:
> Naja, ich weis selber das die ISR damit sehr lange abgearbeitet wird und
> eigentlich sehr kurz gehalten werden soll.

Das stimmt so nicht. Richtig ist, daß alle Interrupts gesperrt sind, 
während die ISR abgearbeitet wird. Die ISR muß also fertig sein, bevor 
der nächste Interrupt kommt. Wie lange du dazu Zeit hast, hängt von der 
Konfiguration deines uC ab.

von Daniel E. (everyday_fun69)


Lesenswert?

Ja, ist klar, dass der Interrupt erst abgearbeitet wird. Passiert 
nebenbei noch einer, wird ins Hauptprogramm gesprungen, nur ein Befehl 
abgearbeitet und dann in den nächsten ISR gesprungen nach deren 
Vektoradresse, nicht deren Reihenfolge

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Daniel E. schrieb:
> Passiert
> nebenbei noch einer, wird ins Hauptprogramm gesprungen

Nein.

von Oliver S. (oliverso)


Lesenswert?

Arduino F. schrieb:
> Daniel E. schrieb:
>> Passiert
>> nebenbei noch einer, wird ins Hauptprogramm gesprungen
>
> Nein.

Na ja, man könnte schon erahnen, das damit „Passiert nebenbei noch 
einer, wird nach Ende der ISR ins Hauptprogramm gesprungen…“ gemeint 
war.

Oliver

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Oliver S. schrieb:
> gemeint war.

Nein!
Serial basiert auf Interrupts.
Das ist nicht wirklich schlimm.
Aber in ISR sind Interrupts erstmal verboten.
Damit ist die Blockade "vorprogrammiert" wenn man in ISR Serial nutzt.
Und das ist schlimm.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Das normale Verhalten beim Abarbeiten einer ISR ist, das global erstmal 
alle IRQs per I-Flag gesperrt werden. Wenn man weiss, was man tut, kann 
man die ISR als NO_BLOCK deklarieren, damit das nicht passiert.
Aber serielle Ausgaben haben in jeglicher ISR nichts zu suchen. Man kann 
doch in der Hauptschleife ausgeben.

von Daniel E. (everyday_fun69)


Lesenswert?

Schade, dass hier am Problem, einer Erklärung oder den möglichen 
Ursachen vorbei diskutiert wird …

von Mario P. (mario_71950c)


Lesenswert?

Daniel E. schrieb:
> Schade, dass hier am Problem, einer Erklärung oder den möglichen
> Ursachen vorbei diskutiert wird …
1. Deine Erklärungen sind für Außenstehende nicht/kaum/nur mit extrem 
hohem Zeitaufwand nachvollziehbar (das tut sich keiner an)
2. Kommentare in Deinem Code verwirren eher, als daß sie nutzbare 
Informationen enthalten ("Bit setzen für deaktivieren" obwohl in der 
Realität das Bit gelöscht wird); auch das tut sich keiner über längere 
Zeit an; ein entsprechender Hinweis kam sehr zeitig im Thread
3. in Deinem Code sind jede Menge nicht 
kontrollierbare/erkennbare/nachvollziehbare Seiteneffekte (Variablen 
werden gesetzt mit nicht erkennbaren Ausirkungen, nutzen der in ISRs 
hochgradig problematischen println-Funktion innerhalb einer ISR, ...); 
Hierzu auch sehr früh im Thread der entsprechende Hinweis.
Zusammengefaßt alles Dinge, durch die potentielle Leser dieses Threads 
von ihrem Willen zu Helfen abschreckt werden.


Daniel E. schrieb:
> Gegenfrage, warum funktioniert es ohne
>
> TIMSK1 &= ~(1<<ICIE1); // -> Bit setzen für Deaktivierung Capture
> Interrupt
>
> ... Wird eigentlich ja nur der ISR gesperrt.
Es wird nicht nur einfach der Interrupt gesperrt. Ab diesem Zeitpunkt 
wird auch die ISR nicht mehr aufgerufen und sämtliche mit dieser ISR 
verbundenen Seiteneffekte (setzen von Variablen, reagieren auf diese 
Variablen, verändern dieser und anderer Werte in Deinem Programm, Aufruf 
weiterer Funktionen mit weiteren Auswirkungen auf den Programmablauf 
usw.) treten nicht oder anders auf.
Dein gesamter Programmablauf ändert sich.

ich bin damit auch raus ....

von Wastl (hartundweichware)


Lesenswert?

Daniel E. schrieb:
> Schade, dass hier am Problem, einer Erklärung oder den möglichen
> Ursachen vorbei diskutiert wird

Beratungsresistenz ist eine Zier, doch weiter kommt man ohne ihr.

Sinnvoller wäre es, erst einmal zu erklären was du überhaupt
erreichen willst bevor du wild mit zwei Timern gleichzeitig
das Programmieren anfängst.

von Thomas F. (igel)


Lesenswert?

Daniel E. schrieb:
> Was will ich eigentlich? Ich möchte aller 200 ms eine Freigabe der
> Capture und Overflow ISR im Timer 2 ISR machen.

Warum ständig sperren und wieder freigeben? Ich halte dieses Konzept für 
eher untauglich.

Lass doch den Timer mit seinen Funktionen einfach ständig weiterlaufen 
und beachte ihn einfach nicht. Kostet doch keine Rechenzeit. Der 
Capture-INT schreibt im Hintergrund immer brav seine Werte in irgendeine 
Variable. Und wenn dann alle 200ms der Wert benötigt wird so holt man 
diesen einfach aus der Variable.
So mache ich das seit Jahren und funktioniert problemlos.

von Peter D. (peda)


Lesenswert?

Daniel E. schrieb:
> Ich habe eine ISR mit Timer 2, welche aller 1 ms eine Zahl erhöht

Rechne doch bitte erstmal nach, wieviel Zeichen Du innerhalb 1ms über 
die UART ausgeben kannst bei Deiner gewählten Baudrate.
Z.B bei 9600 Baud nichtmal eins.

von Daniel E. (everyday_fun69)


Lesenswert?

Hallo und die Runde und danke für das Feedback.

Ich habe den Ratschlag angenommen, ständig zu Capturen und in der 
Routine mir Variablen zu setzen, je nachdem wo ich gerade stehe.

Der Code läuft nun, kleiner 4 Hz gibt es den Overflow und es wird 0 RPM 
angezeigt und ab 240 UPM/ min bis 348 Hz = 20800 UPM/min keine Probleme.

Alle 200 ms wird eine neue Messung frei gegeben.

Wahrscheinlich muss ich meine Denkweise -lasse den µC nur das tun was 
WIRKLICH notwendig ist, ablegen lernen. Eigentlich muss es auch, wenn es 
richtig angestellt ist mit freigeben und sperren gehen, wenn alle 
Variablen richtig deklariert sind. Schade, dass ich nun nicht weiß, 
woran es gelegen hat.

Für die, die es interessiert stell ich den Codeteile mal hier ein. Wer 
noch Bemerkungen hat, gerne her damit.

Ansonsten vielen Dank für den Beistand.
1
void loop() {
2
3
//RPM Motor berechnen_________________________________________________________________________________//
4
5
if (Capture_State ==3 )                                            // Messung gültig
6
  {
7
  RPM_Motor = (1000000/ ZeitT2)*15 ;
8
  Capture_State = 0;                                                //Freigabe neue Messung
9
  }
10
11
if (Overflow == 1 )
12
  {
13
  RPM_Motor = 0;
14
  }
15
16
 ISR(TIMER1_CAPT_vect)                //Capture Interrupt Drehzahlmessung
17
{
18
19
if (Capture_State == 2)
20
    {
21
    ZeitT2 = ICR1; 
22
    Capture_State = 3;                                //Habe Messwert
23
    }
24
25
  if (Capture_State == 1)
26
    {
27
    TCNT1 = 0;                                      // Schreibe Timer mit Wert 
28
    Capture_State = 2;                               //Capture 
29
    }
30
}
31
32
33
34
ISR(TIMER1_OVF_vect)                        // overflow
35
{
36
digitalWrite(LED, !digitalRead(LED));
37
if(Capture_State == 0 || Capture_State == 3)
38
  {
39
  Overflow = 0;
40
  }
41
  else
42
  {
43
  Overflow = 1;
44
  }
45
46
}
47
48
49
50
51
52
ISR(TIMER2_COMPA_vect)                // 1 khz (1 ms Timer)
53
{
54
 
55
  Display_counter ++;
56
  if(Display_counter >= 200)        // aller 200 ms Display refresh
57
    {
58
    DisplayUpdate = 1;
59
    Display_counter = 0;
60
61
    if(Capture_State == 0)
62
      {
63
      TCNT1 = 0;                                          // Schreibe Timer mit Wert 0
64
      Overflow = 0;
65
      Capture_State = 1;                                  //Starte Messung
66
      }
67
    }
68
}

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.