Anfängerfreundliches Timer Tutorial

Mir gefällt, dass das ganze jetzt ein Dreizeiler ist, und der Loop ist noch komplett leer. Da die Timer ja außerhalb des restlichen CPU Ablaufs funktionieren könnte ich im Loop ja jetzt noch so allerhand sogar mit delay() machen. Da muss mir unbedingt noch was einfallen, und wenn es nur ein paar blinkende LEDs sind :wink:

Sich durch das Datenblatt des AVR zu wühlen um die Timer zu verstehen und die Register entsprechend zu beschreiben um zu verstehen was passiert ist schon eine tolle Sache.

Die Loop ist leer (logisch) , schau aber mal was passiert wenn dort ein langer Delay z.b 1000 eingebaut ist.
Laufen die ISR's wirklich weiter ?

Ein Oszi ist für diese Zwecke hilfreich, es muss kein aber kein teureres High Tech Teil sein.
zb. mein uralt Hamek 312 reicht aus, den Zweikanal 312-8 gibt es in der Bucht für 90 Euros

rudirabbit:
Laufen die ISR's wirklich weiter ?

ISRs vielleicht nicht unbedingt. Da bin ich mir jetzt auch nicht sicher.

Aber was hier gemacht wird ist die Pins in Hardware zu schalten. Komplett ohne Software und Interrupts (das Interrupt Enable Bit ist nicht gesetzt!). Das ist das wirklich schöne daran. Es geht alles ohne das Programm zu unterbrechen. Muss es bei diesen relativ hohen Frequenzen auch, sonst würde alle paar µs das der Programmablauf kurz unterbrochen werden.

Das geht auch mit anderen Teilen auf dem AVR. Man kann z.B. Analog/Digital-Wandlungen selbständig durch den Timer oder externe Interrupts triggern lassen. Oder durch den Analog Komparator. Ohne dass man das in einer ISR explizit starten muss.

Da ich immer noch keine Hardware habe zum testen, hätte ich nochmal eine Frage. Weiß einer von Euch, ob ich auf PB0 eine LED anschließen kann, und über Arduino Code per analogWrite ansprechen kann? Oder würde der Arduinoframe für PWM den Timer1 verwenden wollen? Ach ja ich verwende folgenden Core: Google Code Archive - Long-term storage for Google Code Project Hosting.

Grüße Sven

Dazu kann ich jetzt nichts sagen.

Was mir noch eingefallen ist, ist dass da bei der Berechnung des Compare Match Wertes oben ein Fehler drin ist. Die Formel ist:
(gewünschte Zeit * Prozessor-Frequenz / Prescaler) - 1

Das Minus 1 kommt glaube ich daher, dass der Timer erst im nächsten Takt auf 0 zurück gesetzt und nicht sofort bei einem Compare Match. Daher muss man diesen Schritt mitzählen

Danke für die Antwort und den Hinweis mit der Berechnung. Ob das -1 so viel ausmacht wird man sehen. Habe heute gelesen, dass die ATTinys ab Werk schon +-10% der Frequenz Abweichung haben können. Ich werde es aber auf alle Fälle berücksichtigen. Und das mit PWM werde ich einfach am Samstag ausprobieren. In der Hoffnung, dass ich nicht an der Bedienung des Oszilloskops scheitere. Da liegt nämlich seit heute ein DSO203 im Briefkasten. Falls es nicht geht, kann ich ja immer noch selbst ein SoftPWM machen.
Grüße,

Sven

Wenn es mit CTC passt kannst du auch dabei bleiben. Es muss wahrscheinlich nicht unbedingt PWM sein.

Die TSOP Empfänger haben auch selbst nochmal eine Toleranz. Der Frequenzfilter ist ein Bandpass. Wenn man etwas daneben liegt, wird daher das Signal schwächer. Aber in gewissen Grenzen wird es noch detektiert.

Hm, im Moment tut er am Pin 6 (PB1) gar nichts. Das Setzen des pinModes hat wohl funktioniert, da ich an diesem Pin gegen Masse 0V messe, an den anderen Pins bei 5V Versorgungsspannung aber knapp 1,5V. Also hat der Teil des Arduino Cores funktioniert. Dann habe ich noch zum Testen auf Pin3 (PB4) eine LED gehängt, und in den Loop den Blink Scetch kopiert, der funktioniert einwandfrei. Dann habe ich nochmal das ATTiny Handbuch mir geschnappt, und nochmal das Kapitel zu Timer1 durchgeforstet. Ich fand nichts, was ich noch vergessen haben könnte. Anbei mal den Code. Sowohl so, als auch mit leerem Loop tut sich nichts an PB1. Hat jemand noch eine Idee, was falsch sein könnte?

int IR_led = 1;
int led = 4;
void setup()
{
  // Set PB1 as output
  pinMode(IR_led, OUTPUT); 
  pinMode(led, OUTPUT); 
  // Start Timer1 without prescaler. Set CS10
  // Toggle the OC1A output line. Set COM1A0
  // Clear Timer/Counter on Compare Match. Set CTC1
  TCCR1 |=  _BV(CTC1), _BV(COM1A0), _BV(CS10);
  // Set Counter Value to half cycle time
  OCR1A = 105;
}
void loop()
{
  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(300);               // wait for a second
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delay(300);               // wait for a second
}

Grüße,

Sven

TCCR1 |=  _BV(CTC1), _BV(COM1A0), _BV(CS10);

Keine Ahnung wieso das kompiliert. Aber zwischen die Termen muss ein bitweises Oder |

TCCR1 |=  _BV(CTC1)  | _BV(COM1A0) | _BV(CS10);

Ansonsten kannst du als Zwischenschritt mal probieren das Interrupt Enable Bit zu aktivieren und das in einer ISR manuell zu schalten. Dann sieht man immerhin ob der Timer läuft.

Danke! Jetzt leuchtet meine Infrarot LED. Morgen wird die Frequenz geprüft, und versucht die serielle Datenübertragung hin zu bekommen.

Grüße,

Sven

So, nachdem ich Kommas durch | ersetzt habe leuchtet ja die LED, mein Oszilloskop behauptet, dass die LED mit 4,0irgendwas kHz angesteuert wird. Das Oszilloskop ist, neu, ich habe noch nicht viel Ahnung davon, alo ist dieser Wert sehr mit Vorsicht zu geniesen. Auf alle Fälle reagiert der IR Empfänger nicht, aber er reagiert auf eine Fernbedienung mit 38kHz. Dazu habe ich den Datenpin an ein Voltmeter gehängt, und mit der Fernbedienung fällt er ab von5V aauf ca. 3,7V weil das Voltmeter ja nicht schnell genug ist. Bei der IR LED passiert nichts, also scheine ich sehr grob aus dem Raster zu fallen, so dass ich jetzt wirklich einmal von 4,0kHz ausgehe. Falls der Prescaler auf 8 steht, hätte ich sonst 32kHz, das ist mir etwas zu weit außerhalb der Toleranz. Ich setzte jetzt einfach mal prescaler bits, und schaue was passiert.
Ach ja, was passiert mit den Timerbits nach einem Stromausfall, werden die sicher abgenullt, oder kann da mein Fehler liegen, dass irgendein Bit noch einen sinnlosen Wert enthält?

Grüße,

Sven

Die Register werden bei Reset mit 0 initialisiert.

Wenn du sicher gegen willst, mach es so:

TCCR1 =  _BV(CTC1) |_BV(COM1A0) | _BV(CS10);

Ohne das Compound Oder. Geht in diesem Fall, da die anderen Bits nicht verwendet werden.

Wieso das nur 4kHz sind ist mir aber ein Rätsel. Bist du sicher, dass das Ding korrekt mit 8MHz läuft? Wenn du den Prescaler noch höher machst wird es eher langsamer.

Bei 8MHz hat man eine Taktlänge von 125ns. 4kHz wären 250µs. Das ist ein Faktor von 2000!

Ich lade mal nur den Blinkscetch auf den Chip, und stoppe die Zeit für 10mal blinken, dann sehe ich ob er richtig läuft. Habe den Bootloader mit 8MHz schon mehrfach drauf geschoben, aber nie verifiziert. Danke für den Tipp.
Grüße,

Sven

Schau dir mal Seite 95 des Datenblatts an.

Die ganze Taktgeschichte ist etwas komplizierter. Es gibt einmal die System Clock und dann noch eine "Fast Peripheral Clock", wo die 8MHz über eine PPL vervielfacht werden (das steht mal weiter oben).

Timer1 hat zwei Prescaler. Einen 3 Bit Prescaler für die Peripheral Clock, der bei PWM verwendet wird. Somit kommt man da auf bis zu 500kHz. Aber so wie das da angedeutet ist, ist CK gar nicht 8MHz, sondern nur 1,6MHz oder 625ns. Wobei das die 4kHz ohne Prescaler immer noch nicht erklärt.

EDIT:
Siehe auch Seite 94 PLLCSR Register:

The PCKE bit change the Timer/Counter1 clock source. When it is set, the asynchronous clock mode is enabled and fast 64 MHz (or 32 MHz in Low Speed Mode) PCK clock is used as Timer/Counter1 clock source. If this bit is cleared, the synchronous clock mode is enabled, and system clock CK is used as Timer/Counter1 clock source. This bit can be set only if PLLE bit is set. It is safe to set this bit only whenthe PLL is locked i.e the PLOCK bit is 1. The bit PCKE can only be set, if the PLL has been enabled earlier

Also laut dem läuft der Timer doch mit der System Clock (was dann 8MHz sein sollten) wenn das Bit 0 ist. Ich nehme mal an im Arduino Core ist das der Einfachheit halber der Fall.

Dann verstehe ich aber immer noch nicht was das "1,6MHz" auf der nächsten Seite bedeutet

Wow, jetzt wird es langsam Tag. Mit den 1,6MHz. Ich habe wie von Dir vorgeschlagen das komplette Register Wort neu geschrieben, und nicht verodert, also so:

TCCR1 =  _BV(CTC1) |_BV(COM1A0) | _BV(CS10);

Dann hatte ich plötlich eine Schwingung von 16,2kHz und nicht mehr 4kHz. Zusammen mit der Ungenauigkeit der Schwingung des Arduinos kommt ein vergleichsWert von 104 und eine Timer Geschwindigkeit von 1,6MHz hin.
Dachte ich. Dann änderte ich den Wert auf OCR1A auf 20, und ich hatte immer noch 16,2kHz.
Die Hardware Definitionen hatte ich dann als nächstes im Verdacht. Also nochmal neu heruntergeladen, nochmal versucht, wieder 16,2kHz auch mit 20 auf OCR1A.
Neuer ATTiny, wieder dasselbe. also 15,9kHz. Also muss ich jetzt wohl heraus finden, wo der ATTiny Core mir da in die Suppe spuckt.

Grüße,

Sven

Es gibt verschiedene Cores. Versuche vielleicht mal einen anderen. Es gibt anscheinend auch unterschiedliche Cores für den ATtiny84 (84/44/24), bzw. ATtiny85 (85/45/25).

Da kenne ich mich nicht wirklich aus...

Gefunden, jetzt schwingt er mit 38,9kHz. Ich war im Handbuch verrutscht. CTC1 schaltet bei Gleichheit mit OCR1A um, wenn es sich um einen ATTiny15 handelt. Ansosnten wird genullt,

after a compare match with OCR1C register value

Deshalb konnte ich auf OCR1A auch schreiben was ich wollte. Jetzt schreibe ich meine Zeit auf OCR1C, und alles geht. Das war jetzt nervenaufreibend, aber gleichzeitig habe ich mein Oszilloskop kennegelernt. Man wird nicht dümmer....
Grüße und danke,

Sven

Arg! Hatte ich auch nicht gesehen.
Jetzt wo des sagst ist es extrem offensichtlich :frowning:

Bei den Attinys muss man aufpassen. Da ist vieles im Detail anders als bei den großen Prozessoren.

Serenifly:
Da ist vieles im Detail anders als bei den großen Prozessoren.

Ja, vorallem der Preis :wink:

Spaß beiseite, das Handbuch ist so detailliert, das ist Wahnsinn. Leider kann man darin dann auch verloren gehen. Das war nicht das letzte mal, dass ich mit dem Timer1 auf den Attinys gespielt habe, da kann man noch viele Dinge damit tun, bin schon gespannt. PWM will ich mir auf alle Fälle noch anschauen.

So, jetzt kommt das lustigste. Das ganze war für die Katz, da meine serielle Kommunikation zu schnell ist den 38kHz Infrarotempfänger. Jetzt muss ich das ganze mit unmodulierten Impulsen machen.
Grüße,

Sven