Forum: Mikrocontroller und Digitale Elektronik Problem bei Frequenzmessung


von Greenhorn (Gast)


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;
}

von johnny.m (Gast)


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.

von unsichtbarer WM-Rahul (Gast)


Lesenswert?

>Hat sich das immer noch nicht rumgesprochen,
>dass ein Interrupt-Handler so kurz wie möglich zu halten ist?

Wie? Sowas geht?

von johnny.m (Gast)


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...

von unsichtbarer WM-Rahul (Gast)


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?

von Sonic (Gast)


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.

von unsichtbarer WM-Rahul (Gast)


Lesenswert?

>Ich lege mir immer ein Statusregister an

Nicht nur du...

von johnny.m (Gast)


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).

von johnny.m (Gast)


Lesenswert?

@Rahul:
Ich dachte immer, in der main darf man nur
1
while(1);
schreiben...;-)

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.