mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Problem bei Frequenzmessung


Autor: Greenhorn (Gast)
Datum:

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

Autor: johnny.m (Gast)
Datum:

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

Autor: unsichtbarer WM-Rahul (Gast)
Datum:

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

Wie? Sowas geht?

Autor: johnny.m (Gast)
Datum:

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

Autor: unsichtbarer WM-Rahul (Gast)
Datum:

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

Autor: Sonic (Gast)
Datum:

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

Autor: unsichtbarer WM-Rahul (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Ich lege mir immer ein Statusregister an

Nicht nur du...

Autor: johnny.m (Gast)
Datum:

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

Autor: johnny.m (Gast)
Datum:

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

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.