Forum: Mikrocontroller und Digitale Elektronik Interrupt Attiny45


von Tim (Gast)


Lesenswert?

Hallo,
ich habe eine Frage zu meinem Code
1
#define F_CPU 4000000UL
2
#include <avr/interrupt.h>
3
4
int zaehler;
5
6
int main(void) {
7
  DDRB |= (1<<PB0);  //PB0 -> Ausgang  
8
  PORTB &= ~(1<<PB0);  // PB0 -> low 
9
  TIMSK |= (1<<TOIE0);  // Interrupt beim Overflos auslösen
10
  TCCR0B |= (1 << CS01); // prescale = 8
11
  sei();    // Interrupts freigeben
12
13
  while(1){
14
  }
15
16
} 
17
18
ISR(TIM0_OVF_vect){
19
  zaehler++;
20
  if (zaehler==1953) zaehler = 0; // eine Sekunde ist vorbei (1953*0.512=0,99s)
21
  if (zaehler<1) PORTB |= (1<<PB0); //Lasse LED kurz aufblinken
22
  else PORTB &= ~(1<<PB0);
23
24
}

Ich habe gedacht, dass ich alle 0,512ms einen Interrupt auslöse.
Und zunächst jede Sekunde die LED kurz aufblinken lassen. Dies 
funktioniert auch, allerdings wesentlich schneller.

Was habe ich falsch gemacht? Oder wie berechne ich sonst die Zeit eines 
Interrupts?
Bis jetzt habe ich es so gerechnet
t=(2^(Bit des Timers)*Vorteiler)/(Systemtakt in Hz)=(2^8*8)/4000000

von Peter II (Gast)


Lesenswert?

Läuft denn der Tiny mit 4Mhz oder denkst du das nur?

von Tim (Gast)


Lesenswert?

Eigentlich hätte ich gesagt, dass der mit 4MHz läuft, da ich dass ja 
ganz oben so definiert habe. Aber jetzt bin ich mir da nicht mehr so 
sicher, bzw. würde dann fast sagen, dass der das nicht macht. Dann 
müsste der ja (wenn meine Berechnung ansonsten richtig ist) schneller 
laufen.

von Peter II (Gast)


Lesenswert?

Tim schrieb:
> Eigentlich hätte ich gesagt, dass der mit 4MHz läuft, da ich dass ja
> ganz oben so definiert habe

das ist nur eine Info. Damit ändert sich nichts Takt.

Hast du ein Quarz dran? Wie sind die Fuse gesetzt?

In Normalfall müsste er mit 1Mhz laufen
(habe jetzt nicht im Datenblatt nachgelesen)

von kopfkratzer (Gast)


Lesenswert?

kopfkratz
Also ersteinmal Kardinalsfehler bei globalen Variablen und IRQs VOLATILE 
vergessen (hat hier vorerst keine Auswirkungen da Du auch eine lokale 
Variable nehmen könntest) !
Dann wird der Takt nicht im Programm definiert, sondern durch die Fuses 
auf dem Käfer, die mal mit z.B. avrdude auslesen.
Die Formeln für die einzelnen Modi des jeweiligen Timers findest Du im 
Datenblatt.
Daher Datenblatt lesen, den passenden Timer-Modus auswählen und 
programmieren und dann nach der Formel berechnen wie oft der Timer 
durchgelaufen ist bis z.B. eine Sekunde erreicht wird.

von Tim (Gast)


Lesenswert?

Einen Quarz habe ich nicht dran.
Bei Fuses bin ich mir nicht ganz sicher, da ich auch nicht wirklich 
weiss was das ist.
AVRDUDE gibt mir aber folgendes
hfuse 0b11100010
lfuse 0b11011111
leider sagt mir das noch gar nichts. Habe aber jetzt die (hoffentlich) 
passende Seite http://www.mikrocontroller.net/articles/AVR_Fuses dazu 
gefunden

von Tim (Gast)


Lesenswert?

Habe mir die Seite und das Datenblatt angesehen, aber das mit den Fuses 
noch nicht so wirklich verstanden.
Allerdings steht im Datenblatt, dass der Auslieferungszustand mit 8MHz 
ist.
Dann habe ich allerdings noch ein Problem
mit Prescale = 1, bekomme ich einen Interrupt alle
(2^8*1)/8000000Hz=0,032ms
das mach genau 31250 Interrupts für eine Sekunde (ohne komma irgendwas).
1
ISR(TIM0_OVF_vect){
2
  zaehler++;
3
  if (zaehler==31250) zaehler = 0; // -> 1 Sekunde
4
  if (zaehler<15625) PORTB |= (1<<PB0);
5
  else PORTB &= ~(1<<PB0);
6
7
}

Mein erstes Problem ist, dass es trotzdem noch etwas schneller als eine 
Sekunde ist. Noch ist es realtiv egal, da ich es erst einmal mit den 
Interrupts ausprobieren wollte. Wenn ich aber später meine Uhr machen 
möchte, sollte es doch schon etwas genauer sein.

Das zweite Problem ist eher ein verständnisproblem. Das heisst ja, dass 
ich bei einem höheren bit-timer (16bit) wesentlich ungenauer arbeiten 
kann, da
(2^16*1)/8000000Hz=8,192ms
ist das richtig?
Meiner Meinung nach müsste ich wesentlich genauer arbeiten können.

Die dritte Frage ist, was ist ein Kardinalsfehler und IRQs VOLATILE?

von spess53 (Gast)


Lesenswert?

Hi

>Allerdings steht im Datenblatt, dass der Auslieferungszustand mit 8MHz
>ist.

Ja, aber mit gesetzter CKDIV8-Fuse. Das macht dann wieder 1 MHz.

MfG Spess

von Bitflüsterer (Gast)


Lesenswert?

Ein "Kardinalsfehler" ist ein Fehler den ein "Kardinal" (eine Person im 
Kirchenrange eines Kardinals) macht, gemacht hat oder machen wird.

Vermutlich ist ein "Kardinalfehler" (ohne s) gemeint. Ein Haupt-, 
Basis-, Grund- oder auch grundsätzlicher Fehler.

von kopfkratzer (Gast)


Lesenswert?

Tim schrieb:
> Mein erstes Problem ist, dass es trotzdem noch etwas schneller als eine
> Sekunde ist. Noch ist es realtiv egal, da ich es erst einmal mit den
> Interrupts ausprobieren wollte. Wenn ich aber später meine Uhr machen
> möchte, sollte es doch schon etwas genauer sein.
>

Was steht denn im Datenblatt über Prescaler & Co. ?
Welchen Timer-Modus nimmst Du und warum ?

> Das zweite Problem ist eher ein verständnisproblem. Das heisst ja, dass
> ich bei einem höheren bit-timer (16bit) wesentlich ungenauer arbeiten
> kann, da
> (2^16*1)/8000000Hz=8,192ms
> ist das richtig?
> Meiner Meinung nach müsste ich wesentlich genauer arbeiten können.
>

Welche Formel zur Berechnung steht denn im Datenblatt ?
Wie kommst Du auf Deine Formel ?

> Die dritte Frage ist, was ist ein Kardinalsfehler und IRQs VOLATILE?

Lies mal das Tutorial komplett durch:
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Datenaustausch_mit_Interrupt-Routinen

von Tim (Gast)


Lesenswert?

So, habe noch einmal sehr viel gelesen, aber wenn ich ehrlich bin nicht 
allso viel verstanden.
Was steht im Datenblatt über Prescalar?
Der Prescalar dient doch einfach nur als vorteiler oder?
Welchen Timer Modus benutze ich?
Ehrlich gesagt, keine Ahnung. Ich denke aber mal Modus 0
also bei TCCR0A
WGM00=0, WGM01=0, WGM02=0.
Dies ist das sinnvollste, was ich im datenblatt dazu finden konnte.
Da ich es aber nicht im Code hingeschrieben habe, müssten die gleich 
null sein oder?
Zur berechnung habe ich die Formel von
http://www.mikrocontroller.net/articles/AVR-Tutorial:_Timer
(Abschnitt 'Der Vorteiler') verwendet.
Das Tutorial habe ich mir auch angeguckt.
Ich habe jetzt anstelle von
1
 int zaehler;
1
volatile uint8_t zaehler;

hingeschrieben

von Flohzirkus (Gast)


Lesenswert?

Nicht vom Information-Overflow irre machen lassen. Du bist schon auf dem 
richtigen (und sehr steinigen) Weg.

Dein Tiny scheint ja auf 8Mhz internem Takt zu laufen (auch wenn die 
Fuses, die du veröffentlicht hast etwas anderes sagen), also nimm das 
erst einmal als gegeben hin.

Nun möchtest du also mit diesen 8Mhz und dem Weg über einen 
überlaufenden Timer möglichst genau Sekunden zählen. Dabei stößt du auf 
drei Probleme:

1. Je nach Vorteiler ist die Sekunde nicht genau beim Überlauf, sondern 
irgendwann dazwischen erreicht
2. Dein Tiny läuft sicher nicht mit exakt 8Mhz (Datenblatt 21.4.1 
Calibrated Internal RC Oscillator Accuracy), sondern hat eine 
systematische Abweichung
3. Besonders konstant ist dieser Takt auch nicht.

Probleme 1 und 2 kannst du in den Griff bekommen.
Ein 16-Bit-Timer (wenn der Tiny einen hätte) könnte zwar nützlich sein, 
aber es geht auch ohne.

Grundgedanke (ein möglicher Weg von vielen):
- Alle soundsoviel Timerüberläufe ist ungefähr eine Sekunde vorbei, also 
wird ein Sekundenzähler hochgezählt. Allerdings hast du dir 
währenddessen auch einen systematischen Fehler eingefangen. Also zählst 
du auch einen "Fehlerzähler" hoch. Wenn hier ein kritischer Wert 
erreicht ist (ausprobieren und rechnen) spendierst du deinem Timer einen 
zusätzlichen Überlauf (oder eine Überlauf weniger), bevor die nächste 
Sekunde als beendet erklärt wird.

Die Fallstricke, die hier noch lauern (z.B. Variablentypen - signed, 
unsigned, wie groß...) garantieren viel Lernspaß.

Schönes WE
Flohzirkus

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.