Forum: Mikrocontroller und Digitale Elektronik 16bit-Software-Timer mit 8bit-Hardware-Timer


von sc (Gast)


Lesenswert?

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)
26
27
    TCCR0B = (1<<CS02));
28
    
29
    SREG = sreg;
30
}
31
32
// read 16bit software timer 0 (based on 8bit hardware timer 0)
33
34
uint16_t
35
timer_get_TCNT0()
36
{
37
    uint8_t sreg = SREG;
38
    uint8_t lo;
39
    uint8_t hi;
40
41
    // 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.

von Stefan F. (Gast)


Lesenswert?

Ich hätte erwartet dass du in einer Overflow ISR eine 8bit Variable 
hochzählst, die den 8bit Timer-Counter auf 16bit erweitert.

von sc (Gast)


Lesenswert?

Das wäre der Code in ISR(TIMER0_OVF_vect)

von Stefan F. (Gast)


Lesenswert?

sc schrieb:
> Das wäre der Code in ISR(TIMER0_OVF_vect)

Ach, den habe ich übersehen.

von Stefan F. (Gast)


Lesenswert?

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

von S. Landolt (Gast)


Lesenswert?

Für dieses Wochenende keine Lösung, zugegeben, aber vielleicht für 
nächste Woche: ATmega1284 mit Timer3.

von c-hater (Gast)


Lesenswert?

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

von sc (Gast)


Lesenswert?

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

von sc (Gast)


Lesenswert?

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

von Karl M. (Gast)


Lesenswert?

Ups,

da gibt es wohl neuere Datenblätter:

Quelle: 
http://ww1.microchip.com/downloads/en/devicedoc/atmel-42718-atmega1284_datasheet.pdf

Peripheral 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

von c-hater (Gast)


Lesenswert?

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.

von Karl M. (Gast)


Lesenswert?

Hallo sc,

So hat der ATMega644 nur einen Usart, der ATMega644P und ATMega1284P 
davon zwei.

Es gibt immer mal Unterschiede, man kann sie finden.

von Wolfgang (Gast)


Lesenswert?

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?

von sc (Gast)


Lesenswert?

> Ups, da gibt es wohl neuere Datenblätter:

Tatsache. Danke für den Tip!

von Stefan F. (Gast)


Lesenswert?

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.

von Karl M. (Gast)


Lesenswert?

Stefanus F. schrieb:
> Karl M. schrieb:
>> da gibt es wohl neuere Datenblätter
>
> Das steht seit mindestens 4 Jahren im Datenblatt!

Das nennt man Ironie!

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.