Hallo, mir raucht schon der Schädel von dem Datenbuch was mir auch nicht weiterhilft mit den Timern. Ich will einfach nur Timer 2: 40khz Frequenz (25us Periode) auf Pin und das war es. Ein Ausschalten auch noch dazu. Hat da jemand vielleicht einfach ein paar Zeilen Code, die ich anpassen kann? Ich blick da nicht mehr durch zwischen Waveform Mode, PWM Mode, Capture, welchen nehme ich denn nun? Gruss, Christian
Toll... ja, aber das nützt nix, ich muss an die Registerebenr dran! Der Arduino Murks bietet da nichts an. Kann ja nicht so schwer sein, auf dem Cortex alles kein Thema, da bin ich schneller fertig als beim Arduino.... 40 khz, d.h. 8E6 Hz : 1 : (199+1) = 40.000 Prescaler = 1 Timer Top bei 199 soweit bin ich schon. Da muss er dann zurücksetzen auf 0 und den Pin toggeln.
Z.B.: CTC mit doppelter Frequenz, 'Compare Output Mode' auf 'Toggle OC2A on Compare Match'.
Ich kann mit solchen Bruchstück-Sätzen leider nicht viel anfangen. Da gibt es noch einiges mehr, was gesetzt werden will. bei jedem anderen uC ist das einfacher als bei Atmel. Wenn eine Periode 25us sind, dann muss er bei 25us schalten und bei 50us einen Auto-Reload machen. Dann habe ich 50% Duty Cycle.
Nein. Bei jedem Compare alle 25us den Pin OC2 togglen. Also von 0 auf 1 und von 1 auf 0. Genau das hat S. Landolt gesagt. Geht im TCCR2A mit COM2A1 und COM2A0
und was mache ich mit diesen Waveform Bits? Wie müssen die gesetztt werden?
Christian J. schrieb: > und was mache ich mit diesen Waveform Bits? Wie müssen die gesetztt > werden? ProTipp (Von Cyberlord zu Mikrosklaven): Das Datenblatt hat ja nicht nur diese Tabellen zu bieten, sondern sogar auch Prosa welche die verschiedenen Modi erklärt. Und ich fühle dass da bei dir etwas Bedarf besteht. > bei jedem anderen uC ist das einfacher als bei Atmel. Natürlich. Wenn man nicht schwimmen kann ist die Badehose schuld. AVR ist da echt ganz ganz doll kompliziert.
:
Bearbeitet durch User
Mann, das kostet mich ein Drittel der Kaffeepause. So ungefähr:
1 | DDRB |= (1<<PB3) |
2 | TCCR2A = (1<<COM2A0) | (1<<WGM21) |
3 | OCR2A = 99 |
4 | TCCR2B = (1<<CS20) |
Ist aber nicht getestet.
S. Landolt schrieb: > Mann, das kostet mich ein Drittel der Kaffeepause. Ja, das kommt davon, wenn man auf dem Handy tippt statt am PC :-) Ist aber schon gut, ich hämmer das heute abend in einen Arduino rein, Oszi dazu und üblicherweise ist nach rund 20 Minuten etwas fertig, was genaudas macht, ohne dass ich mir die Romane aus dem Datenbuch durchlesen muss.
Christian J. schrieb: > die Romane aus dem Datenbuch > durchlesen muss. Haha, das ist Lustig - trial and error! Programmierung. Also ich arbeite streng nach dem Datenblatt und es funktioniert dann immer. Was sollte einem sonst "sagen" wie es geht?
Christian J. schrieb: > Ist aber schon gut, ich hämmer das heute abend in einen Arduino rein, > Oszi dazu und üblicherweise ist nach rund 20 Minuten etwas fertig, was > genaudas macht, ohne dass ich mir die Romane aus dem Datenbuch > durchlesen muss. Warum machst du dann hier überhaupt so lange rum? Oben war Arduino noch Murks. Bist du Wankelmütig? > Kann ja nicht so schwer sein, auf dem Cortex alles kein Thema, da bin > ich schneller fertig als beim Arduino.... Wie kommt es das du das angeblich auf einem Cortex ohne in Datenblättern zu lesen mal so locker machst und beim popeligen AVR scheiterst? Passt doch nicht zusammen. Ich persönlich habe dich in die Schublade "talentlosen Schwätzer" gesteckt.
:
Bearbeitet durch User
Cyblord -. schrieb: > Ich persönlich habe dich in die Schublade "talentlosen Schwätzer" > gesteckt. Da sind wir schon zwei.... keine Ahnung wieso du meinst noch auf meine Beiträge reagieren zu müssen? Na lassen wir das, hier fehlt eindeutig der Ignore Filter.
S. Landolt schrieb: > Mann, das kostet mich ein Drittel der Kaffeepause. > > So ungefähr: >
1 | > DDRB |= (1<<PB3) |
2 | > TCCR2A = (1<<COM2A0) | (1<<WGM21) |
3 | > OCR2A = 99 |
4 | > TCCR2B = (1<<CS20) |
5 | >
|
> > Ist aber nicht getestet. OCR2A = 199 ;-) siehe deinen beitrag von 15:28 Beitrag "Re: Atmega 328 Timer 2: Hilfe für Frequenzerzeugung"
Also ich opfere einen Teil meiner Pause, und ja, musste selbst erst ins Datenblatt schauen, dann solche Reaktion - na, ich wünsche weiterhin viel Erfolg.
S. Landolt schrieb: > Also ich opfere einen Teil meiner Pause, und ja, musste selbst erst ins > Datenblatt schauen, dann solche Reaktion - na, ich wünsche weiterhin > viel Erfolg. Wundert mich auch. Aber talentlos und arrogant geht leider oft Hand in Hand.
Beitrag #5763614 wurde von einem Moderator gelöscht.
S. Landolt schrieb: > Also ich opfere einen Teil meiner Pause, und ja, musste selbst erst ins > Datenblatt schauen, dann solche Reaktion - na, ich wünsche weiterhin > viel Erfolg. Nun komm runter.... danke Dir doch für Deine Mühen. Es funktioniert ja!
Ich hänge es hier nochmal drunter Die unten stehende Kombination von Bits ist die einzige, die mir eine Frequenz von 40khz erzeugt. Alle denkbar anderen haben eine fixe Frequenz von 15.x khz (8 Mhz Takt). Das AVR Datenblatt ist teils schwer verständlich, auch nach x Mal durchlesen blicke ich teilweise nicht durch. Wie man in Foren sieht viele andere allerdings auch nicht. Ich habe ein Rechteck an Pin B3 (Arduino = 11), also an OC2A. Hätte es zwar lieber gern an OC2B aber das habe ich nicht hin gekriegt. Falls es überhaupt möglich ist. zB mit OCRB. Aber bei CTC steht nur OCRA in der Tabelle. Die Frage ist: Was hat dieses WGM22 Bit für eine Bewandnis? Eigentlich sollte es doch gelöscht sein für CTC Mode, oder? Könnte ja auch sein, dass ich den Fast PWM Mode erwischt habe. Auch der hat bei OCRA = TOP seinen Match. In Tabelle 17-8 steht Mode 2: WGM2 = 0, WGM1 = 1, WGM0 = 0 (CTC Mode), Top = OCRA. Wenn man diese "Verallgemeinerung" anlegt steht da für Timer 2 doch WGM22 = 0; WGM21 = 1, WGM20 = 0 Ob da ein x fehlt für die Timer Nummer? Nur kommt da dann nichts aus dem Pin raus. Da ich eine IR Diode dran habe muss sicher gestellt sein, dass beim Abschalten der Pin auf 0 geht. Das scheint nicht immer der Fall zu sein, wenn man den Pin nicht in den Normalmode zurück stellt.
1 | /* Startet oder stoppt den Timer 2 */
|
2 | void Timer2Enable(bool stat) |
3 | {
|
4 | /* OC2B Pin = INT 1 Pin (PD 3)
|
5 | OC2A Pin = MOSI Pin (PB 3)
|
6 | */
|
7 | |
8 | cli(); |
9 | if (stat) { |
10 | OCR2A = 50; // Compare Match A Register auf 40khz |
11 | TCCR2A = (1 << COM2A0) | (1 << WGM20); |
12 | TCCR2B = (1 << WGM22) | (1 << CS20); // Mode 2 CTC Prescaler 1 und Timer starten |
13 | }
|
14 | else { |
15 | TCCR2B = 0; // Prescaler 1 und Timer stoppen |
16 | TCCR2A = 0; |
17 | digitalWrite(11,LOW); // Pin auf 0 setzen |
18 | }
|
19 | sei(); |
20 | }
|
Christian J. schrieb: > OCR2A = 50; > TCCR2A = (1 << COM2A0) | (1 << WGM20); > TCCR2B = (1 << WGM22) | (1 << CS20); In der Reihenfolge steckt ein Problem und lauert nur darauf einen Wahnsinnig zu machen. Ich habe nicht alles geprüft. Aber dieses ist mir aufgefallen! Ob Timer2 davon betroffen ist, weiß ich auch nicht genau. Aber viele AVR Timer sind es. Prüfe also selber die folgenden Aussagen ! Folgende Situation: Der Timer befindet nach dem Reset in Mode0 Der Arduino Startup Code bereitet ihn für PWM vor. Im PWM Mode wird OCR2A gelatscht. Im CTC Mode nicht. Du schreibst also 50 in das Latch. Stellst dann den Mode um. Folge: Der Latchinhalt landet nie im Register. Mit einigen Timern(allen?) führt das zur Totalblockade des AVR
Arduino Fanboy D. schrieb: > Folge: Der Latchinhalt landet nie im Register. Dass er es doch tut lässt sich auf dem Oszi einwandfrei nachvollziehen. Jede Veränderung des Wertes ändert die Frequenz um n * 1/8E6 Schritte. 39,95xx khz erziele ich. Das reicht auch. Nur die Frage: Bin ich überhaupt im CTC Mode ??? Habe noch stur alle relevanten Bits durchprobiert, nur mit dieser Kombination funzt es.
Nein bist du nicht!
> Phasenrichtige PWM
Darum betrifft dich das auch nicht.
Arduino Fanboy D. schrieb: > Phasenrichtige PWM Und womit würde man dann den Duty Cycle einstellen? Bei mir ist der fix 50% mit "Toggle OCRA". PWM heisst ja Puls Weiten Modulation. Für IR sind ca 30% besser als 50% weil weniger Energie verbraucht wird.
Christian J. schrieb: > Die unten stehende Kombination von Bits ist die einzige, die mir eine > Frequenz von 40khz erzeugt. Nein, mit OCR2A = 50 bestimmt nicht. Dein 328 läuft mit 8MHz, d.h. eine Clockperiode dauert 125ns. Du willst alle 25us Pin OC2A toggeln.
1 | DDRB |= (1<<PB3); |
2 | TCCR2A = (1 << WGM21) | (1 << COM2A0); // CTC (MODE_2) + Toggle OC2A |
3 | TCCR2B = (1 << CS20); // Clock(125ns) => Timer2 |
4 | OCR2A = 199; // 125ns * (199+1) = 25000ns = 25us |
5 | TCNT2 = 0; // Reset Timer2 Counter |
Und das war es schon, funktioniert bestimmt, 1000 Mal erprobt.
:
Bearbeitet durch User
Marc V. schrieb: > Und das war es schon, funktioniert bestimmt, 1000 Mal erprobt. Der einzige Unterschied bei dir ist doch das WGM22 Bit weg und dafür das WGM21 rein und der Matchwert 199. Danke, ich probiere es aus!. Aber doch... 40khz kommen bei mir raus, ganz sicher nach gemessen :-) Nur warum das so ist war nicht klar.... 50 ist 200 / 4... also schon mal ein Vielfaches.
Christian J. schrieb: > Und womit würde man dann den Duty Cycle einstellen? Willst du doch gar nicht.... Das ist alles gar nicht ganz so schwer... Nur ausprobieren, dass ist hier die schlechteste aller Lösungswege. Denn die Anzahl der möglichen Permutationen ist erstaunlich groß. Es bleibt dabei: Datenblatt lesen und das so oft und so lange, bis es verstanden ist. Hier eine 16MHz Version. Für 8MHz Arduinos könntest du OCR2A verdoppeln Oder eine passendere Vorteiler/OCR2A Kombination ermitteln.
1 | #include <util/atomic.h> |
2 | #define AtomicSection ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
|
3 | |
4 | |
5 | void setTimer() |
6 | {
|
7 | AtomicSection
|
8 | {
|
9 | TCCR2A = _BV(COM2A0) |_BV(WGM21); |
10 | TCCR2B = _BV(CS21); |
11 | OCR2A = 24; |
12 | TCNT2 = 0; |
13 | }
|
14 | }
|
15 | |
16 | |
17 | |
18 | |
19 | void setup() |
20 | {
|
21 | Serial.begin(9600); |
22 | Serial.println("Start"); |
23 | setTimer(); |
24 | }
|
25 | |
26 | void loop() |
27 | {
|
28 | pinMode(11, OUTPUT); // Burst |
29 | delay(100); |
30 | pinMode(11, INPUT); // Pause |
31 | delay(1000); |
32 | }
|
Christian J. schrieb: > Danke, ich probiere es aus!. Aber doch... 40khz kommen bei mir raus, > ganz sicher nach gemessen :-) Nur warum das so ist war nicht klar.... Christian J. schrieb: > TCCR2B = (1 << WGM22) | (1 << CS20); // Mode 2 CTC Prescaler 1 > und Timer starten Nein, du hast MODE 5 eingeschaltet und das ist laut DaBla: PWM, Phase Correct
Arduino Fanboy D. schrieb: > #define AtomicSection ATOMIC_BLOCK(ATOMIC_RESTORESTATE) Ok. Bringt das hier Vorteile gegenüber sei und cli? Soll ja wohl heissen, dass da kein Int zwischenfunken darf denke ich mal.
Marc V. schrieb: > Nein, du hast MODE 5 eingeschaltet und das ist laut DaBla: > PWM, Phase Correct Ich glaube es euch! Es kam ja das Gewünschte heraus. Nur warum war die Frage.... kriegt man das Signal auch auf dem INT 1 Pin hin?
Beitrag #5783044 wurde vom Autor gelöscht.
Christian J. schrieb: > Arduino Fanboy D. schrieb: >> #define AtomicSection ATOMIC_BLOCK(ATOMIC_RESTORESTATE) > > Ok. Bringt das hier Vorteile gegenüber sei und cli? Soll ja wohl > heissen, dass da kein Int zwischenfunken darf denke ich mal. Ja, es löscht erst das Flag und erzwingt dann, am Ende des Blocks, dass Interrupt Enable Flag wieder auf den alten Stand gesetzt wird. Händisch ist oft/meist fehlerträchtiger, als ein erprobter Automatismus.
Arduino Fanboy D. schrieb: > Händisch ist oft/meist fehlerträchtiger, als ein erprobter Automatismus. Was ist daran fehlerträchtig?
1 | void blabla(void) |
2 | {
|
3 | uint8_t sreg; |
4 | sreg = SREG; |
5 | cli(); |
6 | ...
|
7 | ...
|
8 | ...
|
9 | SREG = sreg; |
10 | }
|
genau so wird das in einer Microchip-App-Note beschrieben.
Harry L. schrieb: > Was ist daran fehlerträchtig? Da bei einem Arduino eh dauernd ein INT läuft ist es auch wumpe den aus und wieder ein zu schalten. Schaltet man ihn ab funktioniert einiges nicht mehr, zb die Serielle nicht, delay usw. usw.
Christian J. schrieb: > Harry L. schrieb: >> Was ist daran fehlerträchtig? > > Da bei einem Arduino eh dauernd ein INT läuft ist es auch wumpe den aus > und wieder ein zu schalten. Schaltet man ihn ab funktioniert einiges > nicht mehr, zb die Serielle nicht, delay usw. usw. Ja und? Man schaltet den ja deshalb auch nicht dauerhaft aus, sondern nur für kritische Abschnitte, die selten länger als wenige µs dauern. "Wumpe" ist das ganz und gar nicht!
Arduino Fanboy D. schrieb: > Im PWM Mode wird OCR2A gelatscht. > Im CTC Mode nicht. > > Du schreibst also 50 in das Latch. > Stellst dann den Mode um. > Folge: Der Latchinhalt landet nie im Register. Äh, warum nicht? > Mit einigen Timern(allen?) führt das zur Totalblockade des AVR Äh, warum? Oliver
Oliver S. schrieb: > Äh, warum nicht? Weil der Latchinhalt erst in das Register geschrieben wird, wenn der Zähler TOP erreicht. Oliver S. schrieb: > Äh, warum? Tja..... Das Problem ist das Latch, in Verbindung mit dem Moduswechsel von PWM auf Compare Match Hier kann ich dir ein Beispiel für eine solche Blockade liefern. Nur Timer init und ISR (es stammt nicht aus meiner Feder, Kritik am Stil wird verpuffen) Geschrieben für Arduino Mega, also ATMEGA2560
1 | // diese Version funktioniert
|
2 | void set_Timer2() // CTC, Mode 2 |
3 | {
|
4 | cli(); // Interrupts ausschalten |
5 | TCCR2A = (1<<WGM21); // set Mode |
6 | TCCR2B = (1<<CS22); // Prescaler 64 |
7 | TCNT2 = 0; // Reset Register |
8 | OCR2A = 249; // Compare |
9 | TIMSK2 = (1<<OCIE2A); // Compare Match A |
10 | sei(); // Interrupts einschalten |
11 | }
|
12 | |
13 | /*
|
14 | // diese Version versagt, totale µC Blockade
|
15 | void set_Timer2() // CTC, Mode 2
|
16 | {
|
17 | cli(); // Interrupts ausschalten
|
18 | TCNT2 = 0; // Reset Register
|
19 | OCR2A = 249; // Compare
|
20 | TIMSK2 = (1<<OCIE2A); // Compare Match A
|
21 | TCCR2A = (1<<WGM21); // set Mode
|
22 | TCCR2B = (1<<CS22); // Prescaler 64
|
23 | sei(); // Interrupts einschalten
|
24 | }
|
25 | */
|
26 | |
27 | |
28 | ISR(TIMER2_COMPA_vect) // Timer 2 Interrupt |
29 | {
|
30 | static bool state = LOW; |
31 | state = !state; |
32 | digitalWrite(pin_T2, state); |
33 | }
|
Harry L. schrieb: > Arduino Fanboy D. schrieb: >> Händisch ist oft/meist fehlerträchtiger, als ein erprobter Automatismus. > > Was ist daran fehlerträchtig?void blabla(void) > { > uint8_t sreg; > sreg = SREG; > cli(); > ... > ... > ... > SREG = sreg; > } > > genau so wird das in einer Microchip-App-Note beschrieben. Kann ja sein! Tausend Fliegen beweisen: Scheiße schmeckt gut! Im Ernst: cli(); ... ... ... SREG = sreg; Man könnte das ein oder andere cli() oder SREG = sreg, versehentlich löschen, falsch platzieren. Bei Blockklammern fallen fehlende Klammern sofort auf. Der Compiler jault erzürnt .... Und durch die (hoffentlich vorhandene) Einrückung sieht man klar und deutlich was zusammen gehört. Also: Es ist grundsätzlich egal, welche Methode man verwendet. Mir, ist allerdings die Block Methode lieber! Und ja, natürlich kann man auch über diese Geschmacksfrage, Glaubenskriege anzetteln.
Arduino Fanboy D. schrieb: > Hier kann ich dir ein Beispiel für eine solche Blockade liefern. Kannst du nicht. "Totale Blockade" gibt es beim ATMega schlicht gar nicht. Das Programm macht nicht das, was der Programmierer sich vorgestellt hat, aber laufen tut das immer. Zudem setzt du in der angeblich fehlerhaften Version 2 Register OCRA vor allen anderen. Das Latch-Problem kann da also gar nicht auftreten. Natürlich kann das ein Problem sein, wenn man eins der gelatchten Register erts nach der Anwahl des Timermodus schreibt. Der Wert wird dann erst beim nächsten BOTTOM/TOP geupdated, oder wann auch immer in dem Modus das Register geupdated wird. Je nachdem, was man da vorher in die Register geschrieben hat, passiert das eventuell gar nicht, wobei mir dazu beim OCR jetzt erst einmal kein Fall einfallen will. Eine Blockade tritt da aber niemals auf. Oliver
:
Bearbeitet durch User
Oliver S. schrieb: > Das Latch-Problem kann da also gar nicht auftreten. Irgendwas hast du da noch nicht ganz verstanden. Oliver S. schrieb: > Eine Blockade tritt da aber niemals auf. Getestet? Warum nicht? Die genannten Bedingungen eingehalten?
Arduino Fanboy D. schrieb: > Oliver S. schrieb: >> Das Latch-Problem kann da also gar nicht auftreten. > Irgendwas hast du da noch nicht ganz verstanden. Äh, doch. > > Oliver S. schrieb: >> Eine Blockade tritt da aber niemals auf. > Getestet? > Warum nicht? > Die genannten Bedingungen eingehalten? Natürlich. Es passiert - nix. Der Prozessor läuft in seiner Programmende-Endlosschleife fröhlich vor sich hin. Der Timer macht halt, was man ihm sagt, und nicht, was sich der Programmierer wünscht. Von totaler Blockade aber keine Spur. Oliver
Oliver S. schrieb: > Äh, warum nicht? > >> Mit einigen Timern(allen?) führt das zur Totalblockade des AVR > > Äh, warum? >> Irgendwas hast du da noch nicht ganz verstanden. > Äh, doch. Äh stört Dich dieser Sprachfehler nicht? Äh mir würde das maximal auf's Schwein gehen! SCNR
Oliver S. schrieb: > Natürlich. Es passiert - nix. Ok, das nix nehme ich zurück. avrlibc baut ein cli vor die Endlosschliefe. Mit einem while(1) im main wird in beiden Verisonen die ISR angesprungen. Oliver
Marc V. schrieb: > Und das war es schon, funktioniert bestimmt, 1000 Mal erprobt. Ja, es funzt,. mit 20.3 khz :-) Mit 99 passt es, 39,97khz.
Christian J. schrieb: > Ja, es funzt,. mit 20.3 khz :-) Mein Fehler, für 40KHz am OC2A muss der Pin alle 12,5us toggeln, nicht alle 25us. Demzufolge muss OCR2A 99 und nicht 199 sein.
:
Bearbeitet durch User
Marc V. schrieb: > Mein Fehler, für 40KHz am OC2A muss der Pin alle 12,5us toggeln, > nicht alle 25us. Hast du auch ne Lösung für schnelle Stop/Starts? Den Takt abklemmen mit CS0. Für IR muss aber auf jeden Fall dann PB3 auf low gehen.
S. Landolt schrieb: > Ohne Kommentar. Ja, PWM Mode.... kein CTC. Siehe WGM22. Kommt aber das Gleiche bei rum.
Und genau der Kommentar ist falsch: "fast PWM mit top=OCR2A" muss das heißen.
Landholts Lösung ist für mich besser, da ich damit den DC absenken kann denke ich. 30% reichen. TCCR2A = 0; TCCR2B = 0; Kannst noch rauswerfen, die nächsten Befehle sind ja Zuweisungen,.
Ich habe keine Ahnung vom Arduino, wegen dieser Latch-Geschichte nach dem Arduino-Setup wollte ich sicher sein, dass es funktioniert.
Ich will dich nicht schocken aber dein Code, copy & paste grad ausprobiert erzeugt leider nichts. Nacktes Pro Mini Board aus der Tüte. Nur einen High Pegel auf dem PB3 Pin. Nehme ich WGM22 wieder rein kommt 40khz aber OCR2B hat keinerlei Auswirkungen. Ok, Fehler suche ich jetzt aber nicht mehr, muss noch bügeln.....
Wer, bitte, redet von PB3? Sie wollten OC2B = D3.
S. Landolt schrieb: > Wer, bitte, redet von PB3? Sie wollten OC2B = D3. Ok..... da kommt dann auch was.
Christian J. schrieb: > Hast du auch ne Lösung für schnelle Stop/Starts? Den Takt abklemmen mit > CS0. Für IR muss aber auf jeden Fall dann PB3 auf low gehen. Was heißt schnell ? Nachdem du einmal Init gemacht hast: STOP:
1 | TCCR2B = 0; |
2 | PORTB &= ~(1<<PB3); |
Das braucht selbst beim GCC nur 2+2 Takte, da meistens r1 dazu genommen wird und dessen Inhalt ist normallerweise immer 0. Erneuter START:
1 | TCCR2B = (1 << CS20); |
Das braucht 3 Takte.
:
Bearbeitet durch User
Arduino Fanboy D. schrieb: > cli(); // Interrupts ausschalten > TCNT2 = 0; // Reset Register > OCR2A = 249; // Compare > TIMSK2 = (1<<OCIE2A); // Compare Match A > TCCR2A = (1<<WGM21); // set Mode > TCCR2B = (1<<CS22); // Prescaler 64 > sei(); Schießt den uC tatsächlich völlig ab. Der ist nirgendwo mehr. Öfter mal was Neues.... beim ARM käme wohl eine "Hard Fault Exception" aber beim AVR328P eher nicht. Die nachfolgende Blink Routine wird gar nicht mehr erreicht und ein Reboot Findet auch nicht statt. Nur der WDT holt ihn wieder raus.
Kein schöner Anlass.. Aber dennoch herzlichen Dank, für die Rückkopplung.
Christian J. schrieb: > Schießt den uC tatsächlich völlig ab. Der ist nirgendwo mehr. Mal rein interessehalber: Woran siehst du das? Oliver
> Schießt den uC tatsächlich völlig ab.
Sagen wir lieber "den Arduino" statt "den uC"; und wenn die
Arduino-Umgebung nicht einen ganz ungewöhnlichen Kunstgriff in der ISR
für OCIE2A verwendet, so läuft das Hauptprogramm sehr wohl weiter, aber
extrem langsam, immer nur ein einziger Befehl pro ISR-Aufruf.
Hi
>Schießt den uC tatsächlich völlig ab. Der ist nirgendwo mehr.
Dann macht entweder die Arduino-Software total Mist oder du hast einen
anderen Fehler.
Wenn ich die Initialisierung mit diese Werten in Assembler mache,
springt der Controller wie gewünscht in den TIMER2_COMPA-Interrupt und
gibt eine Frequenz von 250Hz aus.
MfG Spess
Arduino Fanboy D. schrieb: > Das Problem ist das Latch, in Verbindung mit dem Moduswechsel von PWM > auf Compare Match Kannst du mal für mein Verständnis ein vollständiges Programm zeigen? Denn in deinem Beispiel sehe ich gar kein PWM-Mode, da wird der Timer von was auch immer auf CTC Mode (nur WGM21=1) eingestellt. "Was auch immer" war bei meinem Test Normal-Mode nach Reset. Oliver
:
Bearbeitet durch User
an Spess:
1 | sbi DDRB,0 ; Blink-LED |
2 | |
3 | ldi tmp0,(1<<WGM20) |
4 | sts TCCR2A,tmp0 ; hier auskommentieren |
5 | |
6 | ldi tmp0,249 |
7 | sts OCR2A,tmp0 |
8 | ldi tmp0,(1<<OCIE2A) |
9 | sts TIMSK2,tmp0 |
10 | ldi tmp0,(1<<WGM21) |
11 | sts TCCR2A,tmp0 |
12 | ldi tmp0,(1<<CS20) |
13 | sts TCCR2B,tmp0 |
14 | sei |
15 | |
16 | main_loop: |
17 | rcall wait100ms |
18 | sbi PINB,0 |
19 | rjmp main_loop |
Lassen Sie dies hier mal laufen, und anschließend das erste 'sts TCCR2A,tmp0' auskommentieren.
S. Landolt schrieb: > Sagen wir lieber "den Arduino" statt "den uC"; und wenn die > Arduino-Umgebung nicht einen ganz ungewöhnlichen Kunstgriff in der ISR > für OCIE2A verwendet, Ich habe da keine wiss. Untersuchung gemacht. Ein Dauer INT Feuer, weil ein Bit nicht zurück gesetzt wurde legt auch jede CPU lahm, auch den ARM. Und die Arduino IDE setzt hauptsächlich den Frame über den Code namens setup und loop. Zudem wird Timer 0 für Millis gebrauchtr. Alles was aber in den Routinen steht, da ist nur der GCC für zuständig. Ich kenne auch den Startup Code nicht, geschweige denn weiss ich nicht, ob da Default INT Handler installiert sind. Möge sich damit jemand befassen, der Spass daran hat. zb mit AVR Studio und einem echten Debugger am JTAG Port. Das habe ich alles nicht.
Aber Sie verstehen nun, weshalb ich vorsichtshalber das Nullsetzen von TCCR2A und B voranstellte.
an Spess: Pardon, da fehlte natürlich noch so etwas wie
1 | .org OC2Aaddr |
2 | reti |
S. Landolt schrieb: > Aber Sie verstehen nun, weshalb ich vorsichtshalber das Nullsetzen von > TCCR2A und B voranstellte. Nein. Nur wenn da Mechanismen am Werk sind, die irgendein Schaltwerk bedienen. Register sind ja keine RAM Variablen, sondern Hardware Latches mit Leitungen dran von und zu irgendwelchen Peripherien. Auch beim ARM gibt es solche, die in einer bestimmten Reihenfolge gesetzt werden müssen, obwohl dieses im ersten Moment unsinnig erscheint. Um das zu ergründen müsste man den VHDL Code des AVR haben und den im Simulator laufen lassen. Und ich nehme an, dass der nicht Open Source ist. Errata steht nix drin: https://www.kitronik.co.uk/pdf/46101_atmega328_summary.pdf
Mit dem Nullsetzen der TCCR2_ wird der Timer2 in den Normalmodus zurückversetzt, damit ist das Problem aus der Welt.
Hi >Lassen Sie dies hier mal laufen, und anschließend das erste 'sts >TCCR2A,tmp0' auskommentieren. Mit dem sts kommen ca. 165kHz und ohne ca. 16kHz heraus. Und weiter? MfG Spess
Christian J. schrieb: > Errata steht nix drin: > https://www.kitronik.co.uk/pdf/46101_atmega328_summary.pdf So isses. Da das Datenblatt zu dem Thema Reihenfolge auch nichts weiter sagt, kann das höchstens eine Fehler im Prozessor sein, aber kein genrelles Latch-Problem. Und nochmals meine Frage: Woran hast du gesehehn, daß der Prozessor "nirgends mehr" ist? Oliver
an Spess: Das Problem besteht darin, dass im einen Fall der Wert für OCR2A nie übernommen wird, folglich permanent die ISR aufgerufen wird.
Beitrag #5784244 wurde vom Autor gelöscht.
Dieses Thema wurde vor geraumer Zeit hier schon einmal diskutiert, aber ich bin unfähig, das wiederzufinden.
Ok.... Ich glaube ich muss einen kleinen Rückzug machen! Denn das Problem ist gerade auch bei mir nicht reproduzierbar. Schade eigentlich, den original Testcode habe/finde ich nicht mehr. Den mit der Totalblockade. Hinter der Totalblockade muss ich jetzt also ein deutliches Fragezeichen platzieren. Was allerdings weiterhin gültig bleibt: Der OCR2A Wert wird nicht übernommen. Das gilt auf jeden Fall für den Timer2 vom ATMEga328P und ATMega2560
1 | OCR2A = 50; |
2 | TCCR2A = (1<<WGM21); |
3 | TCCR2B = (1<<CS22); |
> > In der Reihenfolge steckt ein Problem und lauert nur darauf einen > Wahnsinnig zu machen. > > .... Folgende Situation: > > Der Timer befindet sich nach dem Reset in Mode0 > Der Arduino Startup Code bereitet ihn für PWM vor. > > Im PWM Mode wird OCR2A gelatscht. > Im CTC Mode nicht. > > Du schreibst also 50 in das Latch. > Stellst dann den Mode um. > Folge: Der Latchinhalt landet nie im Register.
> TCCR2B = (1<<CS22);
Was passiert, wenn statt des Vorteilers 64 (CS22) der Vorteiler 1 (CS20)
genommen wird?
Oliver S. schrieb: > Kannst du mal für mein Verständnis ein vollständiges Programm zeigen? > Denn in deinem Beispiel sehe ich gar kein PWM-Mode, da wird der Timer > von was auch immer auf CTC Mode (nur WGM21=1) eingestellt. > > "Was auch immer" war bei meinem Test Normal-Mode nach Reset. Den komplett blockierenden Code finde ich gerade nicht. Ist allerdings auch ein Arduino Programm gewesen, weiß nicht ob dir das dann helfen würde. Der Arduino Startupcode erzeugt folgenden Timer2 Zustand:
1 | // Arduino Startup Code Fragment
|
2 | TCCR2A = 1; |
3 | TCCR2B = 4; |
4 | TCNT2 = 51; // ca. zaehlerstand zum Zeitpunkt des Eintritts in die Main loop |
5 | TIMSK2 = 0; |
6 | OCR2A = 0; |
Gilt für Mega2560 und 328P, TCNT2 unterscheidet sich geringfügig
S. Landolt schrieb: >> TCCR2B = (1<<CS22); > > Was passiert, wenn statt des Vorteilers 64 (CS22) der Vorteiler 1 (CS20) > genommen wird? Ja, so sieht es stehend aus Die Serielle Ausgabe kann sich gerade noch eine 0 abquetschen, dann nichts mehr. Auch wieder Mega2560 und 328P identisches Verhalten.
1 | |
2 | void setTimer2() // CTC, Mode 2 |
3 | {
|
4 | cli(); // Interrupts ausschalten |
5 | TCNT2 = 0; // Reset Register |
6 | OCR2A = 249; // Compare |
7 | |
8 | TIMSK2 = (1<<OCIE2A); // Compare Match A |
9 | TCCR2A = (1<<WGM21); // set Mode |
10 | TCCR2B = (1<<CS20); // Prescaler 1 |
11 | //TCCR2B = (1<<CS22); // Prescaler 64
|
12 | sei(); // Interrupts einschalten |
13 | }
|
14 | |
15 | |
16 | |
17 | |
18 | void setup(void) |
19 | {
|
20 | Serial.begin(9600); |
21 | DDRB |= (1 << PB7); // LED an ArduinoMega Pin 13 |
22 | setTimer2(); |
23 | }
|
24 | |
25 | void loop(void) |
26 | {
|
27 | Serial.println(millis()); |
28 | delay(500); |
29 | }
|
30 | |
31 | |
32 | |
33 | ISR(TIMER2_COMPA_vect) // Timer 2 Interrupt |
34 | {
|
35 | PINB = (1 << PB7); // toggle |
36 | }
|
Kannst du mal TCNT2 = 0; // Reset Register auskommentieren? Oliver
Oliver S. schrieb: > auskommentieren Done! Resultat: Kein Änderung. > Ja, so sieht es stehend aus An dem Toggel Pin stehen 250kHz Rechteck an
Nachtrag So wie ich es jetzt sehe: Die Interrupt Priorität von Timer 2 ist höher als die die von Timer0 (delay,millis) und auch höher als die von der UART. Also kommen beide nicht mehr dran. So entsteht der Eindruck des völligen Stillstands. Richtig so?
Arduino Fanboy D. schrieb: > ISR(TIMER2_COMPA_vect) // Timer 2 Interrupt > { > PINB = (1 << PB7); // toggle > } Aha...
:
Bearbeitet durch User
Arduino Fanboy D. schrieb: > Richtig so? Das ist zwar richtig, aber wie Tim schon anmerkte, müsste der PB7 trotzdem togglen. Die ISR sollte ja aufgerufen werden. Oliver
:
Bearbeitet durch User
Oliver S. schrieb: > wie Tim schon anmerkte, müsste der PB7 > trotzdem togglen. Die ISR sollte ja aufgerufen werden. Ja, das ist auch so... Welches bei 16MHz Takt zu einem ca. 250kHz Rechteck am Pin führt. Der LA zeigt es. Der LED_BULITIN (an PB7) sieht man es nicht an. Schätze mal, dass der Operationsverstärker da nicht mit kommt. Ja, der Arduino Mega und UNO hat einen Operationsverstärker zwischen LED und Prozessor Pin, damit die LED das Signal nicht belastet, wenn der Pin als Eingang genutzt werden soll. Was den Eindruck des Stillstands verstärkt.
Was insofern gut ist, als daß es tatsächlich keinen "Stillstand" gibt. Passiert das auch mit Timer 3? Oliver
Oliver S. schrieb: > Passiert das auch mit Timer 3? Bisher nicht getestet... Timer0 bis Timer2 sind betroffen. Also vermutlich auch Timer 3 Einfach ins Datenblatt schauen. Dürfte reichen. Wenn OCRXY gelatched ist, wird es ihn auch betreffen.
Wenn es nur Timer 2 gewesen wäre, könnte das auch noch mit dessen Asynchron-Funktionalität zusammenhängen. Aber wenn 0 und 1 auch betroffen snd, dann wirds bei allen Timer so sein. Ist aber m.E. immer noch ein Fehler, der in die Errata gehört, und kein generelles Latch-Problem. Oliver
Beitrag #5784378 wurde von einem Moderator gelöscht.
Beitrag #5784387 wurde von einem Moderator gelöscht.
Wie auch immer... Meinen Dank an euch! Vorher war mir klar: Initialisierungsreihenfolge beachten, sonst evtl. derbe Probleme. Jetzt habe ich ein deutlicheres Bild davon, was wirklich passiert. Und warum es diese Probleme gibt. Danke!
> Fehler, der in die Errata gehört
Was sollte Atmel/Microchip dort schreiben?
Für mich ist es ein typischer Programmierfehler, der nur deshalb leicht
tückisch ist, weil hier zwei "Programmierer" arbeiten, einmal die
Arduino-Umgebung und dann der eigentliche Programmierer.
Das ist kein Programmierfehler, und es hat nichts mit Arduino zu tun. Das Datenblatt gibt keine Reihenfolge der Initialisierung vor. Natürlich sollte beim Umschalten von einem gelatchten auf einen ungelachten Modus das entsprechend Register aus dem Latch geupdated werden, wenn da ein noch nicht geschriebener Wert drinsteht. Das ist ein klarer Implementierungsfehler (wenn es denn ohne Reihenfolge funktionieren sollte), oder ein Fehler im Datenblatt, wenn es eine bestimmte Reihenfolge benötigt. Oliver
> beim Umschalten von ... Modus ... geupdated
Zugegeben, das wäre eine Möglichkeit. Trotzdem bin ich der Meinung, dass
das etwas viel verlangt ist von der Hardware, nur wegen eines solchen
Sonderfalles. Und aus dem Datenblatt lässt es sich herauslesen, mit ein
wenig Mühe.
S. Landolt schrieb: > Und aus dem Datenblatt lässt es sich herauslesen, mit ein > wenig Mühe. Na ja, man kann da alles mögliche hineininterpretieren. Da steht: "The OCR2x Register access may seem complex, but this is not case. When the double buffering is enabled, the CPU has access to the OCR2x Buffer Register, and if double buffering is disabled the CPU will access the OCR2x directly." Da steht natürlich nicht, daß bei einem Mode-Wechsel (der ein Normal- und kein Sonderfall ist) Buffer und Register synchronisiert werden, es steht aber auch nicht da, daß dies nicht geschieht. Das wäre aber durchaus erwähnenswert. Statt dessen stehen breit und ausführlich die eigentlich nicht erwähnenswerten Fälle drin, daß ein Compare-Match bei einen Wert größer TOP niemals triggert, oder daß ein ein neuer Top-Wert kleiner als der aktuelle Zählerstand erst im nächsten Timerzyklus triggert. Oliver
S. Landolt schrieb: > Und aus dem Datenblatt lässt es sich herauslesen, mit ein > wenig Mühe. Mit am erstaunlichsten finde ich daran, dass der OCR2A Wert (falsch?) auslesbar ist! OCR2A = 0; PWM mode aktivieren OCR2A = 200; Compare Match aktivieren Danach: Beim OCR2A auslesen bekommt man die 200 gereicht. Obwohl der Timer mit einem OCR2A == 0 arbeitet. Das scheint mir dann doch schon sehr gemein zu sein. Und hätte ein Sprüchlein im Datenblatt verdient.
> hätte ein Sprüchlein im Datenblatt verdient
Vielleicht dieses hier?
"When the double buffering is enabled, the CPU has access to the OCR2x
Buffer Register ..."
Betonung auf 'Buffer-'.
"Gemein" oder nicht, ich kann nichts dafür und kann's auch nicht ändern.
Arduino Fanboy D. schrieb: > Compare Match aktivieren Offiziell heisst der CTC. S. Landolt schrieb: > "Gemein" oder nicht, ich kann nichts dafür und kann's auch nicht ändern. Sacht ja keiner. Aber im CTC-Modus hat die CPU direkten Zugriff aufs Register, liest da 200, der Timer arbeitet aber mit 0. Das ist nicht einfach nur im Datenblatt ungünstig beschrieben oder gemein, daß ist ein Fehler. Oliver
:
Bearbeitet durch User
Okay, eben ausprobiert, und - Arduino Fanboy & Oliver S., ich sei, gewährt mir die Bitte ...: Dass im CTC-Modus, also einem ungepufferten, beim Auslesen nicht der aktuelle Stand von OCR2A zurückgegeben wird, betrachte auch ich als (gemeinen) Fehler.
S. Landolt schrieb: > gewährt mir Gewährt! --------- Ich beantrage den Namen "Ugly timer trap" für diesen doch sehr seltsamen Effekt.
Beitrag #5784863 wurde von einem Moderator gelöscht.
Weiss von euch Arduino Experten jemand wie man den Serial.print auf eine andere Funktion umleitet? Der geht ja auf die Hardware Uart. Oder eine vergleichbare Funktion aufsetzt? Ich verwende nur 2 Möglichkeiten serial.print("Text..."); und serial.print(buffer); Ich habe aber eine IR Diode. Und das F Makro funktioniert nicht, wenn man zb nimmt SendIRString(char* text) Gibt es da einen Trick? Bisher sieht es so aus /* Sende einen 0 terminierten String per IR */ void SendIRString(char* text) { while (*text) SendIRByte(*text++); SendIRByte(0); } IRLED ist mit einer Handykamera so eben zu sehen, die dimmt auch munter drauf los. ich könnte alles auf sprintf_P umschreiben aber das wäre eine irre Arbeit. Mache ich nur bei komplexen Ausgaben.
1 | #include <Streaming.h> // findest du schon... ;-) |
2 | // ist nicht unbedingt nötig, erlaubt allerdings das Streaming
|
3 | |
4 | |
5 | |
6 | |
7 | |
8 | struct IrZeugs: Print |
9 | {
|
10 | virtual size_t write(uint8_t value) |
11 | {
|
12 | SendIRByte(value); |
13 | return 1; |
14 | }
|
15 | };
|
16 | |
17 | |
18 | IrZeugs ir; |
19 | |
20 | |
21 | |
22 | |
23 | void setup() |
24 | {
|
25 | |
26 | // Streaming
|
27 | ir << F("sende dieses ") << "jenes" << 42 << '\0'; |
28 | |
29 | |
30 | // alternativ:
|
31 | ir.print(F("sende dieses ")); |
32 | ir.print("jenes"); |
33 | ir.print(42); |
34 | ir.write(0); |
35 | }
|
36 | |
37 | void loop() |
38 | {
|
39 | |
40 | }
|
Arduino Fanboy D. schrieb: > #include <Streaming.h> // findest du schon... ;-) > // ist nicht unbedingt nötig, erlaubt allerdings das Streaming Funzt :-) Nur ein Prototypen Problem. Arduino braucht ja keine und mich ärgert das etwas dass das System .h und .c da nicht so läuft. Ins .h kommt das Interface rein, ins .c der private Code.
Christian J. schrieb: > Nur ein Prototypen Problem. Arduino braucht ja keine und mich ärgert das > etwas dass das System .h und .c da nicht so läuft. Ins .h kommt das > Interface rein, ins .c der private Code. > Arduino braucht ja keine Das stimmt so nicht wirklich! Es macht sich selber welche, wenn du keine baust. Das betrifft aber nur *.ino Dateien. Keine *.c, *.cpp und *.h Dateien, die stehen in deiner Verantwortung. Wieso überhaupt *.c? Nimm *.cpp, dann musst du nicht die Extrawürste backen um mit dem C++ Rest klar zu kommen.
C++.... ne, alter Hase bleibt bei C. struct IrZeugs: Print { virtual size_t write(uint8_t value) { SendIRByte(value); return 1; } }; Aber dieses zweifach verschachtelte Konstrukt hier .... für mich nicht so ganz verstehbar. Funktioniert aber. irgendwie verwurstelt das Zeichenweise den Stream. Eine Funktion ist einem Struct, öfter mal was Neues. Wie würde das aussehen, wenn in einem Rutsch die IR Ausgabe erfolgen soll und die normale Print Ausgabe dahinter? Ich baue mir einige komplexe Ausgaben mit sprintf_P zusammen und schiebe die nach buf rein. Wäre gut, wenn die Ausgabe meiner Bastelei auf Seriell und IR kommen würde. Einen Nachteil sehe ich nur darin, dass serial.print die Ausgabe per INT erledigt und dadurch IR beeinflusst würde, weil ich da zwingend die INT abschalten muss, damit die Zeiten stimmen. Aber man kann ja auch serial.flush() vorher aufrufen oder die IR Ausgabe vorziehen. Die EEPROM Ausgabe liesse sich sicher auch verstreamen, nur müsste da dann ein zeiger mitlaufen aus das aktuelle Element. Wäre schwer?
Christian J. schrieb: > C++.... ne, alter Hase bleibt bei C. Dann musst du wohl von Arduino weg, oder deine Einstellung ändern. Denn: > Aber dieses zweifach verschachtelte Konstrukt hier .... für mich nicht > so ganz verstehbar. Funktioniert aber. Das ist naives, aber dennoch lupenreines C++. Siehe: https://playground.arduino.cc/Code/Printclass/ So wie vieles, sehr vieles, SEHR *SEHR* vieles in der Arduino Welt. Alles? Nee, aber sehr vieles! Aber wenn du willst, dann mache dir deine Problem! Soviele du möchtest. Christian J. schrieb: > Wäre schwer? Nein, quasi nur ein Fingerschnippen... ;-) aber nicht für C++ Verweigerer ;-) Tipp: Von der EEPROM Klasse erben und das Print Interface implementieren. Und ja, einen Index wird man mitführen müssen, und auch ein bisschen um die Grenzen kümmern, damit da keine ganz gruseligen Dinge passieren. Oder besser sofort Stream implementieren... dann klappts auch mit dem Lesen.
struct IrSend_t: Print { virtual size_t write(uint8_t value) { SendIRByte(value); Serial.write(value); return 1; } };
Arduino Fanboy D. schrieb: > Auch wieder Mega2560 und 328P identisches Verhalten. Hm.... Ich habe jetzt dann doch mal meinen Arduino Mega und den Logikanalysator aus dem Keller gekramt, um das mal nachzuvollziehen. Alledings ohne Arduino-Framework, und ohne serielle Ausgabe.
1 | #include <avr/io.h> |
2 | #include <avr/interrupt.h> |
3 | |
4 | void setTimer2() // CTC, Mode 2 |
5 | {
|
6 | cli(); |
7 | // Interrupts ausschalten
|
8 | TCNT2 = 0; // Reset Register |
9 | OCR2A = 249; // Compare |
10 | |
11 | TIMSK2 = (1 << OCIE2A); // Compare Match A |
12 | TCCR2A = (1 << WGM21); // set Mode |
13 | TCCR2B = (1 << CS20); // Prescaler 1 |
14 | //TCCR2B = (1<<CS22); // Prescaler 64
|
15 | sei(); |
16 | // Interrupts einschalten
|
17 | }
|
18 | |
19 | ISR(TIMER2_COMPA_vect) // Timer 2 Interrupt |
20 | {
|
21 | PINB = (1 << PB7); // toggle |
22 | }
|
23 | |
24 | int main(void) |
25 | {
|
26 | DDRB = 1 << PB7; |
27 | setTimer2(); |
28 | while (1) |
29 | {}
|
30 | }
|
Ergebis: PB7 toggelt nicht mit 250kHz, sondern brav mit 32khz, so wie es auch sein sollte. Oliver
Oliver S. schrieb: > sondern brav mit 32khz, so wie es > auch sein sollte. Deinen Code habe ich jetzt nicht überprüft, kann ich mir aber lebhaft vorstellen. Denn der Timer kommt im Mode 0 aus dem Reset. Dann klappt das auch alles. Lass den Timer mal kurze Zeit in einem PWM Mode laufen... Und dann schalte um. Du wirst sehen.....
> Alledings ohne Arduino-Framework
Aber genau das war doch der springende Punkt! Dass nämlich der Timer ein
'Vorleben' hatte, von dem man erstmal nichts weiß.
Arduino Fanboy D. schrieb: > Lass den Timer mal kurze Zeit in einem PWM Mode laufen... Bitte sehr:
1 | #include <avr/io.h> |
2 | #include <avr/interrupt.h> |
3 | #include <util/delay.h> |
4 | |
5 | void setTimer2_PWM() // PWM, Mode 5 |
6 | {
|
7 | cli(); |
8 | // Interrupts ausschalten
|
9 | TCNT2 = 0; // Reset Register |
10 | OCR2A = 249/4; // Compare |
11 | |
12 | TIMSK2 = (1 << OCIE2A); // Compare Match A |
13 | TCCR2A = (1 << WGM20); // set Mode |
14 | TCCR2B = (1 << WGM22) | (1 << CS20); // Prescaler 1 |
15 | sei(); |
16 | // Interrupts einschalten
|
17 | }
|
18 | |
19 | void setTimer2_CTC() // CTC, Mode 2 |
20 | {
|
21 | cli(); |
22 | // Interrupts ausschalten
|
23 | TCNT2 = 0; // Reset Register |
24 | OCR2A = 249; // Compare |
25 | |
26 | TIMSK2 = (1 << OCIE2A); // Compare Match A |
27 | TCCR2A = (1 << WGM21); // set Mode |
28 | TCCR2B = (1 << CS20); // Prescaler 1 |
29 | sei(); |
30 | // Interrupts einschalten
|
31 | }
|
32 | |
33 | ISR(TIMER2_COMPA_vect) // Timer 2 Interrupt |
34 | {
|
35 | PINB = (1 << PB7); // toggle |
36 | }
|
37 | |
38 | int main(void) |
39 | {
|
40 | DDRB = (1 << PB6) | (1 << PB7); |
41 | setTimer2_PWM(); |
42 | _delay_ms(100.0); |
43 | PORTB |= (1 << PB6); |
44 | setTimer2_CTC(); |
45 | while (1) |
46 | {}
|
47 | }
|
Tut, was es soll. Oliver
:
Bearbeitet durch User
Schreiben Sie mal in setTimer2_CTC
1 | OCR2A = 39;//249; // Compare |
Sehen Sie dann 200 kHz?
Oliver S. schrieb: > void setTimer2_PWM() // PWM, Mode 5 > { > cli(); > // Interrupts ausschalten > TCNT2 = 0; // Reset Register > OCR2A = 249/4; // Compare > > TIMSK2 = (1 << OCIE2A); // Compare Match A > TCCR2A = (1 << WGM20); // set Mode > TCCR2B = (1 << WGM22) | (1 << CS20); // Prescaler 1 > sei(); > // Interrupts einschalten > } Hier mogelst du! > OCR2A = 249/4; Der Problemzustand ist OCR2A = 0; Versuchs mal damit.
Das trifft es nicht ganz - der Trick ist, OCRA2 beim vorlaufenden PWM- größer zu machen als im späteren CTC-Modus, dann bleibt der zweite Wert im Pufferregister stecken.
1 | #include <avr/io.h> |
2 | #include <avr/interrupt.h> |
3 | #include <util/delay.h> |
4 | #include <util/atomic.h> |
5 | |
6 | #define AtomicSection ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
|
7 | |
8 | |
9 | void setTimer2_Arduino_PWM() |
10 | {
|
11 | AtomicSection
|
12 | {
|
13 | // Arduino Startup Code Fragment
|
14 | TCCR2A = 1; |
15 | TCCR2B = 4; |
16 | TCNT2 = 51; // ca. zaehlerstand zum Zeitpunkt des Eintritts in die Main loop |
17 | TIMSK2 = 0; |
18 | OCR2A = 0; |
19 | }
|
20 | }
|
21 | |
22 | void setTimer2_Reset() |
23 | {
|
24 | AtomicSection
|
25 | {
|
26 | TCCR2A = 0; |
27 | TCCR2B = 0; |
28 | TCNT2 = 0; |
29 | TIMSK2 = 0; |
30 | OCR2A = 0; |
31 | }
|
32 | }
|
33 | |
34 | void setTimer2_CTC() // CTC, Mode 2 |
35 | {
|
36 | AtomicSection
|
37 | {
|
38 | TCNT2 = 0; // Reset Register |
39 | OCR2A = 249; // Compare |
40 | |
41 | TIMSK2 = (1 << OCIE2A); // Compare Match A |
42 | TCCR2A = (1 << WGM21); // set Mode |
43 | TCCR2B = (1 << CS20); // Prescaler 1 |
44 | }
|
45 | }
|
46 | |
47 | ISR(TIMER2_COMPA_vect) // Timer 2 Interrupt |
48 | {
|
49 | PINB = (1 << PB7); // toggle |
50 | }
|
51 | |
52 | int main(void) |
53 | {
|
54 | sei(); |
55 | DDRB = (1 << PB6) | (1 << PB7); |
56 | |
57 | |
58 | PORTB |= (1 << PB6); |
59 | |
60 | while (1) |
61 | {
|
62 | setTimer2_Arduino_PWM(); |
63 | _delay_ms(20.0); |
64 | setTimer2_CTC(); // ca 250kHz |
65 | _delay_ms(20.0); |
66 | |
67 | setTimer2_Reset(); |
68 | _delay_ms(20.0); |
69 | setTimer2_CTC(); //ca 32kHz |
70 | _delay_ms(20.0); |
71 | }
|
72 | }
|
S. Landolt schrieb: > Das trifft es nicht ganz - der Trick ist, OCRA2 beim vorlaufenden > PWM- > größer zu machen als im späteren CTC-Modus, dann bleibt der zweite Wert > im Pufferregister stecken. Scheint auch nicht ganz zuzutreffen, in meinem Beispiel oben ist er ja im PWM-Modus kleiner als im CTC-Modus. Mit viel kleineren Werten, nicht nur bei 0, wird er nicht übernommen. Vermutlich, wenn der Wert kleiner als der aktuelle Zählerstand ist. Der Arduino-Code initialisiert den Timer 2 auf PWM 8 Bit mit OCRA=0. Warum die überhaupt da dran rumfummeln, keine Ahnung. Ich muß mir das die Tage nochmals genauer anschauen. Dafür war mir der Sonntag Nachmittag dann doch zu schade. Oliver
Oliver S. schrieb: > Der Arduino-Code initialisiert den Timer 2 auf PWM 8 Bit mit OCRA=0. > Warum die überhaupt da dran rumfummeln, keine Ahnung. Im Startcode vorbereiten für PWM, damit das nicht in analogWrite() gemacht werden muss. So wie auch andere Vorbereitungen für andere Arduino Features, wie millis(), delay() usw durchgeführt werden. Das muss man hinnehmen, wenn man in der Welt unterwegs ist.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.