Forum: Compiler & IDEs Geschwinigkeit messen (atmega8)


von Thomas (Gast)


Lesenswert?

Hallo,
ich versuche über eine Zeitmessung mit dem 16 Bit timer meines atmega 8 
im Endeffekt auf die Geschwindigkeit zu kommen. Vorerst messe ich nur 
einmal die Zeit. Die Messung soll über 2 lichtschranken geschehen.
Jetzt hab ich aber das Problem dass das ganze recht ungenau ist.
Ich erklär mal wie ich es gemacht habe:
Zwei Lichtschranken, beide lösen bei der fallenden Flanke an den Pins 
INT1 und INT0 einen Interrupt aus, der erste Interrupt schaltet den 
Timer ein, der zweite Interrupt schaltet den Timer aus. Damit ich eine 
schöne Flanke bekomme verwende ich eine LM339(komperator).
Bei jedem Overflow wird die Variable i um eins herhöht, bei der 
Berechnung zähle ich dann i mal die zeit eines Timerdurchlaufes dazu.

Mein Problem, wenn ich den zweiten interrupt auslöse(zeitmessung 
fertig,timer stoppen), dann bleibt der Timer anscheinend nicht sofort 
stehen, sprich ich sehe am LCD dass sich die Zeit noch im ca 
Zehn-Millisekundenbereich ändert. Teilweise noch eine halbe Sekunde 
nachdem auslösen der Lichtschranke.
Ich würde gerne sehr genau messen, sprich am liebsten auf 10-100us.

Jetzt meine Fragen: :)
Ist das so wie ich es mir gedacht habe eine gute Lösung?
Geht es einfacher / besser?
und was könnte ein Grund dafür sein warum ich ungenau messe? Die Flanke 
nicht "genau" genug? oder sind die INT0/1 pins ungeeignet?

Freue mich über jede Anregung/Kritik.
Vielen Dank im voraus !

code:
1
char ausgabe[30];
2
float timerwert;
3
volatile unsigned int i = 0;
4
float takt = 0.000000125; // Taktdauer bei 8MHz
5
float time;
6
int port;
7
  
8
int main(void)
9
{  
10
   sei();  // Global Interrupts aktivieren
11
12
  //***Interrupts initialisieren***
13
  GIMSK = (1<<INT1)|(1<<INT0);  //Pin INT0 und INT1 werden enabled
14
  MCUCR = (1<<ISC11)|(0<<ISC10);  //Die Fallende Flanke an Pin INT1 erzeugt einen Interrupt und der timer wird ausgeschalten
15
  MCUCR = (1<<ISC01)|(0<<ISC00);  //Die fallende Flanke an Pin INT0 erzeugt einen Interrupt und der timer wird eingeschalten
16
        
17
  lcd_init();
18
         
19
        while(1)
20
        {
21
         timerwert = TCNT1;
22
         time = (i*65536.0*takt)+(timerwert*takt);
23
24
          sprintf(ausgabe, "%f", time);      //Ausgabe  
25
          lcd_clear();
26
          lcd_string(ausgabe);
27
          _delay_ms(100);
28
        }
29
}
30
31
    ISR (TIMER1_OVF_vect)
32
    {i = i+1;}
33
34
    ISR(INT0_vect)  //timer einschalten
35
    {   TCCR1B = (0<<CS11)|(1<<CS10);
36
        TIMSK |= (1<<TOIE1); //overlow interrupt erlauben
37
    }
38
39
    ISR(INT1_vect)  //timer ausschalten
40
    {   TCCR1B = (0<<CS11)|(0<<CS10);
41
        TIMSK |= (0<<TOIE1);
42
    }

von Karl H. (kbuchegg)


Lesenswert?

timerwert = TCNT1;

und wer sagt dir, dass der Timer bei 0 weggelaufen ist?

Du musst schon die Differenz der Timerstände beim Starten und dem 
Timerstand beim Stoppen nehmen. Wenn du das unsigned rechnest musst du 
dann den ersten Overflow unter Umständen noch nicht einmal einrechnen.
1
  MCUCR = (1<<ISC11)|(0<<ISC10);  //Die Fallende Flanke an Pin INT1 erzeugt einen Interrupt und der timer wird ausgeschalten
2
  MCUCR = (1<<ISC01)|(0<<ISC00);  //Die fallende Flanke an Pin INT0 erzeugt einen Interrupt und der timer wird eingeschalten

und deine Lichtschranke liefert beim durchbrechen welche Flanke?


Das hier
1
        TIMSK |= (0<<TOIE1);
löscht nicht das TOIE1 Bit. Das verändert TIMSK überhaupt nicht.
Ein Bit wird gelöscht mit
1
   TIMSK &= ~( 1 << TOIE1 );

gilt sinngemäss auch für alle anderen Bits, die du mittels 0<<irgendwas 
auf 0 zu setzen versuchst.

Bitmanipulation


> Teilweise noch eine halbe Sekunde nachdem auslösen der Lichtschranke.

Ja nachdem wo der Interrupt diesen Code hier
1
         timerwert = TCNT1;
2
         time = (i*65536.0*takt)+(timerwert*takt);
3
4
          sprintf(ausgabe, "%f", time);      //Ausgabe  
5
          lcd_clear();
6
          lcd_string(ausgabe);
7
          _delay_ms(100);
unterbricht, kann sich dann der finale Wert noch mal ändern. Und je 
nachdem wo der Interrupt den Code unterbricht, kann das dann auch schon 
mal etwas länger dauern. sprintf braucht Zeit, lcd_clear braucht Zeit 
(und führt zu Flackern), lcd_string braucht Zeit und _delay_ms braucht 
sowieso Zeit.

von Oliver (Gast)


Lesenswert?

Für solche Aufgabestellung eignet sich der Input capture mode ganz 
hervorragend. Genauer als damit geht es nicht.

Oliver

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.