Ich habe am tiny85 (8MHz intern, INT0) einen Frequenzgenerator angeschlossen, der auf 15Hz eingestellt ist. Ich möchte nun die Zeit in Mikrosekunden messen, die zwischen zwei Interrupts vergeht. Dabei wird nur die fallende Flanke ausgewertet. Hier meine Konfiguration:
1
MCUCR|=(1<<ISC01);// The falling edge of INT0 generates an interrupt request.
Was dabei herauskommt ist nicht, wie ich erwartet hätte ca. 66000 us. Sondern wechselnde Werte unter 2000 us. Was mich glauben lässt, dass es mehr Interrupts gibt als es eigentlich sein dürften. Wie kann das sein?
Ich habe am tiny85 (8MHz intern, INT0) einen Frequenzgenerator
angeschlossen, der auf 15Hz eingestellt ist. Ich möchte nun die Zeit in
Mikrosekunden messen, die zwischen zwei Interrupts vergeht. Dabei wird
nur die fallende Flanke ausgewertet. Hier meine Konfiguration:
Es gibt keine Konfiguration, wohl aber einen Quelltext. Den sollte mn VOLLSTÄNDIG bereitstellen. Einfach als Datei anhängen, ist gar nicht schwer.
loop() {
if(triggered) {
1
newTriggerTime = micros();
2
triggered = false;
3
4
uint32_t us;
5
if ( newTriggerTime > oldTriggerTime ) {
6
us = newTriggerTime - oldTriggerTime;
7
} else {
8
us = (4294967295UL - oldTriggerTime + newTriggerTime + 1);
9
}
Diesen Unsinn braucht man nicht. Wenn die Differenz kleiner als der halbe Zählerumfang ist, ist die Differenz immer korrekt, auch beim Überlauf.
1
us=newTriggerTime-oldTriggerTime;
Was dabei herauskommt ist nicht, wie ich erwartet hätte ca. 66000 us.
Sondern wechselnde Werte unter 2000 us. Was mich glauben lässt, dass es
mehr Interrupts gibt als es eigentlich sein dürften. Wie kann das sein?
Dein triggered ist hoffentlich als volatile deklariert, siehe Interrupt.
woher nimmst du denn die new / old Triggertime?
Der Tiny85 hat nur Timer mit 8 Bit (0..255)
Sowas macht man mit Input-Capture, wofür es einen Tiny24/44/84 mit
16-Bit-Timer braucht. Eventuell mit einem Zusatzregister, dass die Überläufe erfasst.
Dein triggered ist hoffentlich als volatile deklariert, siehe
Ja, natürlich. Viel mehr Code als das, was ich gepostet habe, gibt es gar nicht.
Ist ein mini Testprogramm, welches zunächst erstmal nur diese eine Aufgabe erfüllen soll.
Im setup findet man noch diese drei Zeilen:
1
CLKPR|=(1<<CLKPCE);// Aktivieren der Taktprescaler-Änderung
2
CLKPR=(0<<CLKPS3)|(0<<CLKPS2)|(0<<CLKPS1)|(0<<CLKPS0);// Setzen auf 8 MHz ohne Prescaler
3
OSCCAL=0x89;
mehr ist es nicht...
Was die Wahl des Controllers angeht, das ist leider durch die Hardware vorgegeben. Um den tiny85 komme ich nicht herum. Da ich normalerweise auf andere Typen setze und dies meine erste Berührung mit dem Tiny85 ist, kenne ich natürlich auch seine Eigenarten nicht. Ist also gut möglich, dass ich das völlig falsch angehe und/oder wesentliches vergessen habe.
Ja, natürlich. Viel mehr Code als das, was ich gepostet habe, gibt es
gar nicht.
Umso einfacher ist es, den Quelltext VOLLSTÄNDIG und im ORIGINAL hier beizustellen! Du wärst nicht der Erste, der beim Kopieren oder gar ABSCHREIBEN einen Fehler einbaut.
Die Fuses sind bestimmt auch noch interessant. Die also auch gleich noch auslesen und posten.
Ist die Frage ob es gut ist irgendwie am Takt zu drehen wenn deine Arduino Lib von etwas anderem ausgeht.
Keine Ahnung ob man der das im Nachhinein mitteilen kann oder ob das Fest ist.
Wenn das nicht der Defaultwert ist, ist mir klar warum keine Zeiten mehr passen.
Also evtl Mal alles zurück auf Anfang und NICHT am Takt drehen. Vielleicht geht's dann. Wäre ein einfacher Test.
Zuerst würde ich mal einen 16-Bit Timer aufsetzen. Das machst du mit dem Timer Overflow Interrupt, der das obere Byte hochzählt. Zusammengesetzt mit dem CNT des Timers hast du dann einen 16 Bit Timer. Das kannste kaskadieren und noch ein Byte hochzählen, wenn du Werte mit mehr als 65535 µs erwartest.
Im flankengesteuerten Interrupt liest du alle 3 Bytes (High, Mid, CNT) aus und speicherst sie an einen Safeplace. Alles löschen und den Timer wieder mit 1µs Zykluszeit starten (Prescaler 8).
Damit ist der Arduino Timer raus und du bekommst ganz gute Werte.
Das Ergebnis ergibt sich aus (65536 x High) + (256 x Mid) + CNT.
Der Code sieht prinzipiell o.k. aus.
Es könnte sein, daß Dir die Dauer der seriellen Ausgabe in die Suppe spuckt.
Ich würde daher die Zeitermittlung direkt im Interrupt machen.
Dabei nicht vergessen, die Übernahme des Wertes in der Loop atomar zu kapseln.
Dein Generator liefert 5V Rechteck?
Zuerst würde ich mal einen 16-Bit Timer aufsetzen. Das machst du
mit dem
Timer Overflow Interrupt, der das obere Byte hochzählt. Zusammengesetzt
mit dem CNT des Timers hast du dann einen 16 Bit Timer. Das kannste
kaskadieren und noch ein Byte hochzählen, wenn du Werte mit mehr als
65535 µs erwartest.
Es reicht, die Überläufe mit 32 Bit zu zählen,
1
ISR(TIMER1_OVF_vect)
2
{
3
ueberlauf++;// grobe Zeitmessung mit T1
4
}
und den Wert des 8 Bit Timers dazuzupacken:
1
temp_ueberlauf=ueberlauf;// ueberlauf++ per ISR
2
if(TIFR&BIT(TOV1)&&(TCNT1<0x80))// noch einer offen?
Es reicht, die Überläufe mit 32 Bit zu zählen,ISR (TIMER1_OVF_vect)
{
ueberlauf++; // grobe Zeitmessung mit T1
}
und den Wert des 8 Bit Timers dazuzupacken:temp_ueberlauf = ueberlauf;
// ueberlauf++ per ISR
if(TIFR & BIT(TOV1) && (TCNT1 < 0x80)) // noch einer offen?
temp_ueberlauf++; // dann +1
zeitpunkt = temp_ueberlauf * 0x100 + TCNT1;
Habe das mal so umgesetzt. Habe das Ergebnis erstmal geteilt und ausgegeben.
#define SENSOR PB2 // pin7
#define LED PB4 // pin3
pinMode (SENSOR, INPUT);
pinMode (LED, OUTPUT);
Das geht so nicht. Die digitalen Ios sind in der Arduino-Welt mit Nummern versehen, also 1, 2,3,4. PB2 und PB4 sind Namen der "normalen" avr gcc Welt. Die funktionieren nicht mit der Funktion pinMode() bzw. man schaltet die falschen IOs.
Wenn deine komische ssPrintln() Funtkion nur 16 Bit ausgeben kann, probier's mal so.
ssPrintln(us/10);
Ein sei() wird bei Arduino nicht benötigt, denn in der setup-Funktion sind die Interrupts schon aktiv, das macht die Arduino-Software vorher. Sie schadet aber auch nicht.
Da wird alles in den Interruptroutinen erledigt und ein PCINT-Pin verwendet. Die Auswertung in loop() ist immer eine schlechte Idee!
Wenn Du die Endung auf .ino änderst, sollte Arduino das auch Übersetzen können. Selbst habe ich es nicht probiert.