Hallo,
ich versuche gerade einen ganz einfachen Timer zu programmieren.
Ausrüstung:
Atmega 8515, 4Mhz Quarz, AVR-Studio, GCC.
Es will einfach nicht funktionieren.
Ich kann mit dem AVR Studio ja schön simulieren und habe festgestellt,
dass die 100 an die Funktion wartems nicht weitergegeben wird. Siehe
Bild1.jpg.
Mir ist der Verdacht aufgekommen, dass eventuell der Simulator Bugs hat
und habe das Programm auf den Controller gespielt. Funktioniert aber
auch nicht.
Habe ich irgend wo was vergessen?
Jürgen
PS: timer.c ist das Hauptprogramm
Hallo
Schau dir mal warteus an. Kommst du da jemals wieder raus.
timer bleibt immer 0 und somit immer kleiner timerus (falls > 0)
Warum werden solche wartezeiten eigentlich immer neu erfunden??
Gruß
Joachim
Joachim schrieb:> Hallo>> Schau dir mal warteus an. Kommst du da jemals wieder raus.> timer bleibt immer 0 und somit immer kleiner timerus (falls > 0)
Das ist nicht der Grund.
timer ist eine globale Variable, die in der ISR erhöht wird.
> TCCR0 &= ~(1<<CS01)|(1<<CS00); // Kein Prescaler
Ein Timer läuft, sobald du einen Prescaler zuweist.
Hat der Timer einen Prescaler von 0, so läuft er auch nicht. Ein Timer
der nicht läuft, zählt auch nicht. Ein Timer der nicht zählt generiert
auch keine Overflows. Keine Overflows, keine ISR. Den Rest kannst du dir
denken
Danke für die Antworten.
ich habe das Programm folgender masen verändert:
1
TCCR0&=~(1<<CS02)|(1<<CS01);// Kein Prescaler
2
TCCR0|=(1<<CS00);
Jetzt funktionierts zwar auf dem Controler aber die Simulation stimmt
immer noch nicht. Auserdem stimmt die Wartezeit nicht. Eine Periode
(Also LED an, LED aus) dauert 1.86s. Deshalb wollte ich ja eine eigene
Routine machen um eine genaue Zeit zu bekommen.
Wo habe ich falsch gedacht?
Jürgen schrieb:> Wo habe ich falsch gedacht?
µC sind zwar schnell. Aber so schnell auch wieder nicht. Du gibst dem
Timer genau 4 Taktzyklen Zeit ehe er den nächsten Overflow auslösen
soll. 4 Takte, da ist der Inhalt deiner ISR schon länger.
Kurz gesagt: Deine Vorgaben sind nicht erfüllbar.
Au´s dem Bauch heraus: 40 Takte ist immer noch verdammt wenig.
Und gewöhn dir den Quatsch mit Vorladen am besten gleich wieder ab, wenn
du halbwegs vernünftige Timings haben willst (zumindest bei einem
Vorteiler von 1). Vom Zeitpunkt wenn der Timer seinen Overflow auslöst,
bis er sich zum ISR Aufruf bequemt, bis du in der ISR die Kontrolle
kriegst ... da vergeht alles Zeit. Zeit in der der Timer in der
Zwischenzeit weitergezählt hat. Zähltakte die du aber nirgends
berücksichtigt. Wenn man eine Timer-ISR braucht, die abweichend von der
Breite des Timers (8Bit oder 16 Bit) aufgerufen wird, dann nimmt man den
CTC-Modus des Timers dafür.
Danke, CTC-Modus, interessant. Wir in der Schule haben immer nur den
einen Timer verwendet. CTC-Modus werde ich mir morgen mal anschauen.
Fühle mich bei euch gut aufgehoben.
Gute Nacht und nochmals Danke.
Hallo,
hab mich jetzt ein wennig reingelesen.
Jetzt funktioniert´s auch. Aber ich weis nicht warum. :-)
1
#include<stdint.h>
2
#include<avr/io.h>
3
#include<avr/interrupt.h>
4
#include"warten.h"
5
#include"var.h"
6
7
ISR(TIMER0_COMP_vect)
8
{
9
timer++;
10
}
11
12
//Hauptprogram
13
14
intmain(void)
15
{
16
//Ein - Ausgänge Definieren
17
18
DDRC=0xff;//PORTC Ausgang (LEDs)
19
PORTA=0xff;//PORTA Pullup aktivieren (Taster)
20
21
DDRD=0xff;//PORTD (Display Daten) auf Ausgang setzten
22
DDRB=0x07;// Asugänge schalten für Display RS/RW/E
23
24
25
// Timer 0 konfigurieren
26
27
//Prescalerkonfiguration
28
TCCR0&=~(1<<CS02)|(1<<CS01);// Kein Prescaler
29
TCCR0|=(1<<CS00);// "
30
31
//CTC Modus aktivieren
32
TCCR0&=~(1<<WGM00);
33
TCCR0|=(1<<WGM01);
34
35
//Output Compare Interrupt erlauben
36
TIMSK|=(1<<OCIE0);
37
38
/*Output Compare Register vorladen mit 40
39
Interrupt Aktion alle (4000000/40 = 1000.000Hz = 10µs
40
ausführen
41
*/
42
OCR0=0x19;
43
44
//Interupt starten
45
sei();
46
47
48
49
while(1)
50
{
51
LED=0x00;
52
wartems(250);
53
wartems(250);
54
wartems(250);
55
wartems(250);
56
LED=0xff;
57
wartems(250);
58
wartems(250);
59
wartems(250);
60
wartems(250);
61
}
62
63
}
Durch rumprobieren habe ich herausgefunden das ich das Register OCR0 mit
HEX 19 also DEZ 25 beschreiben muss um auf die z.B. 1s zu kommen.
Dass würde aber nicht meiner Rechnung entsprechen die folgendermaßen
aussieht: 4.000.000/40 = 100.000 Hz = 10µs.
Mit HEX 19 sieht es aber so aus: 4.000.000/25 = 160.000 Hz = 6,25µs.
Wie kommt das?
Außerdem habe ich nicht ganz verstanden wo der Unterschied zwischen den
beiden Modusen ist. Ich muss doch beide Vorladen.
Auch das simulieren funktioniert nicht. Es kommt immer noch die
Meldung:"Location not valid"
Wo mache ich Fehler?
25 Takte von einem Interrupt zum nächsten ist immer noch sehr eng.
Lass doch dem µC etwas Zeit!
Deine 4Mhz, wo kommen die her?
interner Oszillator, Quarz?
> Außerdem habe ich nicht ganz verstanden wo der Unterschied zwischen> den beiden Modusen ist. Ich muss doch beide Vorladen.
Im CTC lädst du in der ISR den Timer nicht vor.
Der Timer zählt von sich aus nur bis zu einer bestimmten Zahl
> Es kommt immer noch die> Meldung:"Location not valid"
Du hast den Optimizer eingeschaltet und der Optimizer hat die Variable
rausgeworfen, weil er sie nicht braucht.
Karl heinz Buchegger schrieb:> Lass doch dem µC etwas Zeit!
Am Anfang wollte ich eine Routine schreiben um eine Funktion zu haben
Portionsweise 1 µs hochzuzählen.
Jetzt muss ich die Portionen schon erhöhen um 10. Das muss dem doch
reichen!! :-)
Aber im ernst, wie kann ichs besser machen. Und komm mir ja nicht mit
_delay ... . ;-) Genau das möchte ich umgehen. Ich habe gelesen, sobald
ein Interrupt dazwischen kommt, stimmt die Zeit nicht mehr. Deshalb
wollte ich was eigenes machen.
Und da ich die Timer sowieso besser kennen lernen wollte habe ich es als
Übung versucht.
Karl heinz Buchegger schrieb:> Deine 4Mhz, wo kommen die her?> interner Oszillator, Quarz?
externem Quarz.
Karl heinz Buchegger schrieb:> Im CTC lädst du in der ISR den Timer nicht vor.> Der Timer zählt von sich aus nur bis zu einer bestimmten Zahl
Verstanden. Danke.
Jürgen schrieb:> Jetzt muss ich die Portionen schon erhöhen um 10. Das muss dem doch> reichen!! :-)
Wenn du im Büro sitzt und alle 15 Sekunden kommt wer rein und will was
von dir, kriegst du auch deine eigentliche Arbeit nicht mehr auf die
Reihe.
Beschränkst du aber den Zugang zu dir auf alle 5 Minuten, dann geht auch
bei dir was weiter.
>> Deine 4Mhz, wo kommen die her?>> interner Oszillator, Quarz?>> externem Quarz.
ok.
Das erklärt dann nicht den zeitlichen Versatz
>> Im CTC lädst du in der ISR den Timer nicht vor.>> Der Timer zählt von sich aus nur bis zu einer bestimmten Zahl>> Verstanden. Danke.
Der springende Punkt ist:
Der Timer zählt von sich aus exakt die angegebene Anzahl an Takten ab.
Beim vorladen hast du immer einen Versatz drinnen, durch Dinge die du
nicht beeinflussen kannst.
Jürgen schrieb:> Aber im ernst, wie kann ichs besser machen. Und komm mir ja nicht mit> _delay ... . ;-) Genau das möchte ich umgehen.
Das kann man so pauschal nicht sagen.
Das hängt natürlich auch immer von der Taktfrequenz ab.
Bis zu einer gewissen Grenze sind _delay... schon in Ordnung. Vor allen
Dingen, weil du das auch mit einem Timer nicht genauer hinkriegst, ganz
im Gegenteil.
> Ich habe gelesen, sobald> ein Interrupt dazwischen kommt, stimmt die Zeit nicht mehr.
Vor den _delay.. einfach die Interrupts deaktivieren und danach wieder
einschalten.
Ich würde mal aus dem Bauch heraus sagen:
Bis zu ~500µs sind _delay... durchaus verschmerzbar, wenn es nicht im
Programm andere Gründe gibt, warum man auf keinen fall warten möchte.
Denn: Auch ein Timer ist kein Allheilmittel. Vor allen bei kleinen
Zeiten wirds mit einem Timer schin knifflig.
Karl heinz Buchegger schrieb:> Vor allen bei kleinen> Zeiten wirds mit einem Timer schin knifflig.
Das habe ich jetzt auch gemerkt.
Okay, habs jetzt soweit verstanden.
Herzlichen Dank für deine Mühe.