Moin,
also erst mal Hallo zusammen.
Zu meinem Problem habe ich schon viel gegoogelt, aber so richtig komme
ich da nicht weiter.
Ich möchte einen ganz einfachen Timer-Interrupt auslösen. Habe dazu auch
das Datenblatt meines ATmega328 zur Hand. Der Code sieht so aus.
OCR0A = 250; //Compare match value 250 (8-Bit-Register)
18
19
TIMSK0 |= (1<<OCIE0A); //Interrupt on compare match
20
21
sei();
22
}
23
24
ISR (TIMER0_COMPA) {
25
PORTD ^= (1<<6);
26
PORTB |= (1<<5);
27
}
28
29
void loop() {
30
31
}
Der Timer soll einfach bis 250 hochlaufen und dann die entsprechende ISR
aufrufen. Aber er springt nicht in die ISR rein.
Wenn ich den Timer mit 'Serial.println(TCNT0)' auslese, wird nur '0'
angezeigt. Der Timer zählt nicht hoch.
Jemand 'ne Idee?
Gruß Maddin
Also die void setup() wird schon automatisch gestartet. Die
Portkonfiguraton wird ja ausgeführt. Kann man ja einfach testen.
Timer1 klappt auch nicht. Liefert die gleichen Symptome. Der Witz ist,
wenn ich die CS-Bits und TIMSK0 nicht setze, also den ganzen Kram
auskommentiere, dann zählt der Zähler wieder.
Im Datenblatt steht TIMER0_COMPA, habe es aber auch mit
TIMER0_COMPA_vect probiert, weil ich dass in diversen Tutorials auch so
gesehen habe.
Ich kann da quasi wild auf den Tasten klimpern, ohne Effekt.
Martin K. schrieb:> Der Witz ist,> wenn ich die CS-Bits und TIMSK0 nicht setze, also den ganzen Kram> auskommentiere, dann zählt der Zähler wieder
So witzig ist das gar nicht. Zum einen benutzt das Arduinosystem
offenbar den Timer. Wurde jedenfalls oben so gesagt. Ich kenn das Ding
nicht weiter. Also muß ich annehmen, daß das richtig ist. Zum anderen
hast du einen falschen Interrut Vektor, genau genommen hast du damit
keine ISR. Ohne ISR macht der Controller einen Reset, wenn er da
reinspringen will.
Jetzt mach mal das hier:
An sowas hatte ich auch schon gedacht. Hab aber keine Ahung, wie man das
beeinflussen kann. Ich habe das ganze auch schon an einem zweiten
Arduino UNO gestestet. Kommt genau das gleiche raus.
Was mir auch aufgefallen ist, dass der Timer1, der ja ein 16-Bit Timer
ist, auch nur bis 255 zählt.
Wenn ich im Setup nicht konfiguriere (ausser einem Port z.B.), und
einfach nur TCNT1 auslese, kommt der nicht über die 255 raus.
Ich habe sogar TCNT1L und TCNT1H einzeln ausgelesen. TCNT1H bleibt immer
auf 0.
Aber immerhin läuft da was, wenn nichts konfiguriert ist.
Ich habe schon den Verdacht, dass das mit der Arduino IDE nicht geht,
warum auch immer.
Ich habe es auch schon mit folgender Schreibweise in der Arduino IDE
versucht:
Also wenn ich das jetzt mit TIMER1 mache und die CS-Bits nicht setze,
klappt es jetzt auch. Allerdings habe ich jetzt kein 50% Rechteck,
sondern irgendwas im Verhältnis 5:1 oder so.
Egal. Klappt auf jeden Fall.
Danke.
Martin K. schrieb:> Also wenn ich das jetzt mit TIMER1 mache und die CS-Bits nicht setze,> klappt es jetzt auch. Allerdings habe ich jetzt kein 50% Rechteck,> sondern irgendwas im Verhältnis 5:1 oder so.>> Egal. Klappt auf jeden Fall.
Nein, da muß 1:1 rauskommen. Entweder es geht oder es geht nicht.
Geht ist 100%, <100% ist geht nicht.
Geben wir dem Arduino die Schuld. Initialisiere den Timer mal so:
Ja.. ich werd das jetzt mal Stück für Stück durchkauen.
Eines weiss ich schon. Es muss auf jeden Fall
ISR (TIMER1_COMPA_vect)
lauten.
ISR (TIMER1_COMPA)
geht nicht.
Aber das hat jetzt mit den CS-Bits nichts zu tun.
Ist aber dann schon ein Fehler im Datenblatt. Da steht
ISR (TIMER1_COMPA).
Auf meinem Oszi kommt da aber jetzt kein 50% Verhältnis raus.
Korrektur wegen Blödheit......
hängt ja auch vom OCR1A-Wert ab. Sorry....
Hab den mal auf 500 erhöht.... sieht schon besser aus
Hallo,
Hast du jetz so wie in deinem Beispiel WGM11 gesetzt oder WGM12 wie
empfohlen wurde?
WGM11 ist nämlich kein CTC sondern Phasenkorrektes PWM beim Timeer1
Martin K. schrieb:> TCCR1A |= (1<<WGM11); //CTC - Mode> //TCCR1B |= (1<<CS12) | (1<<CS11) | (1<<CS10); //PRESCALER 1/1024> OCR1A = 250; //Compare match value 250 (8-Bit-Register)> TIMSK1 |= (1<<OCIE1A); //Interrupt on compare match> sei();
Was ist denn das? Das habe ich dir nicht so geschrieben!
Die Schuldzuweisung an den Arduino ziehe zurück.
Das kann nicht funktionieren. Programmieren ist kein Copy & Paste. Außer
wenn du mein Konfigurationsbeispiel so nimmst, wie es ist.
Also, kopier das so rein, wie es ist. Dann funktioniert das auch.
Und dann guckst du dir die drei verschiedenen Konfigurationen an,
findest die Unterschiede und siehst im Datenblatt nach, warum das so
konfiguriert sein muß und nicht anders.
Martin K. schrieb:> Es scheint wohl eine Rolle zu spielen, wie man den Timer initialisiert,> also die Reihenfolge.
Nein, das ist vollkommen egal.
Das Arduino Zeugs benutzt die Timer für die Arduino Funktionen. Für
millis() und delay() z.B. wird der Timer0 verwendet.
Probiers mal mit dem Tip:
chris schrieb:> Setz doch einfach mal am Anfang von setup() alle Timerregister auf> default Werte zurück (also auf 0).
Dann funktionieren nur, je nach Timer, einige Arduino Funktionen nicht
mehr.
OCR1A = 250; //Compare match value 250 (8-Bit-Register)
3
TIMSK1 = (1<<OCIE1A); //Interrupt on compare match
Da kann ich beim OCR1A einstellen was ich will. Da ändert sich nichts.
Kann die Zeile auch komplett auskommentieren. Hab immer das gleiche
Rechtecksignal. Läuft dann wohl im Normalmode und nicht im CTC Mode.
Das hier geht
ArduinoArduino schrieb:> Dann funktionieren nur, je nach Timer, einige Arduino Funktionen nicht> mehr.
Ja... da hab ich mal was zu gelesen. Man kann auch auf Kosten einer
Arduinofunktionen mit anderen Einstellungen die PWM-Frequenz verändern.
Bzw. für verschiedene PWM-AUsgänge unterschiedliche Frequenzen verwenden
Da gibts nen haufen Zeug zu lernen. Aber bin schon mal froh, dass das
hier geht.
Martin K. schrieb:> Da kann ich beim OCR1A einstellen was ich will. Da ändert sich nichts.> Kann die Zeile auch komplett auskommentieren. Hab immer das gleiche> Rechtecksignal. Läuft dann wohl im Normalmode und nicht im CTC Mode.
Wahrscheinlich deshalb nicht, weil noch irgendwas im TCCR1A-Register
steht.
Also:
1
TCCR1A=0;
Das zweite ist irgendein PWM-Mode. Und das:
TCCR1B |= (1<<CS12) | (1<<CS11) | (1<<CS10); //PRESCALER 1/1024
funktioniert nicht, weil das External Clock ist.
Ja, man muß alle Register zuweisen bzw. die nicht verwendeten löschen.
Ja stimmt. Da muss ich das WGM-Bit setzen, sonst klappt es nicht.
Also TCCR1A |= (1<<WGM11); muss bleiben, sonst kein CTC-Mode. Steht auch
so im Datenblatt.
Aber die CS-Bits brauch ich nicht setzen. Wenn ich mich da an das
Datenblatt halte, klappt es nicht.
Ich denke, ich werde mich mal näher mit dem Bootloader befassen. Habe so
das Gefühl, dass die Einstellungen, die da gemacht werden, auch was
damit zu tun haben, was geht oder nicht geht. Hab schon gelesen, das der
öfter mal Probleme macht.
Hier mal paar Angaben aus dem Datenblatt.
The Timer/Counter can be clocked by an internal or an external clock
source. The clock source is selected by
the Clock Select logic which is controlled by the Clock Select (CS12:0)
bits located in the Timer/Counter control
Register B (TCCR1B). For details on clock sources and prescaler, see
”Timer/Counter0 and Timer/Counter1
Prescalers” on page 138.
Depending on the mode of operation used, the counter is cleared,
incremented, or decremented at each timer
clock (clkT1). The clkT1 can be generated from an external or internal
clock source, selected by the Clock Select
bits (CS12:0). When no clock source is selected (CS12:0 = 0) the timer
is stopped. However, the TCNT1 value
can be accessed by the CPU, independent of whether clkT1 is present or
not. A CPU write overrides (has priority
over) all counter clear or count operations.
Martin K. schrieb:> Also TCCR1A |= (1<<WGM11); muss bleiben, sonst kein CTC-Mode. Steht auch> so im Datenblatt.
Nein, das steht nicht im Datenblatt. TCCR1A muß 0 sein.
Martin K. schrieb:> Aber die CS-Bits brauch ich nicht setzen. Wenn ich mich da an das> Datenblatt halte, klappt es nicht.
Doch. Nur wenn du dich ans Datenblatt hältst.
TCCR1B |= (1<<CS12) | (1<<CS10);
Das ist anders als beim Timer 2.
Mal ein kleiner Tipp am Rande. Das ist nicht nicht "ein Arduino"
sondern ein ATmega328 oder anderer Controller.
Aber das nur voraus. Wenn es um Arduino direkt geht, dann sollte man
immer auf Arduino.cc schauen.
Timer und PWM:
https://www.arduino.cc/en/Tutorial/SecretsOfArduinoPWM
Naja, der Link...
F. F. schrieb:> Timer und PWM:> https://www.arduino.cc/en/Tutorial/SecretsOfArduinoPWM
... ist schon hilfreich. Statt CTC wird hier Fast PWM genommen, und
damit komme ich schon gut weiter. Zumindest habe ich jetzt sinnvollen
Einfluss auf den OCRx und der Prescaler macht auch was er soll. Auch
wenn die Ergebnisse hier auf dem Oszi noch nicht immer plausibel sind.
Aber es geht voran.
So... das Problem ist gelöst.
Ich hab mal die Register für Timer1 unmittelbar nach dem Reset
ausgelesen, also noch bevor irgendwas programmiert wird. Da kommt dann
das hier raus.
Timer1-Register nach RESET
==========================
TCCR1A-Register
---------------
COM1A1 COM1A0 COM1B1 COM1B0 WGM11 WGM10
0 0 0 0 0 1
TCCR1B-Register
---------------
ICNC1 ICES1 WGM13 WGM12 CS12 CS11 CS10
0 0 0 0 0 1 1
TCCR1C-Register
---------------
FOC1A FOC1B
0 0
TIMSK1-Register
---------------
ICIE1 OCIE1B OCIE1A TOIE1
0 0 0 0
Wenn im Register TCCR1B CS11 und CS10 gesetzt sind, bedeutet das
Prescaler = 1/64. Für Prescaler 1/1024 müsseten die Bits do gesetzt
werden.
CS12=1, CS11=0, CS10=0
Wenn ich aber nur das CS12-Bit auf 1 setze, die anderen Bits aber nicht
lösche, dann kommt da 1 1 1 raus. Und da heist es im Datenblatt:
"External clock source on T1 pin. Clock on rising edge."
Gleiches Problem für den TCCR1A-Register. Da steht nacht dem Start das
Bit WGM10 auf 1. Wenn ich jetzt das WGM12-Bit für den CTC-Modus auf 1
setze ohne WGM10 zu löschen, dann habe ich einen unerlaubten Zustand.
Dieser Modus ist laut Datenblatt als "Reserved" deklariert.
Damit ist dann auch klar, warum der CTC-Mode nicht geklappt hat.
Vorher alles löschen, dann Bits richtig setzen, klappt.
Fall gelöst.
> Ich hab mal die Register für Timer1 unmittelbar> nach dem Reset ausgelesen
Eben nicht. Nach dem Reset stehen die Defaultwerte, wie sie im
Datenblatt nachzulesen sind, drin.
> also noch bevor irgendwas programmiert wird.
Davor befindet sich im vorliegenden Fall die Arduino-Ebene, und genau
das war hier das Problem; eine korrekte, also vollständige
Initialisierung löst es.
Martin K. schrieb:> Ich hab mal die Register für Timer1 unmittelbar nach dem Reset> ausgelesen, also noch bevor irgendwas programmiert wird. Da kommt dann> das hier raus.> ....
Nach Datenblatt müsste aber in diesen Registern nach Reset bei allen
Bits 0 drinstehen ("Initial Value").
Also entweder
- läuft da doch ein Stück Programm, das hier was geändert hat, z.B. das
Arduino-"Betriebssystem", das Du nicht siehst,
- hat kein HW-Reset stattgefunden (SW-Reset, also Sprung nach Adresse 0,
macht keinen vollständigen Reset),
- hast Du was Falsches ausgelesen ;-(
Gruß Dietrich
Es steht eben nicht von Anfang an überall 0, so wie im Datenblatt
angegeben. Deshalb ja auch das Problem. Das liegt daran, dass der
Bootloader ein paar Dinge konfiguriert. Der Bootloader richtet eine
PWM-Funktion ein, und zwar eben genau mit den Registern, die nach dem
Start/Reset auf 1 gesetzt werden. Wenn ich die lösche, und den CTC-Mode
aktiviere, steht mir PWM an dem entsprechenden Ports auch nicht mehr zur
Verfügung, welche mit dem entsprechenden Timer arbeiten.
Das gilt für Timer0 und für Timer1 in der Ausgangskonfiguration.
Der Bootloader hat mich hier in die Irre geführt.
Wenn ich nach dem Start alle Bit des Timers lösche und dann so setze,
wie es im Datenblatt steht, dann klappts ja auch.