Guten Abend, ich möchte mit einem ATTiny85 eine PWM im Bereich von 20 bis 25kHz erzeugen um damit einen "4-Pin" Lüfter steuern zu können. Nach einiger Recherche und ausprobieren bin ich auf TCCR0B = (TCCR0B & 0b11111000) | 0b001 gekommen, welches mir wohl Timer Register B auf Prescaler = 1 setzt - der Rest ist auf den jeweiligen Standardwerten geblieben. Der ATTiny85 läuft auf 8MHz - somit erhalte ich Pin 5 eine PWM mit einer Frequenz von ~31,x kHz. ==> 8MHz/(1*2^8) = 31,25kHz ... passt soweit zu meiner Annahme. Nun brauche ich aber irgendwas zwischen 20 und 25kHz um den PWM Lüfter "richtig" anzusteuern... leider ist das verringern der Frequenz für mich bei weitem nicht so einfach wie ich dachte. Nach einigem Hin- und Her bin ich tatsächlich (wer hätte es gedacht) beim Datenblatt gelandet. https://cdn-reichelt.de/documents/datenblatt/A300/ATTINY25-ATTINY45-ATTINY85_DATASHEET.pdf Hier bin ich in der Beschreibung nun nicht mehr ganz sicher, ob ich's richtig verstehe: 1: Nach den verschiedenen PWM Modi für Timer/Counter0 komme ich mit diesem gar nicht auf den gewünschten Frequenzbereich? Bei den 8MHz und einem Prescaler von 1 müsste ich ja von 0 bis 320 zählen um auf 25kHz zu kommen - was bei einem 8bit Zähler nicht so ganz passt da ich ja mindestens 9bit bräuchte (Modus 2, 3 und 7... alles das gleiche Problem?) ==> Übersehe ich hier irgend etwas offensichtliches? 2: Die nächste Überlegung war dann natürlich den Timer/Counter1 zu benutzen - nur hier bin ich bisschen untergegangen... bei OCR1A hab ich gesehen, es ist auch ein 8-bit Register und infolgedessen habe ic hhier ja irgendwie das gleiche Problem wie bei Timer0 - nur scheint hier mit TCCR1 ja nochmal eine Stufe zwischenschaltbar zu sein... Wenn dem so ist wäre es toll wenn mir jemand da bisschen auf die Sprünge helfen könnte. 3: Auf Seite 88 des Datenblatts (Table 12-3 Timer/Counter1 Clock Prescale Select in the Asynchronous Mode) wird die PWM Frequenz in Abhängigkeit von Prescale und OCR1C aufgelistet... hier wäre ja eine PWM Frequenz von 20kHz zu finden. Jedoch bin ich mir nicht im Klaren darüber, was mit "Asynchronous Mode" hierbei sagen soll und Resolution von 7.6(bits? Hat das Sinn, entweder 7 oder 8.. dachte ich zumindest). Vielen Dank schon einmal! Gruß, Wolfgang
Diese 20khz setzen 16Mhz Clock voraus. Wie wärs mit 4Mhz Clock und OCR0A=200 als Top. Das ergäbe 20Khz. oder 160 dann wärns 25KHz. Die 7,6 Bits Auflösung sind eine etwas unkonventionelle Darstellung. Mit 200 sinds 7,55 mit 160 ca 7,3 also mehr als 128 (7Bit) und weniger als 256 (8Bit)
:
Bearbeitet durch User
Wolfgang V. schrieb: > Der ATTiny85 läuft auf 8MHz - somit erhalte ich Pin 5 eine PWM mit einer > Frequenz von ~31,x kHz. > ==> 8MHz/(1*2^8) = 31,25kHz ... passt soweit zu meiner Annahme. Nimm den Phase Correct Mode(5). Dann passt das.
Hallo, noch ein Tipp, Was die wenigstens nicht wissen ist, dass der Athlet ein E85 auch Inter mit 16 Megahertz laufen kann . dazu schaut man ins Datenblatt: Stichwort PLL. Jetzt läuft aber leider die IO mit 64 Megahertz oder mit 32 Megahertz und nun muss andere Maßnahmen ergreifen, um die Timer Register beschreiben zu können.
Thomas E. schrieb: > Wolfgang V. schrieb: >> Der ATTiny85 läuft auf 8MHz - somit erhalte ich Pin 5 eine PWM mit einer >> Frequenz von ~31,x kHz. >> ==> 8MHz/(1*2^8) = 31,25kHz ... passt soweit zu meiner Annahme. > > Nimm den Phase Correct Mode(5). Dann passt das. Ich habe mich mal am Phase Correct Mode (5) anhand des Datenblattes und sonstiger Suche im Internet versucht... leider bekomme ich so überhaupt kein PWM Signal: Mit verschiedensten Kombinationen aus COM0x0/1 habe ich schon "gespielt" - aber ohne, dass es was verändert hätte. Sobald ich WGM[2:0] auf 5 habe, tut nichts mehr. Mit WGM[2:0] = 1 bekomme ich auf B0 und B1 jeweils ~15,7kHz als PWM Frequenz. (In geposteten Beispielcode habe ich hierfür einfach 1<<WGM02 durch 0<<WGM02 ausgetauscht.)
1 | #include <Arduino.h> |
2 | void setup() { |
3 | TCCR0A = 0b0 | ((1 << COM0A1)|(0 << COM0A0)|(1 << COM0B1)|(0 << COM0B0)| (0 << WGM01) | (1 << WGM00)); |
4 | TCCR0B = 0b0 | ((0 << FOC0A)|(0 << FOC0B)|(1 << WGM02)|(0 << CS02)|(0 << CS01)|(1 << CS00)); |
5 | OCR0A = 160; |
6 | pinMode(PINB0, OUTPUT); |
7 | pinMode(PINB1, OUTPUT); |
8 | }
|
9 | |
10 | void loop() { |
11 | analogWrite(PINB0, 50); |
12 | analogWrite(PINB1, 50); |
13 | delay(1000); |
14 | }
|
Hab ich da was vergessen/falsch gemacht? (Offenbar: ja :-))
Wolfgang V. schrieb: > Hab ich da was vergessen/falsch gemacht? (Offenbar: ja :-)) Du mußt Dich schon entscheiden. Entweder Du benutzt das Arduino-Framework oder Du greifst direkt auf die Register zu. Beides zusammen geht nicht. Das analogWrite() verläßt sich darauf, daß die Register so sind, wie sie das Framework initialisiert hat. Wenn nicht, dann knallt es.
:
Bearbeitet durch User
Will man 2 PWMs mit einer bestimmten Frequenz, muß man T1 benutzen. Bei 8MHz mit Prescaler 2 (CS13..CS10 = 0010) und OCR1C = 199 kommt man dann auf 20kHz.
Peter D. schrieb: > Du mußt Dich schon entscheiden. Entweder Du benutzt das > Arduino-Framework oder Du greifst direkt auf die Register zu. > Beides zusammen geht nicht. Moin, das ist leider nicht richtig. Es geht sehr wohl z.Bsp. auf meinem Arduino Mega mit
1 | //************ PWM *****************
|
2 | int myEraser = 7; |
3 | int myPrescaler = 1; |
4 | |
5 | void setup() { |
6 | //set PWM Frequency
|
7 | // TCCR3 -> Pin 2,3,5
|
8 | // TCCR4 - > Pin 6,7,8
|
9 | |
10 | TCCR3B &= ~myEraser; // this operation (AND plus NOT), set the three bits in TCCR3B to 0 |
11 | TCCR4B &= ~myEraser; // this operation (AND plus NOT), set the three bits in TCCR4B to 0 |
12 | TCCR3B |= myPrescaler; // this operation (OR), replaces the last three bits in TCCR3B with our new value 001 |
13 | TCCR4B |= myPrescaler; // this operation (OR), replaces the last three bits in TCCR4B with our new value 001 |
14 | }
|
15 | |
16 | void loop() { |
17 | ...
|
18 | analogWrite(2, 150); |
19 | ...
|
20 | }
|
Peter D. schrieb: > Will man 2 PWMs mit einer bestimmten Frequenz, muß man T1 benutzen. > Bei 8MHz mit Prescaler 2 (CS13..CS10 = 0010) und OCR1C = 199 kommt man > dann auf 20kHz. Ich möchte / brauche nur einen Port mit PWM - das ich beide Ports drin habe ist eher als Verzweiflungstat zu sehen weil ich mir nicht sicher war ob ich vielleicht mit den zugehörigen Ports was verhaut habe. Sorry dafür.
:
Bearbeitet durch User
Peter D. schrieb: > Du mußt Dich schon entscheiden. Entweder Du benutzt das > Arduino-Framework oder Du greifst direkt auf die Register zu. > Beides zusammen geht nicht. Okay, das leuchtet ein... => bin durch die includes gegangen und hab halt recht viele ifdefs gesehen die das Vorhandensein einiger defines usw. geprüft haben... das sah schon so aus als wenn die da eine "Grundabsicherung" hätten. (Teilweise war Code vorhanden um bei digitalWrite PWM abzuschalten usw.) - habe aber nicht weiter drüber nachgedacht, ein enablePwm bzw. setPwmMode o.ä. habe ich nicht gefunden und es damit halt auf sich beruhen lassen. ==> Bin eher der Freund davon das "direkt" ohne die Arduino zu machen da sie ja offenbar eh nicht alles bietet, was ich gerade möchte. Könntest du mir bitte sagen wie ich dann den Pin (B0) ohne arduino.h auf output schalte und den duty cicle eingebe? Da finde ich im Datenblatt gar nichts zu und alle Beispiele die ich online finden konnte scheinen auf analogWrite der arduino Bibliothek zu gehen. Gerne auch, nach was ich im Datenblatt suchen müsste.. Wäre super, vielen Dank!
PB0 (OC0A) kann keine bestimmte Frequenz ausgeben, d.h. der TOP-Wert der PWM kann nicht verkürzt werden. Das geht nur für OC0B/OC1A und OC1B. Bzw. falls PB1 nicht benutzt wird, kann man PB0 auch als /OC1A konfigurieren.
User schrieb: > das ist leider nicht richtig. Ich würds trotzdem nicht machen, auch wenn es bei Deinem ATmega2560 zu funktionieren scheint. Früher oder später oder auf einem andern AVR kann es Seiteneffekte geben und Du legst Dir die Karten. WIMRE benutzt das Framework T0 für Delays, d.h. das sorgt schon für Konflikte mit T0 als PWM.
Hallo, dieser Lösungsansatz ist auch "offiziell" bei Arduino beschrieben.. https://www.arduino.cc/en/Tutorial/SecretsOfArduinoPWM
Peter D. schrieb: > PB0 (OC0A) kann keine bestimmte Frequenz ausgeben, d.h. der TOP-Wert der > PWM kann nicht verkürzt werden. > Das geht nur für OC0B/OC1A und OC1B. > Bzw. falls PB1 nicht benutzt wird, kann man PB0 auch als /OC1A > konfigurieren. Wo im Datenblatt finde ich das? Ich hatte mich im Datenblatt auf 11.7.4 gestützt (11. 8-bit Timer/Counter0 with PWM) (11.7. Modes of Operation) (11.7.4 Phase Correct PWM) In phase correct PWM mode, the compare unit allows generation of PWM waveforms on the OC0x pins. Setting the COM0x[1:0] bits to two will produce a non-inverted PWM. An inverted PWM output can be generated by setting the COM0x[1:0] to three: Setting the COM0A0 bits to one allows the OC0A pin to toggle on Compare Matches if the WGM02 bit is set. This option is not available for the OC0B pin (See Table 11-4 on page 78). ==> Ich frage deshalb so "genau" nach, weil ich mir ja irgendwie auch selbst helfen können will. Thx Und thx für den Ausschnitt aus dem Datenblatt... das war wohl Schlampigkeit meinerseits. :-(
Hier noch eine kurze Rückmeldung meinerseits, es scheint soweit funktioniert zu haben. Habe nun 23kHz erzeugt, wie von Peter schon erwähnt nur auf PB1. Ich hoffe noch auf den Hinweis bezüglich wo ich im Datenblatt hätte gucken müssen wegen PB0 und um einen sauberen Abschluss im Thread zu kriegen, hier mein Code (unglaublich, wieviel Zeit die paar Zeilen gekostet haben..):
1 | #include <avr/io.h> |
2 | |
3 | int main() |
4 | {
|
5 | TCCR0A = 0b0 | ((1 << COM0A1) | (0 << COM0A0) | (1 << COM0B1) | (0 << COM0B0) | (0 << WGM01) | (1 << WGM00)); |
6 | TCCR0B = 0b0 | ((0 << FOC0A) | (0 << FOC0B) | (1 << WGM02) | (0 << CS02) | (0 << CS01) | (1 << CS00)); |
7 | |
8 | // freq / prescale / OCR0A / 2 = pwm freq => OCR0A = freq/(2*pwm freq)
|
9 | OCR0A = 174; // 160 = 25kHz, 23kHz = ~174 |
10 | OCR0B = 87; // duty cycle = OCR0B/OCR0A: 87/174=0.5 |
11 | |
12 | // MCUCR = MCUCR | (1 << PUD); // MCU Control Register, PUD: Disable all Pull-Ups
|
13 | DDRB = 0b0 | (1 << PORTB1); //Data Direction Register Port B: 1 for output, 0 for input (datasheet 10.2.1, P. 55, Table 10-1) |
14 | // PORTB: Port B Data Register
|
15 | PORTB = PORTB & 0b11111101; // Bit 1 = PORTB1 = 0 |
16 | |
17 | while (true) |
18 | {
|
19 | //analogWrite(PINB0, 50);
|
20 | //analogWrite(PINB1, 50);
|
21 | }
|
22 | }
|
Vielen Dank an dieser Stelle für die wirklich kompetente Hilfe!
Wolfgang V. schrieb: > Ich hoffe noch auf den Hinweis bezüglich wo ich im Datenblatt hätte > gucken müssen wegen PB0 In die Fußnote zu Tabelle 11-4:
1 | A special case occurs when OCR0A or OCR0B equals TOP and COM0A1/COM0B1 is set. In this case, the Com- |
2 | pare Match is ignored, but the set or clear is done at TOP. See “Phase Correct PWM Mode” on page 74 for more |
3 | details. |
Du verwendest den Mode 5 (WGM0[2:0]=101, Tabelle 11-5): PWM, Phase Correct. Dort wird OCR0A für den Endwert des Zählers verwendet (TOP). Wenn es auf beiden Pins (PB0 und PB1) wackeln soll, mußt Du vermutlich auf Mode 1 (WGM0[2:0]=001) wechseln. Dann kommt in OCR0A der Vergleichswert für OC0A/PB0. Um auf 23 kHz PWM Frequenz zu kommen, müßte der Tiny dann mit 11,73 MHz getaktet werden (23000 * 510).
Karl M. schrieb: > Jetzt läuft aber leider die IO mit 64 Megahertz oder mit 32 Megahertz > und nun muss andere Maßnahmen ergreifen, um die Timer Register > beschreiben zu können. Eigentlich nicht. Wenn man die interne PLL verwendet, werden der Timer 1 und die dazugehörigen IO-Pins mit dem schnellen Takt versorgt. Die Registerzugriffe sind m.E. gepuffert. Mit der PLL sind mit Timer 1 PWM-Frequenzen zwischen 20 und 500 kHz in Schritten von 10 bzw. 50 kHz möglich.
Die PLL (Fuse-Bits) setzt den CPU-Takt auf 16MHz. Der asynchrone Mode (PCKE im PLLCSR-Register) setzt T1 auf 64MHz oder 32MHz. Beides kann unabhängig voneinander benutzt werden.
Für die AT Controller sind die Codeschnipsel unter https://www.electronicsplanet.ch/mikrocontroller/source-code/ATmega8/ATmega8-Timer1-index.htm oft auch noch recht hilfreich um funktionierenden Beispielcode zu erzeugen.
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.