Problem bei Frequenzmessung

Gast #444901
Lesenswert?
• ▲
▼
Hallo,

ich versuche langsame Frequenzen zu messen, und benutze dabei den 
externen Interrupt. Starte ich mein Programm liefer mir der Kontroller 
als erstes ein richtiges Ergebnis, doch alle fortlaufenden Ergebnise 
sind unterschiedlich und falsch. Kann mir jemand helfen. Ich versuche 
einfach Messungen im 10 Sekunden Takt zu erzeugen, doch irgendwie will 
mir das nicht gelingen. Vielen Dank für konstruktive Hilfe.

#ifndef F_CPU                                         //Definiere 
ATmega16L
#define F_CPU 3686400UL                                //Quarz:3.6864 
MHz
#endif
#include <util/delay.h>
#include <avr/io.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <avr/interrupt.h>


ISR(INT0_vect)
{

static int i=0;
unsigned int j;
unsigned long time;
unsigned int timer[7];
unsigned char stream[40];
if(i==0)
{
i++;
TCNT1=0;
}
else
{
GICR=0;
i=0;
cli();
time=TCNT1;
time=57600*((float)1000000/(float)time);
timer[0]=time%10;
time=time/10;
timer[1]=time%10;
time=time/10;
timer[2]=time%10;
time=time/10;
timer[3]=time%10;
time=time/10;
timer[4]=time%10;
time=time/10;
timer[5]=time%10;
time=time/10;
timer[6]=time%10;
UCSRB=UCSRB | (1<<TXEN);                 //UART-Transmitter einschalten
UCSRC=UCSRC | (3<<UCSZ0);                //8-bit Datemformat;1 Stoppbits
UBRRH=0;                                 //Baudrate 19600 bei 3,6864MHz
UBRRL=11;
UDR=0;
sprintf(stream,"\n\r%d.%d%d%d%d%d%d 
",timer[6],timer[5],timer[4],timer[3],timer[2],timer[1],timer[0]);
for(j=0;j<=15;j++)
{
while(!(UCSRA & (1<<UDRE)))              //Warten bis der UART fertig
{
}
UDR=stream[j];
}
}
}




int main (void)
{
unsigned int i;
TCCR1B=(1<<CS01) | (1<<CS00);            //Clk auf 1/64 legen
MCUCR=MCUCR | (1<<ISC01) | (1<<ISC00);   //reagierend auf steigende 
Flanke INT0
while(1)
{
GICR=(1<<INT0);                          //lokalen Interrupt setzen
sei();                                   //globalen Interrupt setzen
for(i=0;i<=200;i++)
{
_delay_ms(50);
}
GICR=0;
cli();
}
return 0;
}
Gast #444913
Lesenswert?
• ▲
▼
Au Mann, wieder einer, der alles was es an rechenzeitintensiven 
Ausgaberoutinen gibt und noch alles Mögliche andere in einen 
Interrupt-Handler schmeißt und sich dann wundert, dass er 
Timing-Probleme kriegt. Hat sich das immer noch nicht rumgesprochen, 
dass ein Interrupt-Handler so kurz wie möglich zu halten ist?

Mal im Ernst: Schmeiß den ganzen sprintf- und sonstigen Kram aus der ISR 
raus und ins Hauptprogramm. Und überlege v.a. mal, wie lange sprintf und 
der ganze Rest brauchen und wie viele Interrupts Dir dadurch entgehen.
Gast #444920
Lesenswert?
• ▲
▼
Bedenke v.a., dass während der Ausgabe, die ja dummerweise in der ISR 
stattfindet, alles andere, auch die Frequenzmessung, auf Eis liegt. Mach 
die Frequenzmessung mit einem Timer-Interrupt (habs mir nicht so genau 
angesehen, musst also selbst entscheiden, obs mit Periodendauermessung 
[Capture] oder Periodenzählung [bei höheren Frequenzen] geht). Und die 
ganze Ausgabe ins Hauptprogramm. Dann kann der Timer-Interrupt (Compare, 
Overflow oder Capture, je nachdem) nämlich den ganzen Mist unterbrechen, 
wenn etwas wichtiges passiert. Das ganze Programm ist nicht 
durchdacht...
Gast #444921
Lesenswert?
• ▲
▼
Geil! (SCNR)
Sowas hab ich noch nie gesehen: Eine bedingte USART-Initialisierung in 
einer ISR.
Wie mein Held vo KTEL im "Vierten" immer meint "Einfach groossaartig!"


Manchmal glaube ich fast, dass es verboten ist, in der main irgendwas zu 
machen.
Die main ist doch dazu da, von Interrupts unterbrochen zu werden, oder?
Gast #444925
Lesenswert?
• ▲
▼
Ich lege mir immer ein Statusregister an, in dem ich Flags definiere. 
Zeitaufwändige Sachen, wie gesagt, ins Hauptprogramm und mi Hilfe der 
Flags ausführen lassen. So müssen in den INT-Routinen nur Flags gesetzt 
werden.
Gast #444934
Lesenswert?
• ▲
▼
Ach ja, worüber Du Dir vielleicht zuerst Gedanken machen solltest, sind 
die Bearbeitungsprioritäten im Programm. Zeichne Dir am besten einen 
Ablaufplan. Denke daran, dass eine Frequenzmessung darauf angewiesen 
ist, dass kein Zählereignis verloren geht. Die Ausgabe und die 
Berechnung der auszugebenden Werte sind völlig unkritisch, was das 
Timing angeht. Die können auch mal warten, wenn grad was wichtiges 
ansteht.

Merke:
Sachen wie Fließkommaberechnungen, serielle Ausgaben, Warteschleifen 
usw. haben in einem Interrupt-Handler nichts zu suchen. Außerdem 
könntest Du überlegen, ob es wirklich unbedingt sprintf sein muss. Da 
gibt es wesentlich spezialisiertere Funktionen in der stdlib.h, die 
aufgrund ihrer Spezialisierung wesentlich weniger Overhead produzieren 
(was auch i.d.R. zu wesentlich kürzeren Bearbeitungszeiten führt).

Antwort schreiben

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.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.