Forum: Mikrocontroller und Digitale Elektronik Die komischen Timer der attinyXXX


von Hans (Gast)


Lesenswert?

Hallo,

ich wollte einen Timer so konfigurieren, dass er einen passiven 
Piezo-Buzzer ansteuert. Dazu sollten die Ausgangs-Pins im Idealfall 
folgende Werte annehmen:

Bei TCNT=0: Pin0=LOW Pin1=HIGH
Bei TCNT=49: Pin0=HIGH Pin1=LOW
Bei TCNT=99: TCNT=0 setzen

Das Problem ist hier bei Timer0, dass er, wieso auch immer, OCRA für den 
Top-Wert nimmt. Gleichzeitig nimmt er aber für Pin0 auch OCRA für den 
Compare-Wert, wo er umschalten soll. Ich habe also gar keine Chance, den 
Timer so wie oben gewünscht zu konfigurieren. Habe ich jetzt einfach ein 
Brett vor dem Kopf, oder ist der Timer wirklich braindead designed?

Der Timer1 ist wesentlich aufgebohrter und dort kann ich den Register 
ICR nehmen, um die wrap-around Grenze des Timers festzulegen. Aber 
leider ist der Timer1 schon belegt und ich muss mit Timer0 für meinen 
kleinen Buzzer auskommen.

Wer kann helfen?

PS: Ich verwende den t24a, aber sehr viele tinys nehmen den gleichen 
Timer.

Beitrag #6381095 wurde von einem Moderator gelöscht.
von Bernd B. (bbrand)


Lesenswert?

Das erscheint mir ein wenig umständlich.

Du willst doch nur, dass alle 50 Timer-Takte die Ausgänge OC0A und OC0B 
toggeln.
Dazu sollte es ausreichen, den Timer im CTC-Mode zu betreiben, sowohl 
OCR0A als auch OCR0B auf 49 zu setzen und vorm Start des Timers OC0B auf 
HIGH zu intialisieren.
1
PORTA |= (1 << PA7); // set OC0B
2
OCR0A = 49;
3
OCR0B = 49;
4
TCCR0A = 0b01010010; // CTC mode, toggle OC0A
5
TCCR0B = 0b00000XXX; // and OC0B on compare match

Ich habe es nicht ausprobiert, aber nach meinem Verständnis sollte das 
funktionieren.

Gruß,
Bernd

von Peter D. (peda)


Lesenswert?

Bernd B. schrieb:
> PORTA |= (1 << PA7); // set OC0B

Das geht so nicht, man muß FOC0A/B nehmen.

von Georg M. (g_m)


Lesenswert?

Hans schrieb:
> Ich habe also gar keine Chance, den
> Timer so wie oben gewünscht zu konfigurieren. Habe ich jetzt einfach ein
> Brett vor dem Kopf, oder ist der Timer wirklich braindead designed?

Für solche Zwecke wurde der Timer/Counter type D entwickelt:
"Generating complementary driving signals"

von Stefan F. (Gast)


Lesenswert?

Man kann die Ausgänge auch in einer ISR toggeln.

von c-hater (Gast)


Lesenswert?

Hans schrieb:

> PS: Ich verwende den t24a, aber sehr viele tinys nehmen den gleichen
> Timer.

Nicht nur viele Tinys, auch die meisten Megas.

Bei den Tinys gibt es aber auch welche, die invertierte Timerausgänge in 
Hardware zur Verfügung stellen, da braucht man dann nur einen Kanal des 
Timers, z.B. 25/45/85 oder auch 26 oder auch 261/461/861.

Und es gibt Tinys mit mehr als einem 16Bit-Timer (incl. ICR-Register), 
z.B.: 441/841

Und, wie schon von Georg M. angemerkt, gibt es die neueren Tinys mit 
TypD-Timern.

Also mehr als reichliche Auswahl...

von Yalu X. (yalu) (Moderator)


Lesenswert?

Hans schrieb:
> Das Problem ist hier bei Timer0, dass er, wieso auch immer, OCRA für den
> Top-Wert nimmt. Gleichzeitig nimmt er aber für Pin0 auch OCRA für den
> Compare-Wert, wo er umschalten soll.

Es gibt ja noch OCRB. Damit geht PWM auch in Verbindung mit einer
variablen Zählerobergrenze. Dann wird das Signal eben auf einem anderen
Pin ausgegeben.

Da du aber kein anderes Tastverhältnis als 0,5 benötigst, brauchst du
nicht einmal PWM, sondern kannst wahlweise OC0A oder OC0B (oder auch
beide) bei jedem Zählerdurchlauf toggeln lassen (s. Beitrag von Bernd).
Dabei muss die Timer-Periode die Hälfte der gewünschten Periodendauer am
Ausgang betragen.

Wenn das für dich – aus welchen Gründen auch immer – auch keine Option
ist, hast du eben den falschen µC-Typ ausgewählt. Es liegt in der Natur
der Sache, dass nicht jeder alles können kann.


Stefan ⛄ F. schrieb:
> Man kann die Ausgänge auch in einer ISR toggeln.

Das wird halt etwas unrund. Insbesondere dann, wenn noch weitere
Interrupts im Spiel sind, wird man das vermutlich hören.

von Georg M. (g_m)


Lesenswert?

Wenn nur vereinzelt und kurz gepiept wird, dann geht es auch ohne 
Timer/Counter, nur mit delay.

von Axel S. (a-za-z0-9)


Lesenswert?

Yalu X. schrieb:
> Stefan ⛄ F. schrieb:
>> Man kann die Ausgänge auch in einer ISR toggeln.
>
> Das wird halt etwas unrund. Insbesondere dann, wenn noch weitere
> Interrupts im Spiel sind, wird man das vermutlich hören.

Genau so eine Situation hatte ich bei meinem Platinenbelichter. 
Einerseits den Interrupt für die Abfrage des Drehgebers, andererseits 
der Interrupt für das Pulsen des Buzzers. Ich habe das einfach so 
gelöst, daß ich an den Anfang der Drehgeber-ISR ein
1
sei()
 gesetzt habe. Ohne das hatte ich in der Tat ein komisches Schnarren im 
Buzzer-Signal. Mit ist keine Anomalie mehr hörbar, obwohl die Buzzer-ISR 
hin und wieder verzögert werden wird.

µC ist ein AT90S2313 (ja, der ganz alte). Da hatte ich nur noch Timer0 
ohne CTC-Modus zu Verfügung und lade in der ISR auch noch den Timer neu:
1
/* toggle buzzer pins */
2
ISR(TIMER0_OVF0_vect)
3
{
4
    TCNT0 = 130;
5
    PORTD ^= (_BV(buzzer_pin_a) | _BV(buzzer_pin_b));
6
}

von Hans (Gast)


Lesenswert?

Danke Bernd. Hat so funktioniert. Ich dachte, nur im PWM gibt der 
Controller Signale an den Pins aus. So kann man sich irren.

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.