Ahoi! So langsam bin ich am Ende mit meinen Nerven: Habe gestern den Umstieg von Bascom auf C gewagt, heute versuche den ganzen Nachmittag schon den Timer0 vom ATmega48 so zum laufen zu bekommen, dass ich eine Frequenz um die 440Hz zu hören bekomme. Der Piezo ist an PB1 (OC1A) angeschlossen und läuft auch (Testprogramm via delay). Bei den ganzen Registern wird man wahnsinnig... Ich habs sowohl über den weg Software-PWM als auch direkt per Fast-PWM versucht, auch hab ich mir schon nen Wolf gegoogled. Meine Frage: Hat jemand einen Beispielcode, den ich nachvollziehen kann, am besten für mein Problem? Ich glaub per Reverse-engineering komme ich besser an die Sache, und was google ausspuckt ist entweder für ältere Prozessoren oder nicht für Fast-Pwm oder,oder.... :/ Schöne Restwoche! oyla
Hi >und was google ausspuckt ist entweder für ältere >Prozessoren oder nicht für Fast-Pwm oder,oder.... :/ Zum Erzeugen von Frequenzen ist CTC besser als Fast PWM geeignet. Und der erste Anlaufpunkt ist nicht Gurgel sondern das Datenblatt. MfG Spess
Für Soundausgabe per PWM nehme ich prinzipiell den PFC-PWM Mode. Die CMP-Register liefern den Signalausgang und das ICR-Register ist der TOP Wert (CMP = (TOP/2)). Man muss nur dem Prescaler einen sinnvollen Wert verpassen und den Output Compare Mode korrekt einstellen (Achtung, da hats im Datenblatt haufenweise Tabellen für alle Modis - also nix durcheinander bringen!)
> Und > der erste Anlaufpunkt ist nicht Gurgel sondern das Datenblatt. Wenn ich mich komplett neu einfuchsen muss, ziehe ich erst, meist verständlichere Anleitungen zu rate, natürlich im Vergleich mit dem Datenblatt. Für den Einstieg an sich ist das Datenblatt einfach zu komplex teilweise (und mit meinen nicht flüssigen aber gut ausreichenden Sprachkenntnissen auch nich unbedingt einfachst zu lesen). Aber ohne gehts nicht, das stimmt schon. >Zum Erzeugen von Frequenzen ist CTC besser als Fast PWM geeignet. Dann versuch ichs mal...
Hi >Wenn ich mich komplett neu einfuchsen muss, ziehe ich erst, meist >verständlichere Anleitungen zu rate, natürlich im Vergleich mit dem >Datenblatt. Datenblätter sind zwar nicht immer fehlerfrei. Aber immer tausend mal besser als der Müll den man so im www findet. MfG Spess
oyla schrieb: >> Und >> der erste Anlaufpunkt ist nicht Gurgel sondern das Datenblatt. > > Wenn ich mich komplett neu einfuchsen muss, ziehe ich erst, meist > verständlichere Anleitungen zu rate, natürlich im Vergleich mit dem > Datenblatt. Für den Einstieg an sich ist das Datenblatt einfach zu > komplex teilweise (und mit meinen nicht flüssigen aber gut ausreichenden > Sprachkenntnissen auch nich unbedingt einfachst zu lesen). Aber ohne > gehts nicht, das stimmt schon. Das kann ich verstehen. Die Kapitel sind schon sehr umfangreich im Datenblatt. Wenn man aber erst einmal weiß, welcher Modus was macht, dann ist es eigentlich sehr einfach. Das interessante Kapitel bei jedem Timer ist das Kapitel "Register Summary". Dort sind alle Modi aufgeführt, die der jeweilige Timer kann. Dort suchst du dir den Modus raus, den du haben willst. Aus der Tabelle erhältst du so die Bitnamen der Bits (und ihre) Werte, die du setzen musst, damit dieser Modus ausgewählt wird. Mit diesen Bitnamen scrollst du etwas zurück und siehst nach, in welchem der Konfigurationsregister welches Bit beheimatet ist. So viele Konfigurationsregister gibt es ja normalerweise nicht - das geht also schnell. Je nach Modus sind unter Umständen auch noch andere Register beteiligt. Welche das sind, steht ebenfalls in der ersten Tabelle bzw. ergibt sich aus dem Modus. Wenn ein Ausgansgpin beteiligt ist (PWM), sucht man sich noch die zum Timer-Modus gehörende Tabelle für die Ausgangspins und ermittelt die zu setzenden Bits um dem Ausgansgpin ein bestimmtes Verhalten aufzuzwingen. Dann noch den Vorteiler setzen (erst dann läuft der Timer tatsächlich) und das wars. http://www.mikrocontroller.net/articles/FAQ#Timer
Das war schonmal eine sehr gute Hilfe, danke! Es will noch nicht anlaufen, irgendwas habe ich wohl noch nicht ganz bedacht. Hier der Code:
1 | #include <avr/io.h> |
2 | #include <util/delay.h> |
3 | #include <avr/interrupt.h> |
4 | |
5 | |
6 | int main() { |
7 | DDRB = 0xff; PORTB = 0xFF; // alles auf Ausgang und An |
8 | DDRC = 0xff; PORTC = 0xFF; |
9 | |
10 | TCCR0A |= (1<<COM0A0); // Toggle OC1A |
11 | TCCR0A |= (1<<WGM01); //Modus wählen (CTC) - WGM02 ist in TCCR0B, gerade unwichtig |
12 | |
13 | TCCR0B |= (1<<CS01) | (1<<CS00); //Taktquelle und Prescale (64) |
14 | |
15 | OCR0A = 15; |
16 | |
17 | sei(); //Erlaube inter. (nötig?) |
18 | |
19 | while(1){} |
20 | |
21 | |
22 | }
|
Wo ist der grobe Verstoß? :)
Edit: Ich bin davon ausgegangen, dass ich bei 1000000/64 (Pres.) / 15 auf 1040Hz komme, sollte hörbar sein.
1 | TCCR0A |= (1<<COM0A0); // Toggle OC1A |
Nein. Timer0 kann keinen Pin toggeln, der zu Timer1 gehört. Was hier getoggelt wird, ist OC0A.
oyla schrieb: > TCCR0A |= (1<<COM0A0); // Toggle OC1A Damit kannst du PB1(OC1A) lange lauschen. OC1A ist für Timer1. Deine Einstellung toggelt OC0A(PD6). mfg.
oh. Das scheint ein Kommentarfehler zu sein. Laut Datenblatt Seite 101 siehts so aus: COM0A1 COM0A0 Description 0 1 Toggle OC0A on compare match ... und das habe ich ja getan, denke ich?
oyla schrieb: > oh. Das scheint ein Kommentarfehler zu sein. Laut Datenblatt Seite 101 > siehts so aus: > > COM0A1 COM0A0 Description > 0 1 Toggle OC0A on compare match > ... > > und das habe ich ja getan, denke ich? Ja, aber wo genau hängt der Piezo denn nun dran? Im ersten Post steht: > Der Piezo ist an PB1 (OC1A) angeschlossen Und wenn er nun doch tatsächlich an OC0A hängt, dann musst du den Pin noch zum Ausgang machen.
oyla schrieb: > und das habe ich ja getan, denke ich? PD6 muß auf Ausgang stehen. sonst toggelt der nicht. Wo ist dein Piepser denn jetzt angeschlossen? oyla schrieb: > Piezo ist an PB1 (OC1A) angeschlossen und läuft auch (Testprogramm via > delay). mfg. Edit: @Stefan Ernst: Nächstes Mal bin ich schneller.
Es läuft! :) Tut mir leid! Ihr hattet recht, ich hatte den Piezzo falsch angeklemmt. Eobei ich eben geguckt habe, die Versuche die ich vorher gemacht hatte, sind dennoch nicht funktionstüchtig. Erstmal soweit :) Hier für die, die den selben Leidenweg haben der richtige Code:
1 | #include <avr/io.h> |
2 | |
3 | int main() { |
4 | |
5 | DDRB = 0xff; PORTB = 0xFF; //Datenrichtungen |
6 | DDRC = 0xff; PORTC = 0xFF; |
7 | DDRD = 0xff; PORTD = 0xFF; |
8 | |
9 | TCCR0A |= (1<<COM0A0); // Toggle OC0A (PD6) |
10 | TCCR0A |= (1<<WGM01); //Modus wählen (CTC) - WGM02 ist in TCCR0B, gerade unwichtig |
11 | |
12 | TCCR0B |= (1<<CS01) | (1<<CS00); //Taktquelle und Prescale (64) |
13 | |
14 | OCR0A = 15; //Zählgrenze |
15 | |
16 | while(1){ |
17 | //Hauptprogramm
|
18 | }
|
19 | |
20 | |
21 | }
|
Dankesehr! Nun kann ich doch ruhig schlafen :) Schöne Restwoche!
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.