Forum: Compiler & IDEs Frequenz messen über ICP Atmega8


von Sandro W. (swissm)


Lesenswert?

Moin,
vorweg ich habe die Suchfunktion verwendet aber nichts konkretes zu 
meine Problem Gefunden.

Ich möchte ein Signal über den ICP-Pin erfassen, welches zwischen 13- 60 
Hz variiert.

Ich habe versucht das mit dem Input Capturing zu verstehen, werde da 
aber nicht so richtig schlau raus.

Wollte wie folgt vorgehen:

Timer 1, jede ms aufrufen, diesen also im Hintergrund laufen lassen.

Ich teile hierzu den CLk von 16Mhz auf 16/64Mhz.
Also 4us.

Nur wie bekomm ich den Timer jetzt auf 1ms?


Nun brauch ich aber einen Zweiten Interrupt den Output Compare, der den 
Zählstand sichert, wenn eine Flanke auftritt an dem PIN oder?

Dieser wird dann aufgerufen, wenn eine Flanke an dem ICP-PIN erfolgt.
Das problem hierbei ist ich weiß nicht wie der ISR Interrupt Vector in C 
heißt. Wo kann man das denn nachgucken, im Datenblatt steht dies ja so 
direkt nicht drin.

Code sieht unvollständig bisher so aus:
1
ISR(TIMER1_CAPT_vect)               // Interrupt-Serviceroutine Timer 0
2
{ 
3
    millisekunde++; 
4
}
5
ISR( //Output Compare)
6
{
7
    //Letzter Zählerstand in vorheriges Feld
8
    zaehlerstand[0][0]=zaehlerstand[1][0];
9
    zaehlerstand[0][1]=zaehlerstand[1][1];
10
    
11
    //Aktueller Zählerstand sichern
12
    zaehlerstand[1][0]=ICR1L;
13
    zaehlerstand[1][1]=ICR1H;
14
    
15
    //Akt Zählerstand - Letzter Zählerstand Abstand in ms
16
    frequenz=zaehlerstand[1][0]+256*zaehlerstand[1][1];
17
    frequenz-=zaehlerstand[0][0]+256*zaehlerstand[0][1];
18
}
19
20
main
21
{
22
  TCCR1B |= (1<<ICES1); // pos Flanke
23
  TCCR1B |= (1<<CS10)|(1<<CS11); //clk/64
24
  TIMSK  |= (1<<TICIE1);    //Input Capture enable
25
  SREG |= 0x80;  // SREG : Globales "Interrupt enable"*/
26
27
  for(;;)
28
  {
29
    asm volatile ("nop");  
30
  }
31
32
}

Ich hoffe ich hab nicht zu dumme Fragen gestellt :(

von MWS (Gast)


Lesenswert?

Du hast die Logik hinter Input Capture nicht verstanden.

Du lässt Zähler1 laufen, wenn dann ein Signal am Input Capture Pin ICP1 
eintrifft, sichert der Atmel den Zählerstand von TCNT1 nach ICR1, und 
löst einen Capture Interrupt aus wenn der freigegeben ist.

Im Capture Interrupt zieht man den vorherigen Zählerstand, den man sich 
in einer Variablen merkt, vom neuen Wert des ICR1 ab und erhält so die 
Periodendauer in Anzahl der Zyklen des Zähler1. Das versuchst Du 
bereits, nur gehört das eben in den TIMER1_CAPT_vect rein. Bei 13 - 60 
Hz ergeben sich dann Werte ICR1_alt - ICR1 von 19230 - 4166

Man könnte auch in der Capture ISR den Zähler auf 0 setzen und erhält so 
ohne Subtraktion im ICR1 direkt die Periodendauer. Allerdings entsteht 
dann durch den während der Befehlsausführung weiterlaufenden Zähler ein 
Fehler, der evtl. aber nicht stört.

Die weitere Auswertung der Frequenz würde man dagegen in der Mainloop 
machen, durch ein Flag gesichert um ein Überschreiben des Wertes während 
der Berechnung zu verhindern.

Und Output Compare hat etwas mit PWM zu tun, das ICR1 Register kann auch 
dafür verwendet werden, aber das scheint mir nicht das zu sein was Du 
willst. Außer Du möchtest aus der Periodendauer gleich wieder eine davon 
abhängige PWM machen.

Die Namen aller Interruptvektoren stehen übrigens in iom8.h, die Du 
sicherlich einbindest.

von Rolf Magnus (Gast)


Lesenswert?

> Ich möchte ein Signal über den ICP-Pin erfassen, welches zwischen
> 13- 60 Hz variiert.
>
> Ich habe versucht das mit dem Input Capturing zu verstehen, werde
> da aber nicht so richtig schlau raus.

Das ist eigentlich ganz einfach. Wenn ein Input-Capture-Ereignis 
eintritt, wird der aktuelle Zählerwert automatisch in einem Register 
zwischengespeichert. Du kannst dir dann auch einen Interrupt generieren 
lassen, mit dem du diesen Wert abholst.

Wollte wie folgt vorgehen:

> Timer 1, jede ms aufrufen, diesen also im Hintergrund laufen lassen.

Das hat dann aber nicht mehr viel mit Input Capture zu tun.

> Ich teile hierzu den CLk von 16Mhz auf 16/64Mhz.
> Also 4us.
> Nur wie bekomm ich den Timer jetzt auf 1ms?

Du schaltest ihn in den CTC-Modus und schreibst ins dafür verwendete 
Output-Compare-Register einen Wert von 250. Dann bekommt der Timer alle 
Millisekunde einen Reset, und der  Output-Compare-Interrupt wird dabei 
ausgelöst.

> Nun brauch ich aber einen Zweiten Interrupt den Output Compare,
> der den Zählstand sichert, wenn eine Flanke auftritt an dem PIN
> oder? Dieser wird dann aufgerufen, wenn eine Flanke an dem ICP-PIN
> erfolgt.

Der Output Compare hat nichts mit einer Flanke am Pin zu tun. Der wird 
aufgerufen, wenn der Zähler einen bestimmten Zählwert erreicht.

> Das problem hierbei ist ich weiß nicht wie der ISR Interrupt Vector in
> C heißt. Wo kann man das denn nachgucken, im Datenblatt steht
> dies ja so direkt nicht drin.

Das steht in der Doku von der avr-libc.

Deine Vorstellung von Input-Capture paßt aber noch nicht ganz. 
Prinzipiell kannst du deinen Timer einfach durchrennen lassen. In der 
Input-Capture-ISR liest du das ICR1-Register aus und sicherst es in 
einer Variablen. Wenn du die Differenz der Zähler-Werte zweier 
aufeinanderfolgener Flanken nimmst, kannst du daraus die Frequenz des 
Signals ermitteln. Wichtig ist dabei nur, daß zwischen zwei 
Input-Capture-Ereignissen nicht mehr als ein Zählerüberlauf vorkommen 
kann.

> Ich hoffe ich hab nicht zu dumme Fragen gestellt :(

Nein. Dumme Fragen stellen eigentlich fast ausschließlich diejenigen, 
die glauben, ihre Fragen seien höchst intelligent.

von Rolf Magnus (Gast)


Lesenswert?

> Man könnte auch in der Capture ISR den Zähler auf 0 setzen und
> erhält so ohne Subtraktion im ICR1 direkt die Periodendauer.
> Allerdings entsteht dann durch den während der Befehlsausführung
> weiterlaufenden Zähler ein Fehler, der evtl. aber nicht stört.

Wobei eigentlich der wirkliche Vorteil von Input Capture ist, daß man 
eben gerade diesen Fehler nicht bekommt. Sonst könnte man auch einen 
normalen Interrupt-Eingang nehmen und den aktuellen Zählerwert in der 
ISR auslesen.

von MWS (Gast)


Lesenswert?

> Sonst könnte man auch einen normalen Interrupt-Eingang nehmen und den
> aktuellen Zählerwert in der ISR auslesen.

Stimmt, könnte man, aber ich hab doch geschrieben daß bei dieser Lösung 
ein Fehler entsteht, was ist da jetzt nicht zu verstehen ?

Der Frequenzbereich umfasst 13-60 Hz, der entstehende Fehler ist 
verschwindend gering, rechnerisch ca. 0.004Hz.

Wenn man Einsprung in die ISR, das Pushen der Register und Setzen des 
Zählers mit 15 Zyklen annimmt, dann hat der Zähler bei Prescaler 64 in 
dieser Zeit noch nicht einmal weitergezählt, der Fehler ist also 
außerhalb der möglichen Zählerauflösung.

Bei dieser Lösung kann man auch noch eine Timer1 Overflow ISR aufsetzen, 
in der man ein Flag löscht, welches man vor Verlassen der Input Compare 
ISR gesetzt hat. Ist diese Flag beim erneuten Aufruf der Input Compare 
ISR immer noch gesetzt, dann ist der Zähler nicht übergelaufen und man 
hat eine gültige Messung.

Das macht den Code einfacher, warum sollte man das nicht nutzen, bzw. 
erwähnen ?

von Rolf Magnus (Gast)


Lesenswert?

>> Sonst könnte man auch einen normalen Interrupt-Eingang nehmen
>> und den aktuellen Zählerwert in der ISR auslesen.
>
> Stimmt, könnte man, aber ich hab doch geschrieben daß bei dieser
> Lösung ein Fehler entsteht, was ist da jetzt nicht zu verstehen ?

Nein, deine Lösung war ein Reset des Timers in der Input-Capture-ISR. 
Ich wollte einfach nur darauf hinweisen, daß das den einzigen wirklichen 
Vorteil von Input Capture gegenüber normalen Interrupt- oder 
PCINT-Eingängen zunichte macht. Daß das bei den niedrigen Frequenzen, um 
die es hier geht, keine Rolle spielt, ist natürlich richig.

von Sandro W. (swissm)


Lesenswert?

Also ich habe den Code jetzt wie folgt abgeändert:
1
ISR (TIMER1_CAPT_vect)               // Interrupt-Serviceroutine Timer 0
2
{ 
3
  temp[0]=ICR1L;
4
  temp[1]=ICR1H;
5
  freq_alt[0]=freq[0];
6
  freq_alt[1]=freq[1];    
7
  freq[0]=temp[0];
8
  freq[1]=temp[1];
9
}
10
11
int main()
12
{
13
  InitRS485();
14
  DDRC=0x20;
15
16
17
  TCCR1B |= (1<<ICES1); // pos Flanke
18
  TCCR1B |= (1<<CS10)|(1<<CS10); //clk/64
19
  TIMSK  |= (1<<TICIE1);    //Input Capture enable
20
21
  SREG |= 0x80;  // SREG : Globales "Interrupt enable"*/
22
23
  LED_AUS();
24
25
  freq[0]=0;
26
  freq[1]=0;
27
28
  freq_alt[0]=0;
29
  freq_alt[1]=0;
30
31
  for(;;)
32
  {
33
    cli();
34
    frequenz= (freq[0] + 256*freq[1]);
35
    frequenz-=(freq_alt[0]+256*freq_alt[1]);
36
    sei();
37
    frequenz*=4; //us
38
    frequenz=1000000/frequenz; 
39
    asm volatile ("nop");  
40
  }
41
42
}

Allerdings bekomme ich immer noch nicht die korrekte Frequenz raus, nur 
Frage ich mich wo der fehler liegt.

Ist es nicht so, das die ISR-Routine ausgelößt wird, wenn eine steigende 
Flanke ausgelößt wird?

Wenn ich nun  Flanken voneinander abziehe müsste ich doch die Freqzenz 
berechnen könnnen oder?

Und was wäre in meine Fall ein vernünftiger Prescaler und wie verhinder 
ich Fehler, die bei einem Überlauf entstehen?

Gibt es eine andere Möglichkeit als die globalen Interrupts 
auszuschalten, um schreibgeschützt, die Variabel zur berechnung zu 
benutzen?

von Karl H. (kbuchegg)


Lesenswert?

Sandro W. schrieb:
> Also ich habe den Code jetzt wie folgt abgeändert:

Warum wirfst du da wie wild mit Arrays um dich?
Braucht doch kein Mensch!
1
volatile uint16_t freq_alt;
2
volatile uint16_t freq;
3
4
ISR (TIMER1_CAPT_vect)               // Interrupt-Serviceroutine Timer 0
5
{
6
  freq_alt = freq;
7
  freq = ICR1;
8
}
9
10
int main()
11
{
12
  InitRS485();
13
  DDRC=0x20;
14
15
  TCCR1B |= (1<<ICES1); // pos Flanke
16
  TCCR1B |= (1<<CS10)|(1<<CS10); //clk/64
17
  TIMSK  |= (1<<TICIE1);    //Input Capture enable
18
 
19
  freq = 0;
20
  freq_alt = 0;
21
22
  LED_AUS();
23
24
  sei();
25
26
  for(;;)
27
  {
28
    cli();
29
    frequenz = freq - freq_alt;
30
    sei();
31
32
    frequenz*=4; //us
33
    frequenz = 1000000/frequenz;
34
  }
35
}


Die Timereinstellung hab ich nicht kontrolliert.

Auch der Datentyp von frequenz wäre interessant. Denn eines ist klar: 
frequenz kann maximal 65536 gross werden. Mehr geht durch den 16-Bit 
Timer und der jetzigen Programmierung nicht. Daher ist 1000000/frequenz 
mit Sicherheit immer 0 (selbst wenn ich berücksichtige, dass du 
zwischendurch noch mal 4 rechnest)

von Karl H. (kbuchegg)


Lesenswert?

Sandro W. schrieb:

> Und was wäre in meine Fall ein vernünftiger Prescaler

Ein vernünftiger Prescaler ist dann gegeben, wenn sich deine zu 
messenden Frequenzen im Zahlenbereich 0 bis 65536 gut abbilden.
Dazu kommt dann noch die Fragestellung: Wie genau will ich mein Ergebnis 
eigentlich messen?

> und wie verhinder
> ich Fehler, die bei einem Überlauf entstehen?

Indem du Überläufe feststellst und mit einrechnest?

> Gibt es eine andere Möglichkeit als die globalen Interrupts
> auszuschalten, um schreibgeschützt, die Variabel zur berechnung zu
> benutzen?

Nein.
Ist aber kein großes Thema. Die Variablen werden schnell gelesen und die 
Subtraktion dauert auch nicht lange. Läuft in der Zwischenzeit in 
Interrupt an, so wird er ein klein wenig verzögert. Der gecapturte Wert 
ist trotzdem richtig, lediglich die Bearbeitung verzögert sich ein klein 
wenig.

von Karl H. (kbuchegg)


Lesenswert?

Karl heinz Buchegger schrieb:
> Sandro W. schrieb:
>
>> Und was wäre in meine Fall ein vernünftiger Prescaler
>
> Ein vernünftiger Prescaler ist dann gegeben, wenn sich deine zu
> messenden Frequenzen im Zahlenbereich 0 bis 65536 gut abbilden.
> Dazu kommt dann noch die Fragestellung: Wie genau will ich mein Ergebnis
> eigentlich messen?

Und die Vorgehensweise ist genau andersrum.
Nimm deine langsamste Frequenz und rechne dir aus bis zu welchem Wert 
ein 16-Bit Timer bei allen möglichen Vorteilern von einer Signalflanke 
bis zur nächsten kommen wird.
Hast du das mit allen Vorteilern ausprobiert, siehst du nach, welcher 
geeignet ist, so dass du ohne Berücksichtigung der Überläufe arbeiten 
kannst. Geht sich das mit keinem Vorteiler aus, dann musst du auf 
Überläufe gehen.
Geht es sich aber aus, dann rechnest du mit diesem Vorteiler und einem 
Zählerwert + 1 wieder zurück auf die Frequenz und kriegst so raus, mit 
welcher Genauigkeit du deine Frequenz messen kannst. Selbes Spiel am 
anderen Ende der Skala.
Dann entscheidest du, ob dir das reicht, oder ob du mehr Aufwand treiben 
willst (musst).

Ja, auch in der Programmierung muss man im Vorfeld mal etwas 
Papierarbeit leisten.

von Sandro W. (swissm)


Lesenswert?

Karl heinz Buchegger schrieb:
> Karl heinz Buchegger schrieb:
>> Sandro W. schrieb:
>>
>>> Und was wäre in meine Fall ein vernünftiger Prescaler
>>
>> Ein vernünftiger Prescaler ist dann gegeben, wenn sich deine zu
>> messenden Frequenzen im Zahlenbereich 0 bis 65536 gut abbilden.
>> Dazu kommt dann noch die Fragestellung: Wie genau will ich mein Ergebnis
>> eigentlich messen?
>
> Und die Vorgehensweise ist genau andersrum.
> Nimm deine langsamste Frequenz und rechne dir aus bis zu welchem Wert
> ein 16-Bit Timer bei allen möglichen Vorteilern von einer Signalflanke
> bis zur nächsten kommen wird.
> Hast du das mit allen Vorteilern ausprobiert, siehst du nach, welcher
> geeignet ist, so dass du ohne Berücksichtigung der Überläufe arbeiten
> kannst. Geht sich das mit keinem Vorteiler aus, dann musst du auf
> Überläufe gehen.
> Geht es sich aber aus, dann rechnest du mit diesem Vorteiler und einem
> Zählerwert + 1 wieder zurück auf die Frequenz und kriegst so raus, mit
> welcher Genauigkeit du deine Frequenz messen kannst. Selbes Spiel am
> anderen Ende der Skala.
> Dann entscheidest du, ob dir das reicht, oder ob du mehr Aufwand treiben
> willst (musst).
>
> Ja, auch in der Programmierung muss man im Vorfeld mal etwas
> Papierarbeit leisten.

Ok habe ich gemacht:

Habe noch eine Änderung die Frequenz geht bis 1,3Hz, eine Kommastelle 
reicht mir von der Genauigkeit her dicke.

bei 1,3Hz
16Mhz/1024   -> 12019
16Mhz/256    -> 48077
16Mhz/64     -> 192308

Also beo 1024 und 256 erfolgt kein Überlauf.
Was mir noch nicht ganz klar ist:
Wenn der Timer 2 Flanken erfasst hat, zählt er dann weiter oder resetet 
er seinen Zähler auf 0?
Wenn er weiterzählt muss ja früher oder später mal ein Überlauf 
auftrteen, der zu einem Fehler führt oder nicht?


Die Variabel frequenz in dem Quellcode oben ist von uint32_t und daher 
den Wert 1.000.000 aufnehmen oder nicht?

von Karl H. (kbuchegg)


Lesenswert?

Sandro W. schrieb:

> Was mir noch nicht ganz klar ist:
> Wenn der Timer 2 Flanken erfasst hat, zählt er dann weiter oder resetet
> er seinen Zähler auf 0?

Zählt weiter.

> Wenn er weiterzählt muss ja früher oder später mal ein Überlauf
> auftrteen, der zu einem Fehler führt oder nicht?

Überlauf kommt zwar, aber solange es nur einer ist, ist das kein 
Problem. Durch die unsigned Arithmetik brauchst du das nicht 
berücksichtigen. Durch die Subtraktion kommt immer die Anzahl der 
Timerticks raus. Wie gesagt: Nur dann, wenn du nur 1 Überlauf hast.
Daher auch die Überlegung, den Vorteiler so einzurichten, dass sich 
alles im Bereich 0 bis 65535 abspielt.

> Die Variabel frequenz in dem Quellcode oben ist von uint32_t und daher
> den Wert 1.000.000 aufnehmen oder nicht?

Schon.
Aber aus deinem Timer kannst du (so wie es jetzt ist, also ohne 
Berücksichtigung von mehreren Überläufen) keinen Wert erhalten, der 
größer als 65536 ist. Das folgt daraus, dass es ein 16 Bit Timer ist.

von Sandro W. (swissm)


Lesenswert?

Ok Vielen dank!
Soweit habe ich die Frequenzmessung jetzt zum laufen bekommen.

Ein entscheidende Problem, was ich mit dem Frequenzgenerator nicht 
bedacht habe, ist, das ich unter realen Bedingungen durchaus mal eine 
Frequenz von 0hz haben kann.
Das Problem ist wie detektiere ich das?

Das Input Capture das nicht erfassen kann ist klar, da kommen  ja keine 
Flanken mehr.

Meine erste war eventuell ein zweiter Timer der den Ausgang über längere 
Zeit beobachtet und dann die Frequenz automatisch 0 setzt, wenn über 
einen Zeitraum keine Frequenz vorhanden ist.

Ich frage mich ob das auch eleganter geht?

Code sieht jetzt so aus
1
ISR (TIMER1_CAPT_vect)               // Interrupt-Serviceroutine Timer 0
2
{ 
3
  freq_alt=freq;
4
  freq=ICR1;
5
  capt_int=1;
6
}
7
8
int main()
9
{
10
  InitRS485();
11
  DDRC=0x20;
12
13
14
  TCCR1B |= (1<<ICES1); // pos Flanke
15
  TCCR1B |= /*(1<<CS10)|*/(1<<CS12); //clk/1024
16
  TIMSK  |= (1<<TICIE1);    //Input Capture enable
17
18
  SREG |= 0x80;  // SREG : Globales "Interrupt enable"*/
19
20
  LED_AUS();
21
22
  freq=0;
23
  freq_alt=0;
24
  capt_int=0;
25
  frequenz=0;
26
27
  for(;;)
28
  {
29
    if(capt_int==1)
30
    {
31
      capt_int=0;
32
33
      cli();
34
      frequenz = freq - freq_alt;
35
      sei();
36
      frequenz*=16; //us
37
      frequenz=10000000/frequenz;
38
      //Daten aufbereiten für den Bus
39
      akt_freq[1]=  frequenz/256;
40
      akt_freq[0]=  frequenz - ( akt_freq[1]*256);
41
    }
42
  }
43
44
}

von Karl H. (kbuchegg)


Lesenswert?

Sandro W. schrieb:
> Ok Vielen dank!
> Soweit habe ich die Frequenzmessung jetzt zum laufen bekommen.
>
> Ein entscheidende Problem, was ich mit dem Frequenzgenerator nicht
> bedacht habe, ist, das ich unter realen Bedingungen durchaus mal eine
> Frequenz von 0hz haben kann.
> Das Problem ist wie detektiere ich das?
>
> Das Input Capture das nicht erfassen kann ist klar, da kommen  ja keine
> Flanken mehr.

Das nicht.
Aber der Timer zählt weiter.
Wenn 2 Timeroverflows hintereinander kommen, ohne dass dazwischen eine 
Flanke lag (= der Input Capture angesprochen hat), dann ist das Signal 
zu langsam.

von Sandro W. (swissm)


Lesenswert?

Karl heinz Buchegger schrieb:
> Sandro W. schrieb:
>> Ok Vielen dank!
>> Soweit habe ich die Frequenzmessung jetzt zum laufen bekommen.
>>
>> Ein entscheidende Problem, was ich mit dem Frequenzgenerator nicht
>> bedacht habe, ist, das ich unter realen Bedingungen durchaus mal eine
>> Frequenz von 0hz haben kann.
>> Das Problem ist wie detektiere ich das?
>>
>> Das Input Capture das nicht erfassen kann ist klar, da kommen  ja keine
>> Flanken mehr.
>
> Das nicht.
> Aber der Timer zählt weiter.
> Wenn 2 Timeroverflows hintereinander kommen, ohne dass dazwischen eine
> Flanke lag (= der Input Capture angesprochen hat), dann ist das Signal
> zu langsam.

Also müsste ich nur feststellen, wenn ein 2ter Overflow stattgefunden 
hat.
Kann man das irgendwie abfragen ?

von Karl H. (kbuchegg)


Lesenswert?

Sandro W. schrieb:

> Also müsste ich nur feststellen, wenn ein 2ter Overflow stattgefunden
> hat.
> Kann man das irgendwie abfragen ?


Du hängst den Overflow Interrupt auf eine ISR, dort zählst du eine 
Zählvariable hoch, wenn sie nicht schon größer als 2 ist (damit 
Overflows dieser Variablen vermieden werden). In der Capture ISR wird 
die Variable auf 0 gesetzt. Ist die Variable bei der Auswertung größer 
als 2, dann gab es offensichtlich mehere Overflows hintereinander, ohne 
dass eine Flanke reinkam. Deine Entscheidung, was du dann machen willst.

von Sandro W. (swissm)


Lesenswert?

Also irgendwie bin ich zu blöd, ermüsste theoretisch in der ISR- 
Overflow Routine auf 3 Hochzählen und damit größer 2 sein und damit in 
den else Zweig gelangen aber, tut dies nicht.

Aber ich frag mich warum, iegenltich müsste die ISR doch ausgeführt 
werden.
1
ISR (TIMER1_CAPT_vect)              
2
{ 
3
  freq_alt=freq;
4
  freq=ICR1;
5
  capt_int=1;
6
  overflow_status=0;
7
}
8
9
ISR (TIMER1_OVF_vect)
10
{
11
  if(overflow_status <= 2)
12
  {
13
    overflow_status++;
14
  }
15
}
16
17
int main()
18
{
19
  InitRS485();
20
  DDRC=0x20;
21
22
23
  TCCR1B |= (1<<ICES1); // pos Flanke
24
  TCCR1B |= /*(1<<CS10)|*/(1<<CS12); //clk/1024
25
  TIMSK  |= (1<<TICIE1);    //Input Capture enable
26
27
  SREG |= 0x80;  // SREG : Globales "Interrupt enable"*/
28
29
  LED_AUS();
30
31
  freq=0;
32
  freq_alt=0;
33
  capt_int=0;
34
  frequenz=0;
35
36
  for(;;)
37
  {
38
    if(capt_int==1)
39
    {
40
      capt_int=0;
41
42
      cli();
43
      frequenz = freq - freq_alt;
44
      sei();
45
      frequenz*=16; //us
46
      frequenz=10000000/frequenz;
47
      //Daten aufbereiten für den Bus
48
      akt_freq[1]=  frequenz/256;
49
      akt_freq[0]=  frequenz - ( akt_freq[1]*256);
50
    }
51
    else if(overflow_status > 2)  //Frequenz zu langsam um erfasst zu werden
52
    {
53
      akt_freq[0]=0;
54
      akt_freq[1]=0;
55
      cli();
56
      freq=0;
57
      freq_alt=0;
58
      capt_int=0;
59
      frequenz=0;
60
      sei();
61
    }
62
63
  }
64
65
}

von Karl H. (kbuchegg)


Lesenswert?

TIMSK  |= (1<<TICIE1);    //Input Capture enable


Ich kann beim besten Willen nicht erkennen, wo hier der Overflow 
Interrupt freigeschaltet wird

von Karl H. (kbuchegg)


Lesenswert?

>  SREG |= 0x80;  // SREG : Globales "Interrupt enable"*/

Nein. Mach das nicht. Um die Overflows global freizuschalten, benutzt du

   sei();

Für dich als C-Programmierer, heißt es: Hände weg vom SREG.

von Sandro W. (swissm)


Lesenswert?

ok ich habe das ganze durch

1
  TIMSK  |= (1<<TICIE1) | (1<<TOIE1);    //Input Capture enable, Overflow enable
2
3
  sei();


ersetzt, nun müsste eigentlich der Overflow aktiviert sein oder?

von Karl H. (kbuchegg)


Lesenswert?

Sandro W. schrieb:
> ok ich habe das ganze durch
>
>
>
1
>   TIMSK  |= (1<<TICIE1) | (1<<TOIE1);    //Input Capture enable,
2
> Overflow enable
3
> 
4
>   sei();
5
> 
6
>
>
>
> ersetzt, nun müsste eigentlich der Overflow aktiviert sein oder?

Probiers aus.
Schalt im Overflow Interrupt eine LED ein (das Hello World des kleinen 
Mannes) und sieh nach ob sie eingeschaltet wird, wenn der Messeingang 
auf Masse geschaltet wird.

Brennt sie       -> ISR wird aufgerufen
Brennt sie nicht -> ISR wird nicht aufgerufen

So einfach ist das. Hilf dir selbst, dann hilft dir Gott :-)

von Sandro W. (swissm)


Lesenswert?

Karl heinz Buchegger schrieb:
> Sandro W. schrieb:
>> Wenn er weiterzählt muss ja früher oder später mal ein Überlauf
>> auftrteen, der zu einem Fehler führt oder nicht?
>
> Überlauf kommt zwar, aber solange es nur einer ist, ist das kein
> Problem. Durch die unsigned Arithmetik brauchst du das nicht
> berücksichtigen. Durch die Subtraktion kommt immer die Anzahl der
> Timerticks raus. Wie gesagt: Nur dann, wenn du nur 1 Überlauf hast.
> Daher auch die Überlegung, den Vorteiler so einzurichten, dass sich
> alles im Bereich 0 bis 65535 abspielt.
>

Das wollte ich nochmal aufgreifen.
Was genau ist damit gemeint. Wie genau findet den die Subtraktion statt, 
wenn ein Überlauf stattgefunden hat, damit noch das korrekte Ergebnis 
raus kommt?

von Karl H. (kbuchegg)


Lesenswert?

Sandro W. schrieb:

> Das wollte ich nochmal aufgreifen.
> Was genau ist damit gemeint. Wie genau findet den die Subtraktion statt,
> wenn ein Überlauf stattgefunden hat, damit noch das korrekte Ergebnis
> raus kommt?

Wenn man bei unsigned Arithmetik einen Über oder Unterlauf einfach 
ignoriert, entspricht das dem Arbeiten auf einer Zahlen'gerade' die zu 
einem Ring gebogen wird. Die Arithmetik findet automatisch 'modulo zu 2 
hoch Bitzahl' statt, ohne dass man irgendetwas dazu tun muss.


Das ist so wie bei einer Uhr: 56 Sekunden PLUS 5 Sekunden ergibt 1 
Sekunde (und eine Minute, aber der Überlauf wird ja ignoriert)
Gleichzeitig ergibt aber auch 1 Sekunde MINUS 5 Sekunden das Ergebnis 56 
Sekunden (und einen Unterlauf von 1 Minute, aber der wird ja ignoriert)

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.