Ich brauche einen 16bit-Timer, habe aber nur einen 8bit-Timer frei
(ATMega644). Kann man aus einem 8bit-Hardware-Timer verlässlich einen
16bit-Software-Timer mit zwei Compare-Match-Interrupts machen? Ich habe
den Code, wie ich ihn mir z.Zt. denke, unten hingeschrieben.
Hintergrund: Timer soll 60hz-Halbwelle bzw. 8.3ms zwecks
Phhasenanschnitt in exakt 180 Segmente zerlegen. Compare-Match A soll
den Fire-Impuls zu einem dieser Zeitpunkte einschalten (zeitkritisch),
Compare-Match B 0.2ms später ausschalten (nicht zeitkritisch).
18.4MHz-Quarz => Passender Divider wäre 256 => Timer zählt bis 720 (>
8bit).
1
volatile uint8_t TCNT0_H; // hi byte of 16 bit soft timer, based on 8bit timer 0 (low byte in TCNT0)
2
volatile uint8_t OCR0A_H; // hi byte of 16 bit compare match , based on 8bit timer 0 (low byte in OCR0A)
3
volatile uint8_t OCR0B_H; // hi byte of 16 bit compare match , based on 8bit timer 0 (low byte in OCR0B)
4
5
void
6
timer_init(void)
7
{
8
uint8_t sreg = SREG;
9
10
cli();
11
12
// stop timer 0
13
14
TCCR0A = 0;
15
TCCR0B = 0;
16
17
// disable interrupts
18
19
TIMSK0 = 0;
20
21
// configure timer 0
22
23
TIMSK0 = (1<<OCIE0A) | (1<<OCIE0B) | (1<<TOV0);
24
25
// start timer 0 by setting divider to 256 (one increment = 13.88us)
// stop interrupts before reading lo/hi parts of counter
42
43
cli();
44
45
lo = TCNT0;
46
hi = TCNT0_H;
47
48
SREG = sreg;
49
50
return(((uint16_t)hi)<<8 | lo);
51
}
52
53
// set compare match A for 16bit software timer 0 (based on 8bit hardware timer 0)
54
55
void
56
timer_set_OCR0A(uint16_t value)
57
{
58
uint8_t sreg = SREG;
59
60
// stop interrupts before setting lo/hi parts of match
61
62
cli();
63
64
OCR0A_H = value >> 8;
65
OCR0A = value & 255;
66
67
SREG = sreg;
68
}
69
70
// set compare match A for 16bit software timer 0 (based on 8bit hardware timer 0)
71
72
void
73
timer_set_OCR0B(uint16_t value)
74
{
75
uint8_t sreg = SREG;
76
77
// stop interrupts before setting lo/hi parts of match
78
79
cli();
80
81
OCR0B_H = value >> 8;
82
OCR0B = value & 255;
83
84
SREG = sreg;
85
}
86
87
// interrupt handler for timer overflow
88
89
ISR(TIMER0_OVF_vect)
90
{
91
// this is a software 16bit timer, increment high byte
92
93
++TCNT0_H;
94
}
95
96
// interrupt handler for compare match interrupt A of timer 0
97
98
ISR(TIMER0_COMPA_vect)
99
{
100
// this is a software-implemented 16bit timer, several interrupts may occur until the real match; check if this is the real match
101
102
if (OCR0A_H == TCNT0_H)
103
{
104
...
105
}
106
}
107
108
// interrupt handler for compare match interrupt B of timer 0
109
110
ISR(TIMER0_COMPB_vect)
111
{
112
// this is a software-implemented 16bit timer, several interrupts may occur until the real match; check if this is the real match
113
114
if (OCR0B_H == TCNT0_H)
115
{
116
...
117
}
118
}
Ich vermute man muss wegen der Interrupt-Priorities noch was ändern
(was, wenn Overflow- und Compare-Match-IRQ gleichzeitig kommen und der
Compare-Match wegen der Interrupt-Priorities zuerst ausgeführt wird).
Der 8bit-Timer wird immer im Kreis laufen, das Setzen der nächsten
Compare-Match-A/B-Werte erfordert also Auslesen des Timer-Stands - dafür
die Funktion timer_get_TCNT0(). Zum Zeitunkt, in dem das passiert, ist
der nächste Compare-Match A garantiert deutlich in der Zukunft, es gibt
also Zeitpuffer für etwas Interrupt-Code.
> was, wenn Overflow- und Compare-Match-IRQ gleichzeitig kommen und> der Compare-Match wegen der Interrupt-Priorities zuerst ausgeführt> wird.
Dann werden sie ohne besondere Klimmzüge nacheinander ausgeführt.
sc schrieb:> Ich brauche einen 16bit-Timer, habe aber nur einen 8bit-Timer frei> (ATMega644). Kann man aus einem 8bit-Hardware-Timer verlässlich einen> 16bit-Software-Timer mit zwei Compare-Match-Interrupts machen?
Ja, das ist aber schon ziemlich hohe Kunst, jedenfalls, wenn die
Forderung ist, dass wirklich (timer-)taktgenau die Pins wackeln sollen,
eben so, wie das bei einem echten 16Bit-Timer der Fall wäre und das
unter allen Umständen und in allen Timermodi. Selbst wenn man es auf
FastPWM begrenzt: die allermeisten Probleme (vor allem alle
zeitkritischen) sind auch dann zu lösen.
> Ich habe> den Code, wie ich ihn mir z.Zt. denke, unten hingeschrieben.
Der zeigt vor allem, dass du nicht einmal das Grundprinzip der Timer
verstanden hast. Nein, du kannst mit cli() nicht den Timer anhalten,
dafür interessiert der sich kein bisschen...
UND: Du darfst auch nicht den Timer anhalten, wenn du dein Ziel wirklich
erreichen willst...
> Nein, du kannst mit cli() nicht den Timer anhalten
Wer redet denn von Timer anhalten? cli() verhindert, dass Haupt-Code und
Interrupt-Code gleichzeitig auf globale Variablen zugreifen.
> ATmega1284 mit Timer3.
Hab ich was verpasst? Der ATMega644 bietet Timer 0, 1 und 2, wovon nur
Timer 1 die gewünschten 16bit bietet (brauche ich für andere Zwecke).
Der ATMega1284 hat laut Datenblatt genau die gleichen Timer. Kein Timer
3.
Ups,
da gibt es wohl neuere Datenblätter:
Quelle:
http://ww1.microchip.com/downloads/en/devicedoc/atmel-42718-atmega1284_datasheet.pdfPeripheral Features
– Two 8-bit Timer/Counters with Separate Prescaler and Compare Mode
– Two 16-bit Timer/Counters with Separate Prescaler, Compare Mode, and
Capture Mode
– Real Time Counter with Separate Oscillator
:
Und Kapitel 17. -- TC1/3 - 16-bit Timer/Counter1/3 with PWM
sc schrieb:>> ATmega1284 mit Timer3.>> Hab ich was verpasst? Der ATMega644 bietet Timer 0, 1 und 2, wovon nur> Timer 1 die gewünschten 16bit bietet (brauche ich für andere Zwecke).>> Der ATMega1284 hat laut Datenblatt genau die gleichen Timer. Kein Timer> 3.
Du kannst also nicht nur nicht programmieren, sondern auch keine
Datenblätter lesen...
Also explizit für Dummies: Ja, der Mega1284 hat zwei 16Bit-Timer.
sc schrieb:> Ich brauche einen 16bit-Timer, habe aber nur einen 8bit-Timer frei> (ATMega644).
Da kann dir keiner bei helfen. Vielleicht hast du deine Timer ungünstig
genutzt oder du hast - betriebswirtschaftlich betrachtet - den falschen
Controller. Wieviel kostet ein passendes Stück Silizium verglichen mit
der Arbeitszeit, um das mit einem 8-Bit Timer wasserdicht hinzufummeln.
> Hintergrund: Timer soll 60hz-Halbwelle bzw. 8.3ms zwecks> Phhasenanschnitt in exakt 180 Segmente zerlegen.
Warum musst du die Halbwelle unbedingt in 180 Segmente zerlegen?
Nur weil die Babylonier vor 4000 Jahren mal aus ganz anderen Erwägungen
beschlossen haben, das 60er-System für die Teilung zu verwenden?
Karl M. schrieb:> da gibt es wohl neuere Datenblätter
Das steht seit mindestens 4 Jahren im Datenblatt!
Wolfgang schrieb:> du hast - betriebswirtschaftlich betrachtet - den falschen> Controller. Wieviel kostet ein passendes Stück Silizium verglichen mit> der Arbeitszeit, um das mit einem 8-Bit Timer wasserdicht hinzufummeln.
Vergiss nicht, dass hie viele Hobbybastler unterwegs sind. Da betrachtet
man solche Aufgaben oft als interessante Herausforderung, die es zu
meistern gilt.