16bit-Software-Timer mit 8bit-Hardware-Timer

Gast #5651399
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.
Gast #5651430
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.
Gast #5651495
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...
Gast #5651597
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.
Gast #5651605
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
Gast #5651607
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.
Gast #5651625
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?
Gast #5651694
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren