Forum: Mikrocontroller und Digitale Elektronik Frequenzmessung mit ATMEGA8 T/C1


von Andreas H. (anderlh)


Lesenswert?

Hallo liebe Controllerfreunde,

ich habe ein eigentlich einfaches Problem. Ich weis theoretisch auch wie 
es gehen sollte. Nun tu ich schon Wochen rum und les hier die Beiträge, 
aber leider bekomm ich es ums Verrecken nicht hin. Vielleicht kann mir 
jemand helfen.

Ich möchte ein Rechtecksignal mit einer Frequenz von 20-80kHz messen. 
Der duty cycle ist immer 50%.
Sowas geht doch z.B. mit dem Timer/Counter 1 mittels Input Capture und 
den zugehörigen Interrupt. Das Rechtecksignal bringe nach 
Figure38(Manual) über den PIN ICP1. Betriebsart des Zählers CTC.

Verstehe ich die Funktion richtig?
Die Flanke kommt am Pin, der Counter läuft los. Tritt erneut die Flanke 
auf, schreibt der Controller der Wert aus dem Zählerregister TCNT1H+L 
die Register ICR1H+L, es wird der Interrupt ausgelöst....

Mein Ansatz:

ATMEGA8 mit 16Mhz Quarz und zwei 7-Segmentanzeigen für die Darstellung.

Die Ansteuerung der 7-Segment mit den PORTS ist kein Problem, das schaff 
ich immerhin ;-)

Die Messung:
Ich setze das Bit GlobalInterrupt im  SREG.
Dann die Betriebsart CTC (WGM12+13), Prescaler 1 (CS10), rising 
edge(ICES1) und noise canceler on(ICNC1), sowie die Interrupt TICIE1 in 
den Registern TCCR1A+B und TIMSK.
Hier im Forum habe ich gelesen, dass es wichtig sei, am Anfang einmal 
das Interruptflag im TIFR mit einer "1" zurückzusetzen.

Jetzt muss ich doch nur noch warten bis der Interrupt auftritt und 
verarbeite ihn in meiner ISR, die eine Funktion namens 
INTERRUPT(SIG_INPUT_CAPTURE1) enthält. Solange die Routine abgearbeitet 
wird deaktiviere ich den Interrupt TICIE1, um mir keine Werte zu 
überschreiben.

Das funktioniert so nicht, vielleicht habe ich ein Problem mit dem 
Timing ??

Hier mein Code: Es sind zwei Dateien main.c und isr.c
1
#include <avr/io.h>
2
int main(void)
3
{
4
  //Pin B0 (ICP1) Input is default
5
  DDRB |= 0x04; //7Segment
6
  DDRC |= 0x3F; //7Segment
7
  DDRD |= 0xFF; //7Segment
8
  PORTB = 0x04; //7Segment
9
  PORTC = 0x3F; //7Segment
10
  PORTD = 0x7F; //7Segment
11
  
12
  TCCR1B |= (1<<ICNC1)|(1<<ICES1)|(1<<WGM13)|(1<<WGM12)|(1<<CS10);
13
  SREG |= 0x80;
14
  TIMSK |= (1<<TICIE1);
15
  TIFR |= (1<<ICF1);
16
  while(1)
17
  {
18
  }
19
}
20
21
22
23
24
#include <avr/io.h>
25
#include <avr/interrupt.h>
26
int INTERRUPT(SIG_INPUT_CAPTURE1)
27
{
28
  TIMSK &= ~(1<<TICIE1);
29
30
  unsigned int ziffereiner[] = {0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10};
31
  unsigned int zifferzehner1[] = {0x00,0x39,0x24,0x30,0x19,0x12,0x02,0x38,0x00,0x10};
32
  unsigned int zifferzehner2[] = {0x04,0x04,0x00,0x00,0x00,0x0,0x0,0x04,0x00,0x00};
33
34
  unsigned int icr,einer,zehner;
35
  double f;
36
  icr = ICR1L + (ICR1H<<8);
37
38
  f = 8e3/(icr+1);  //frequenzberechnung
39
  einer = (int)f%10; //ausrechnen der digits
40
  zehner = (int)f/10; //ausrechnen der digits
41
42
  PORTB = zifferzehner2[zehner];
43
  PORTC = zifferzehner1[zehner];
44
  PORTD = ziffereiner[einer];
45
  TIFR |= (1<<ICF1);
46
  TIMSK |= (1<<TICIE1);
47
}

von Uwe (Gast)


Lesenswert?

Hi!
>Betriebsart des Zählers CTC.
Was ist denn das für ein Unsinn. Der Zähler ist erstmal ein Timer der 
von irgendeinem CLK hochgezählt wird. CTC finde ich nicht gut weil man 
dann eventuell sehr oft auf die Überläufe achten muss.
Mit ICP kannst du nun den zeitlichen Abstand zwischen 2 Flanken 
bestimmen, die ISR muss also bei jedem Auftreten vom neuen ICP-Wert den 
vorherigen Wert abziehen(Wenn neu>alt sonst Überlauf beachten).
1/die Differenz ist dann f
ICP macht also nichts anderes als den aktuellen Wert des Timers(der 
immer läuft) nach ICR1L/H zu kopieren und das bei jedem Auftreten.

Viel Erfolg, Uwe

von Andreas H. (anderlh)


Lesenswert?

Danke Uwe für die Antwort,

dass der Timer/Counter1 ja immer läuft habe ich völlig übersehen!
Das würde dann bedeuten, dass die erste Messung nicht richtig ist?
Welchen "Mode of Operation" würdest du statt CTC vorschlagen (Tabelle 39 
im Manual)?

Gruss
Andreas

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.