ATtiny85 - externer Interrupt

#7687967
Lesenswert?

Hallo,

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.
2
   GIMSK |= (1 << INT0);  // External Interrupt Request 0 Enable
3

4
ISR(INT0_vect) {
5
   triggered = true;
6
}
7

8

9
loop() {
10
    if(triggered) {
11
    
12
    newTriggerTime = micros();
13
    triggered = false;
14
 
15
    uint32_t us;
16
    if ( newTriggerTime > oldTriggerTime ) {
17
      us = newTriggerTime - oldTriggerTime;
18
    } else {
19
      us = (4294967295UL - oldTriggerTime + newTriggerTime + 1); 
20
    }
21
    Serial.print(F("Difference : "));
22
    Serial.println(us);
23
        
24
    oldTriggerTime = newTriggerTime;
25
    
26
  }
27
}

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 hoffe, jemand kann helfen...

VG Matze

#7687980
Lesenswert?

Matthias H. schrieb:

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.

#7687984
Lesenswert?

Hallo Matthias,

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.

Beitrag #7688035 wurde von einem Moderator gelöscht.
#7688123
Lesenswert?

Falk B. schrieb:

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.

#7688184
Lesenswert?

Man sieht auch nirgends ein sei().

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.

(Firma: matzetronics) #7688200
Lesenswert?

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.

#7688232
Lesenswert?

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?

#7688266
Lesenswert?

Matthias S. schrieb:

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?
3
  temp_ueberlauf++;                      // dann +1
4
zeitpunkt = temp_ueberlauf * 0x100 + TCNT1;

Mario M. schrieb:

Dein ssPrintln kann nur 16 Bits.

Dann vielleicht in zwei Hälften ausgeben.

#7688395
Lesenswert?

Mi N. schrieb:

Matthias S. schrieb:

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.

32 21 -1 -23 -24 84 -54 51 -23 -23 78 -28 -16

Peter D. schrieb:

Dein Generator liefert 5V Rechteck?

Ja, der liefert ein Rechteck. HighLevel 5,0V ; LowLevel 0mV ; 15Hz

#7688403
Lesenswert?

Ich sehe da mehrere Probleme.

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

#7688407
Lesenswert?

Probier's mal so.

1
#include "SS_Tiny85.h"
2

3
#define SENSOR    PB2     // pin7   
4
#define LED      PB4     // pin3 
5

6
volatile bool triggered = false;
7
uint32_t oldTriggerTime = 0;       
8
uint32_t newTriggerTime = 0;       
9

10
ISR(INT0_vect) {
11
  
12
  triggered = true;
13
  
14
}
15

16
void setup() {
17
  CLKPR |= (1 << CLKPCE);                                                       // Aktivieren der Taktprescaler-Änderung
18
  CLKPR = (0 << CLKPS3) | (0 << CLKPS2) | (0 << CLKPS1) | (0 << CLKPS0);        // Setzen auf 8 MHz ohne Prescaler
19
  OSCCAL = 0x89;
20
  
21
  pinMode (SENSOR, INPUT);
22
  pinMode (LED, OUTPUT);
23

24
  MCUCR |= (1 << ISC01);                  // The falling edge of INT0 generates an interrupt request.
25
  GIMSK |= (1 << INT0);                   // External Interrupt Request 0 Enable
26

27
  ssBegin(9600);
28
}
29

30
void loop() {
31
  if ( triggered ) {
32

33
    triggered = false;    
34
    newTriggerTime = micros();    
35
    uint32_t us;
36
    us = newTriggerTime - oldTriggerTime;
37
    ssPrint(F("difference : "));
38
    ssPrintln(us/10);    
39
    oldTriggerTime = newTriggerTime;
40
  } 
41
}
#7688424
Lesenswert?

Matthias H. schrieb:

Habe das mal so umgesetzt. Habe das Ergebnis erstmal geteilt und ausgegeben.

32 21 -1 -23

Kleine Werte sind es ja, aber was Du da gemacht hast, sehe ich nicht.

Es ist vielleicht etwas der Holzhammer, aber die Tage hatte ich hier das vollständige Programm gezeigt und nicht nur die obigen Schnipsel: Beitrag "Re: Analoges Fahrrad-Tachymeter mit Dynamo betreiben"

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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren