www.mikrocontroller.net

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


Autor: Andreas H. (anderlh)
Datum:

Bewertung
0 lesenswert
nicht 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
#include <avr/io.h>
int main(void)
{
  //Pin B0 (ICP1) Input is default
  DDRB |= 0x04; //7Segment
  DDRC |= 0x3F; //7Segment
  DDRD |= 0xFF; //7Segment
  PORTB = 0x04; //7Segment
  PORTC = 0x3F; //7Segment
  PORTD = 0x7F; //7Segment
  
  TCCR1B |= (1<<ICNC1)|(1<<ICES1)|(1<<WGM13)|(1<<WGM12)|(1<<CS10);
  SREG |= 0x80;
  TIMSK |= (1<<TICIE1);
  TIFR |= (1<<ICF1);
  while(1)
  {
  }
}




#include <avr/io.h>
#include <avr/interrupt.h>
int INTERRUPT(SIG_INPUT_CAPTURE1)
{
  TIMSK &= ~(1<<TICIE1);

  unsigned int ziffereiner[] = {0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10};
  unsigned int zifferzehner1[] = {0x00,0x39,0x24,0x30,0x19,0x12,0x02,0x38,0x00,0x10};
  unsigned int zifferzehner2[] = {0x04,0x04,0x00,0x00,0x00,0x0,0x0,0x04,0x00,0x00};

  unsigned int icr,einer,zehner;
  double f;
  icr = ICR1L + (ICR1H<<8);

  f = 8e3/(icr+1);  //frequenzberechnung
  einer = (int)f%10; //ausrechnen der digits
  zehner = (int)f/10; //ausrechnen der digits

  PORTB = zifferzehner2[zehner];
  PORTC = zifferzehner1[zehner];
  PORTD = ziffereiner[einer];
  TIFR |= (1<<ICF1);
  TIMSK |= (1<<TICIE1);
}


Autor: Uwe (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Andreas H. (anderlh)
Datum:

Bewertung
0 lesenswert
nicht 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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.