Archiv verlassen und diese Seite im Standarddesign anzeigen : Zeit genau messen
Johannes G.
23.08.2006, 18:55
Hallo,
also, ich habe 2 Taster, T1 und T2. Wenn ich auf T1 drücke soll der AVR anfangen die Zeit zu stoppen bis T2 gedrückt wird (auf 0.01 sek genau wenn es so genau geht ;) ).
Wie programmiere ich sowas am besten?
Da ich noch nicht lage mit AVRs arbeite hab ich da keine Idee wie ich das machen könnte...
Viele Grüße,
Johannes
BlackDevil
23.08.2006, 20:45
ich kann zwar kein C aber überleg dir ma folgendes:
WENN (PORTX=1) THEN
TimerStart
ENDIF
und in den overflow vom timer dann halt wen porty ein high bekommt
denke mal
Johannes G.
24.08.2006, 09:51
Hm, an Timer habe ich auch schon gedacht, aber ich weiß leider nicht, wie die genau funktionieren, bzw. wie ich die mit C starte/stoppe etc...
16Bit Timer verwenden.
Dann zwei Interruptroutinen:
Die erste für die Tastendrücke. Wenn die T0 gedrückt wird, werden die Ergebnisregister und das Timerregister zurück gesetzt. Wenn T1 gedrückt wird, wird auf das Ergebnis der aktuelle Timerwert aufaddiert und in eine andere Variable weggeschrieben.
Die zweite Reagiert auf einen Timerüberlauf und zählt das Ergebnissregister hoch.
Bei einem Mega168 kommt man so auf eine Genauigkeit von
ca. 1/20MHz/8 (wegen Verzögerungen in den Interruptroutinen, max. 8 Takte zum Interruptvektor ausführen und Timerregister lesen) und einen Zählbereich von 65536/20Mhz * 32bit = 14073748,8355328s also ca. 3909 Stunden.
Die genaue Funktion der Timer kannst Du in den Datenblättern von Atmel nachlesen. Da gibt es meistens auch Beispiele in C
Johannes G.
24.08.2006, 12:57
Ok, dann fang ich als erstes mit den Interrupts an.
Ich wollte an INT0 und INT1 je einen Taster anschließen... Brauche ich da Pullups/Pulldowns?
Im Datenblatt vom AVR (mega8) hab ich aber kein Beispiel gefunden, wie ich das dann genau programmieren muss, kann mir da bitte jemand mal ein Beispiel zeigen?
Viele Grüße,
Johannes
Ja, am einfachsten:
Einen Pullup von 10k und einen Kondensator 47n nach Masse. Den Taster vom Pin ebenfalls nach Masse. So ist die Taste entprellt und Du sparst Dir das Entprellen in Software.
Die Konfiguration ist dann für den INT0 bzw. INT1 "Interrupt on falling edge"
Es gibt Beispiele für die Interruptprogrammierung in den AVR GCC Turtorials hier im wiki oder auf mikrocontroller.net
SprinterSB
24.08.2006, 15:09
Etwas einfacher geht's hier, weil du 2 verschiedene Taster hast auf denen je nur eine Funktion liegt: zu Entprellen brauchst du eigentlich nicht (schon garnicht bei einer Auflösung von 10ms).
Die internen PullUps aktivieren und die Taster vom jeweiligen Port nach Masse.
Falls der Start-Taster kurz prellt, wirst du den Timer zweimal oder öfter kurz hintereinander starten, was aber nicht weiter stören sollte.
Falls du entprellen willst geht das auch einfach dadurch, daß du in INT0 (Start) den INT0 deaktivierst und INT1 (Ende) aktivierst. Und erst in INT1 wird INT0 wieder aktiviert und INT1 deaktiviert.
Stimmt, elegante Lösung, das spart ein paar Bauteile.
Johannes G.
24.08.2006, 15:57
Hallo,
ich bekomme das mit den Interrupts nicht ganz hin, hier mal der Code:
#define F_CPU 16000000
#include <avr/io.h>
#include <avr/interrupt.h>
#include <inttypes.h>
#include "usart.c"
ISR(INT0_vect)
{
usart_print("INT0\n");
}
int main()
{
usart_init();
sei();
usart_print("Warte auf Interrupt...\n");
while(1)
;
}
Aber wenn ich INT0 mit VCC verbinde passiert gar nix...
Viele Grüße,
Johannes
Falls der Start-Taster kurz prellt, wirst du den Timer zweimal oder öfter kurz hintereinander starten, was aber nicht weiter stören sollte.
Es geht aber ohne weiteres auch genauer. Nachdem der Interrupt des ersten Tasters ausgelöst wurde, wird dierser sofort deaktiviert und der Interrupt des zweiten Tasters enabled. Ein Nachprellen auf dem ersten Taster löst somit keine Interruptroutine mehr aus.
Johannes G.
24.08.2006, 16:04
Wie kann ich einzelne Interrupts deaktivieren?
Mit cli(); deaktiviere ich ja alle...
Ich meine hier:
General Interrupt Control Register – GICR
Seite 49 im Datenblatt
Sorry, ich bin da irgendwie garnicht mehr drin...
@johannes:
Schau bitte mal in eines der oben erwähnten Tutorials rein. Da ist alles bestens erklärt.
Kurzer Hinweis: Du musst erst mal Deine Interrupt Register so einstellen, dass der INT0 und INT1 frei geschaltet sind.,
Johannes G.
24.08.2006, 17:37
Hallo,
ok, also hier der aktuelle Code
#define F_CPU 16000000
#include <avr/io.h>
#include <avr/interrupt.h>
#include <inttypes.h>
#include "usart.c"
ISR(INT0_vect)
{
usart_print("INT0\n");
}
ISR(INT1_vect)
{
usart_print("INT1\n");
}
int main()
{
usart_init();
GIMSK |= (1 << INT1) | (1 << INT0);
MCUCR |= (1 << ISC11) | (1 << ISC10);
MCUCR |= (1 << ISC01) | (1 << ISC00);
sei();
usart_print("Warte auf Interrupt\n");
while(1)
;
}
Wenn ich nun INT0 oder INT 1 mit VCC verbinde passiert manchmal gar nix, manchmal kommt Zeichensalat im Terminal an..
Viele Grüße,
Johannes
Hm, also usart.c habe ich noch nie benutzt.
Setze auf jeden Fall mal die DDR.
ich glaube:
DDRD = 0bxxxx0010;
x := wie es bei dir ist.
Dann solltest du die Ports noch Null setzten (Pulldown):
PORTD &= ~(1<<2);
PORTD &= ~(1<<3);
Johannes G.
25.08.2006, 08:37
Hm, also usart.c habe ich noch nie benutzt. Das ist meine eigene Datei und die funktioniert sonst immer ;)
Setze auf jeden Fall mal die DDR.
ich glaube:
DDRD = 0bxxxx0010;
x := wie es bei dir ist.
Was meinst du damit?
plusminus
25.08.2006, 11:02
Er weiß ja nicht genau, wie die DatenRichtung an deinem PortD aussieht...
Johannes G.
25.08.2006, 12:35
An meinem AVR ist gar nix angeschlossen, nur eben die 2 Taster an INT0/1
Soll ich Port D als eingang oder ausgang definieren?
Viele Grüße,
Johannes
Er weiß ja nicht genau, wie die DatenRichtung an deinem PortD aussieht...
genau
An meinem AVR ist gar nix angeschlossen, nur eben die 2 Taster an INT0/1
Soll ich Port D als eingang oder ausgang definieren?
Beides alleine geht nicht, da D2 und D3 je Eingänge sein müssen. Du willst aber per serieller Schnittstelle senden, deshalb muss PD2 auf jeden fall Ausgang sein. Falls du noch Empfangen willst, dann muss PD1 ein Eingang sein. Wenn aber sonst ncihts anderes and den AVR angeschlossen ist, probier mal das:
DDRD = 0b11110010;
PORTD &= ~(1<<2);
PORTD &= ~(1<<3);
Wenn du D2 oder D3 jetzt an 5V legst sollte was passieren ;-)
DDRD ist das Data Direction Register des Port D. Eine 1 bedeutet Ausgang, eine 0 Eingang.
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.