Die komischen Timer der attinyXXX

Gast #6381082
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.
#6381101
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
Gast #6381158
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...
Moderator #6381185
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.
#6381539
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
}

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