Forum: Mikrocontroller und Digitale Elektronik Pulspause mit ATMega 8 messen


von Kai (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Leute,

ich will mit einem ATMega 8 die Länge einer Pulspause messen.
Mein Signal ist ein Rechtecksignal mit variabler Frequenz und variablem 
Tastverhältnis, von diesem Signal möchte ich die Aus-Zeit messen.

Ich habe mir schon etliche Beiträge zu diesem Thema durchgelesen, nur 
jetzt komme ich nicht mehr weiter, ich mache wahrscheinlich einen 
Denkfehler.

Ich gehe jetzt so vor, dass ich den ICP-Pin des Controllers nehme dort 
erst bei fallender Flanke einen Interrupt auslöse, in der 
Interruptschleife dann auf steigende Flanke umschalte und dann wiederum 
auf die positive Flanke warte.

Die beiden Timerstände zieh ich dann von einander ab und hab die 
Differenzzeit, das mache ich aus dem Grund, da ich ja den Anfangsstand 
des Timers nicht kenne wenn ich nur auf die steigende Flanke triggere.

Hinzu kommt, dass ich einen kleinen Überschwinger von maximal etwa 60ms 
nach jeder positiven Flanke habe, jetzt hab ich den Verdacht, dass hier 
schon die fallende Flanke erkannt wird, lange bevor sie wirklich kommt.

Hier der relevante Code:
1
//Timer 1 initalisieren  
2
3
  TCCR1B |= /*(1 << ICES1) | */(1 << CS11) | (1 << ICNC1);    //Input Capture auf Positive Flanke / Prescaler = 8 -> Timerfrequenz = 1MHz / Input Noise-Canceler An
4
  TIMSK |= (1 << TICIE1) | (1 << TOIE1);    //Input Capture Interrupt und Timer Overflow Interrupt aktivieren
5
6
//Pulspause berechnen
7
8
unsigned long get_timer()
9
{
10
  timer_value = valueB - valueA + (overflow * 65536);
11
  return timer_value;
12
}
13
14
15
ISR(TIMER1_CAPT_vect)
16
{
17
18
19
  if(run)
20
  {
21
  
22
    valueA  = ICR1;  // Inhalt vom Input Capture Register in Value A laden
23
    run = 0;
24
    overflow = 0;  // Overflow zurücksetzen
25
    TCNT1 = 0;   // Timerstand auf 0 setzen
26
    TCCR1B |= (1 << ICES1);  // Auf steigende Flanke triggern
27
    TIFR |= ( 1 << ICF1 );  //Input Capture Interrupt Flag löschen
28
29
  }
30
31
  else if (run == 0)
32
  {
33
34
    valueB = ICR1;  // Inhalt vom Input Capture Register in Value B laden
35
    run = 1;
36
    TCCR1B &= ~(1 << ICES1);  // Auf negative Flanke triggern
37
    TIFR |= ( 1 << ICF1 );  // Input Capture Interrupt Flag löschen
38
    overflow = 0;  //Overflow zurücksetzen
39
    
40
  }
41
42
}

Kann das überhaupt so funktionieren?

Die nächste Frage wäre, wie bekomme ich es hin, dass der Interrupt für 
die fallende Flanke für 60ms nach der steigenden Flanke unterdrückt 
wird? Ich habe es schon über Timer 2 probiert, aber das funktioniert 
auch nicht wirklich.

Ich hoffe Jemand kann mir weiterhelfen.

Danke!

Gruß, Kai

von Helfer (Gast)


Lesenswert?

1) Die Variablen in der ISR und im nicht sichtbaren Anwendungscode 
benutzten valueA, valueB, overflow und möglicherweise sollten volatile 
definiert sein. Sind sie das?

2) Toggele doch mal in der ISR(TIMER1_CAPT_vect) einen Pin am µC und 
beobachte das am Oszi. Dann siehst du wie der µC bzw. dein Programm das 
Eingangssignal erkennt.

von Helfer (Gast)


Lesenswert?

> möglicherweise
möglicherweise run

von Helfer (Gast)


Lesenswert?

>    TIFR |= ( 1 << ICF1 );  // Input Capture Interrupt Flag löschen
          ^

So nicht! Das löscht auch andere Flags in TIFR.

So ja:
     TIFR = ( 1 << ICF1 );  // Input Capture Interrupt Flag löschen

von NopNop (Gast)


Lesenswert?

Wieso nicht ein Timer?
Starten bei negativer Flanke,Stoppen bei positiver Flanke.
Starten und Stoppen im gleichen Interrupt.

Dann weist Du direkt die Low-Time und kannst über die bekannte Frequenz 
das Pwm-Verhältnis ausrechnen.

Gruß

von NopNop (Gast)


Lesenswert?

Helfer schrieb:
>>    TIFR |= ( 1 << ICF1 );  // Input Capture Interrupt Flag löschen
>           ^
>
> So nicht! Das löscht auch andere Flags in TIFR.
>
> So ja:
>      TIFR = ( 1 << ICF1 );  // Input Capture Interrupt Flag löschen

Gerade so ist es falsch.

von NopNop (Gast)


Lesenswert?

Wenn dann TIFR&= ~(1<< ICF1)

von Helfer (Gast)


Lesenswert?

Atmega8 Datenblatt Timer/Counter Interrupt Flag Register – TIFR

ICF1 is automatically cleared when the Input Capture Interrupt Vector is 
executed. Alternatively, ICF1 can be cleared by writing a logic one to 
its bit location.

TOV1 is automatically cleared when the Timer/Counter1 Overflow Interrupt 
Vector is executed. Alternatively, TOV1 can be cleared by writing a 
logic one to its bit location.

Angenommen die Hardware setzt in TIFR die Bits TOV1 und ICF1 und ICP-Irq 
kommt zuerst. Verodert man TIFR dann mit Bit ICF1 (Schreiben von 1 auf 
ICF1 = Löschen), verodert man gleichzeitig das bereits vorhandene 1 Bit 
TOV1 auf Bitposition TOV1, d.h. man hat beim Verodern ungewollt TOV1 
gelöscht. Eine Zeitmessung mit Overflow ist damit nicht sinnvoll 
möglich.

Das steht aber auch im Tutorial als typ. Fallstrick bei den AVR 
Interrupts.

von Kai (Gast)


Lesenswert?

Danke für eure Antworten,

die entsprechenden Variablen sind alle volatile.

Auf die Idee den einen Pin togglen zu lassen bin ich noch gar nicht 
gekommen, das werde ich mal ausprobieren.

@NopNop

Kann ich denn den Timer 1 so einfach starten und stoppen in der IC-ISR?
Der Input Capture gehört ja quasi zum Timer 1.

Wenn das so funktioniert dann wäre meine Idee, erst auf die fallende 
Flanke zu triggern und dann auf die steigende, also diese Umschaltung in 
der ISR selbst zu machen, prinzipiell in Ordnung oder?

Ich werde erstmal austesten ob das Signal überhaupt richtig erkannt 
wird.

von Peter D. (peda)


Lesenswert?

Kai schrieb:
> Kann ich denn den Timer 1 so einfach starten und stoppen in der IC-ISR?

Jain, Du holst Dir damit nen Jitter rein durch die unbekannte 
Interruptlatenz und den Startcode des Interrupthandlers.
Der Vorteil des Input Capture (zyklusgenau messen) wird damit 
vernichtet.

Solange keine 2 Überläufe stattfinden, ist die Differenz zweier 
Capturewerte immer richtig.


Peter

von Kai (Gast)


Lesenswert?

Ich hab es jetzt getestet, die Interrupts werden richtig ausgelöst.
Ich starte nun in der ersten Interruptschleife den Timer 1 und stoppe 
ihn in der 2. wieder,
das funktioniert nun auch super, mit ausreichender Genauigkeit.

Danke für Eure Hilfe!

Kai

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.