Arduino Nano Timer1 capture und overflow interrupt

OP #7566571
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.

OP #7566814
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
 }
Beitrag #7566837 wurde von einem Moderator gelöscht.
OP #7566845
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
  3. Capture routine 39 ich capture trotzdem
  4. Capture routine 12176 49837 Timer setzen 27 ich capture trotzdem
  5. Capture routine 12178 49837 Timer setzen 27 ich capture trotzdem
  6. Capture routine 39 ich capture trotzdem
  7. Capture routine 12179 49837 Timer setzen 27 ich capture trotzdem
  8. Capture routine 39 ich capture trotzdem
  9. 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

OP #7566868
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.

OP #7566873
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.

#7566936
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.

(Firma: matzetronics) #7567032
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.

#7567067
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 ....

#7567087
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.

OP #7567459
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
}

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren