Hallo zusammen!
Ich versuche nun schon seit etwa 3 Stunden den Timer1 meines ATtiny45 (@
1Mhz) dazu zu bringen alle 200ms PB0 ein-/auszuschalten.
Compiler-Fehermeldungen habe ich keine.
1
#include<stdlib.h>
2
#include<avr/io.h>
3
#include<avr/interrupt.h>
4
#include<avr/sleep.h>
5
6
volatileuint8_ti=0;
7
8
ISR(TIMER1_OVF_vect){
9
i++;
10
if(i>200){
11
i=0;
12
PORTB^=(1<<PB0);
13
}
14
}
15
16
intmain(){
17
DDRB|=(1<<PB0);
18
19
TCCR1=(1<<CS13)|(1<<CS11)|(1<<CS10);
20
TIMSK|=(1<<TOIE1);
21
22
sei();
23
24
while(1);
25
return0;
26
}
Da mein Controller bei 1Mhz werkelt müsste doch ein Prescaler von 1024
etwa alle 1ms den Interrupt ausführen? Was hab ich faksch gemacht?
Grüsse C. Schönauer
C. Schönauer schrieb:
> Da mein Controller bei 1Mhz werkelt müsste doch ein Prescaler von 1024> etwa alle 1ms den Interrupt ausführen? Was hab ich faksch gemacht?
Rechne nochmal nach. Ich komme auf 13421,7728 Sekunden statt 200ms. Ich
denke du hast nicht berücksichtigt, dass Timer1 16-Bit breit ist und der
Interrupt beim Overflow kommt.
> Ich versuche nun schon seit etwa 3 Stunden
Mit etwas mehr Geduld (~3,7h) hätte das Programm etwas ausgegeben!
>Da mein Controller bei 1Mhz werkelt müsste doch ein Prescaler von 1024>etwa alle 1ms den Interrupt ausführen?
Timer1 läuft mit 1 MHz/1024 = 976 Hz, d. h. er zählt alle 1.024 ms eins
rauf. Da er das 256 mal machen muss bis es zu einem Overflow Interrupt
kommt, tritt dieser Interrupt alle 0.262144 s auf. Wegen des
Softwareteilers (Variable i) von 200 wird Dein Pin alle 52.4288 s seinen
Zustand ändern.
Fazit: Du bist nur zu ungeduldig.
>Was hab ich faksch gemacht?
Das "k"! :-D Außerdem hast Du auf gut Glück herumprobiert anstatt im
Datenblatt nachzulesen, wie die Timer funktionieren.
@Stefan: Timer1 beim ATtiny45 ist nur 8 Bit breit.
Und das Nonplusultra: CTC-Modus mit Compare-Interrupt bei 10 ms und
diese 10 ms softwaremäßig auf 200 ms runterteilen. Ein Basistakt von 10
ms ist noch für viele andere Sachen prima geeignet, z. B. Tasten
entprellen (200 ms wäre dafür schon zu langsam).
Hallo zusammen,
vielen Dank für die vielen Antworten!
Hab jetzt probiert einen 10ms Interrupt zu programmieren. (Prescaler=64)
OCR1A = 10/(1/1000000*64*1000) => 156
Das gibt mir doch dann folgenden Code:
C. Schönauer schrieb:
> Ist das so korrekt?
Nein
== 1 ==
Lies nochmals im Handbuch über den CTC-Mode nach
-- Das CTC-Flag in TCCR1 muss gesetzt werden
-- Der CTC-Wert steht in OCR1C
OCR1A resp. OCR1B kann also immer 0 sein
== 2 ==
Du verwendest den falschen IRQ-Vektor.
== 3 ==
Anstatt der magischen Zahl 156 tut's auch die Rechnung
1
#define F_CPU 1000000
2
#define IRQS_PER_SECOND 100
3
#define PRESCALE 64
4
5
OCR1C=(uint32_t)F_CPU/IRQS_PER_SECOND/PRESCALE-1;
Beachte, daß F_CPU modulo (IRQS_PER_SECOND*PRESCALE) nicht 0 ist, d.h.
die anvisierte Frequenz wird nicht exakt getroffen.
Johann
>Ist das so korrekt?
Ich würde zum Testen in den i-Teiler einfach noch einen weiteren
Software-Teiler schalten, der durch 5 teilt. Dann Proggi laufen lassen
und gucken ob ne LED an dem Pin brav mit 1 Hz blinkt (genaugenommen
ändert sie ihren Zustand jede Sekunde, blinkt also mit der Frequenz 0.5
Hz). Alternativ: Großer Teilfaktor und mit der Stoppuhr messen.
Dein Interrupt-Intervall ist übrigens nicht genau 10 ms, sondern 9.984
ms. Bei einer Uhrenanwendung würdest Du den Fehler schnell spüren.
Leider lässt sich 10 ms bei 1 Mhz Systemclock mit einem 8-Bit-Timer
schlecht erzeugen. Aber 8 ms ginge exakt, nämlich mit Prescaler 64 und
OCR-Wert 125. Aus 8 ms kannst Du ja auch 200 ms problemlos ableiten.
> * OCR1C berechnet (~156)
Welche Überlegung steckt denn dahinter, den berechneten Compare-Wert in
OCR1C zu schreiben?
Edit: Sehe gerade, dass das von Johann L. kommt. Keine Ahnung, was ihn
da geritten hat.
Zum CTC1-Bit steht im Datenblatt:
"When the CTC1 control bit is set (one), Timer/Counter1 is reset to $00
in the CPU clock cycle
after a compare match with OCR1C register value. If the control bit is
cleared, Timer/Counter1
continues counting and is unaffected by a compare match."
Stefan Ernst schrieb:
> Welche Überlegung steckt denn dahinter, den berechneten Compare-Wert in> OCR1C zu schreiben?>> Edit: Sehe gerade, dass das von Johann L. kommt. Keine Ahnung, was ihn> da geritten hat.
Es ist die Überlegung, das Handbuch zu lesen (ATtiny45, pp. 92):
1
12.3.1 TCCR1 – Timer/Counter1 Control Register
2
Bit 7- CTC1 : Clear Timer/Counter on Compare Match
3
When the CTC1 control bit is set (one), Timer/Counter1 is reset to $00
4
in the CPU clock cycle after a compare match with OCR1C register value.
5
If the control bit is cleared, Timer/Counter1 continues counting and is
Das da?
http://atmel.com/dyn/resources/prod_documents/doc2586.pdf
Auch da steht OCR1C in 12.3.1, hab eben nochmal extra in die
Onine-Version geschaut.
Der CTC-Reset geschieht bei == OCR1C.
Der IRQ-Trigger geschieht bei == OCR1A bzw. == OCR1B. Und da beim Reset
Timer1 auf 0 gesetzt wird, kann man hier einfach OCR1A=0 nehmen.
Hab den Timer auch so am laufen, allerdings mit OCR1B.
Johann
Ja, ja, ich bin der Idiot hier. :-(
Ich hatte das hier offen:
13. 8-bit Timer/Counter1 in ATtiny15 Mode
@ C. Schönauer:
Dann musst du aber auch TIMER1_COMPC_vect nehmen.
Hab grad getestet:
Ob OCR1A = 156 und OCR1C = 156, nur OCR1C = 156 oder nur OCR1A = 156,
macht keinen Unterschied...Muss also was anderes falsch sein.
Die Schaltung stimmt: Wenn ich den uC rausnehme und VCC mit PB0 verbinde
leuchtet die LED.
Stefan Ernst schrieb:
> @ C. Schönauer:> Dann musst du aber auch TIMER1_COMPC_vect nehmen.
Ach, den gib es ja anscheinend gar nicht. Am besten halte ich mich aus
diesem Thread einfach raus. ;-)
@ Stefan Ernst
TIMER1_COMPC_vect gibts leider nicht bzw. mein AVR-GCC kennt's nicht.
Laut der Header-Datei /usr/avr/include/avr/iotnx5.h gibts nur
TIMER1_COMPA_vect (Makro auf "_VECTOR(3)")und TIMER1_COMPB_vect.
_VECTOR(3) würde wieder mit dem Datenblatt (zu TIMSK) übereinstimmen:
"OCIE1A: Timer/Counter1 Output Compare Interrupt Enable
[...] The corresponding interrupt at vector $003 is executed if a
compare matchA occurs. The Compare Flag in Timer/Counter1 is set (one)
in the Timer/Counter Interrupt Flag Register."
C. Schönauer schrieb:
> [...] Muss also was anderes falsch sein.
Möglicherweise hängts auch an den Fuses, zB ein aktivierter WDT der
immer wieder zu einem Reset führt oder ein falsch eingestellter
Prescaler per CLKPR.
Den Port kann man übrigens toggeln via
1
PINB|=(1<<PB0);
was gegenüber dem ^= den Vorteil hat daß es kürzer und vor allem atomar
ist.
Johann
ATtiny25/45/85 + Timer1 + CTC-Modus ist in der Tat ein Kapitel für sich.
Such mal über die Suchfunktion nach dem Thread
"ATtiny25, TimerCounter1, CTC-Mode: Bug?"
von 12/2008 und lies ihn genau durch. Da hatte jemand dieselben Probs.
Die schließlich gefundene Lösung steht auch drin.
Ich dachte, es läuft darauf hinaus, das Ding im PWM-Mode betreiben zu
müssen, um das gewünschte CTC sozusagen als Nebeneffekt zu bekommen (d.
h. die PWM wird zwar erzeugt, aber nicht auf einen Pin geschaltet).
Oder hab ich das falsch verstanden?
Das Problem konnte behoben werden in dem der Code anstatt auf einer
Linux-Maschine auf einer Windows-Maschine mit AVR Studio kompiliert
wurde. Vielleicht funktionierts auch unter Linux wenn ich die
AVR-Studio-Compiler-Flags mal identisch übernehme.
Grüsse
C. Schönauer
PS: Sorry das ich den Thread nochmals aufrolle, dachte es sei gut wenn
später jemand hierrauf zurück kommt