{"id":314,"date":"2020-01-19T12:57:53","date_gmt":"2020-01-19T11:57:53","guid":{"rendered":"http:\/\/www.skie.info\/?p=314"},"modified":"2020-01-19T13:08:04","modified_gmt":"2020-01-19T12:08:04","slug":"avr-attiny25-pwm-in-schnell-mit-hilfe-der-pll","status":"publish","type":"post","link":"http:\/\/www.skie.info\/?p=314","title":{"rendered":"AVR ATTiny25\/45\/85: PWM in schnell mit Hilfe der PLL"},"content":{"rendered":"\n<p>In diesem Beitrag m\u00f6chte ich ein wenig das PWM-Modul eines ATTiny25\/45\/85 vorstellen mit Schwerpunkt der Nutzung des PLL-Moduls als Taktquelle des PWM-Timers.<\/p>\n\n\n\n<!--more-->\n\n\n\n<p>PWM steht f\u00fcr <strong>P<\/strong>ulse <strong>W<\/strong>idth <strong>M<\/strong>odulation. Hierbei handelt es sich um ein Rechteck-Signal bei dem sich das Puls-Pause-Verh\u00e4ltnis ver\u00e4ndern l\u00e4sst. Damit lassen sich recht einfach Motoren in ihrer Geschwindigkeit beeinflussen, Servos als Stellglieder aus dem RC-Modellbausektor ansteuern oder auch, mittels geeigneter Tiefpassfilterung, Steuerspannungen generieren und noch einiges mehr.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Aufbau Beispiel<\/h2>\n\n\n\n<p>Da es hier nur um ein Beispiel geht werde ich hier demonstrieren, wie man damit eine Steuerspannung generieren kann (z.B. als Set-Wert-Vorgabe f\u00fcr ein Labornetzteil). Dazu wird am Pin PB2 eine Spannung von 0-5 Volt vorgegeben, an Pin PB1 wird das PWM-Signal ausgegeben und mittels eines 1k\u03a9 Widerstandes und eines 1\u00b5F Kondensator gefiltert.<\/p>\n\n\n\n<p>Der ATTiny wird bzgl. seiner Fuse-Bits mit den Werkseinstellungen betrieben, d.h. er l\u00e4uft mit 1 MHz Taktrate. Bei maximaler PWM-Aufl\u00f6sung von 255 sind damit maximal PWM-Frequenzen von ~3921 Hz m\u00f6glich. Gen\u00fcgt einem diese PWM-Frequenz nicht so l\u00e4sst sich die Taktquelle f\u00fcr Timer 1 des ATTiny auf bis zu 64 MHz erh\u00f6hen wodurch die PWM-Frequenz auf bis zu 251 kHz steigt bei voller Aufl\u00f6sung. Eine weitere Steigerung der PWM-Frequenz l\u00e4sst sich bewirken indem man den Wert, bis wohin der Timer z\u00e4hlen soll, verringert, maximal kann bis 255 gez\u00e4hlt werden.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Beispiel-Code<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;avr\/io.h>\n#include &lt;avr\/interrupt.h>\n\n\/\/ Wert bis wohin der Timer zaehlen soll\nstatic const uint8_t PWM_MAX_VALUE = 0xff;\n\nint main(void){\n\n  \/\/ zunaechst den ADC einstellen\n  \/\/ IO-Clock = 1MHz => ADC-Prescaler auf 8 einstellen\n  \/\/ ADC-Clock = 125 kHz, darf\/soll zwischen 50kHz-200kHz liegen\n  ADCSRA |= (1 &lt;&lt; ADPS0)|(1 &lt;&lt; ADPS1);\n  \/\/ Referenzquelle auf AVCC einstellen und Kanal 1 auswaehlen\n  ADMUX |= (1 &lt;&lt; REFS0)|(1 &lt;&lt; MUX0);\n  \/\/ Beim Aendern der Referenzquelle wird eine Dummy-Messung empfohlen\n  \/\/ ADC starten (default: free running)\n  ADCSRA |= (1 &lt;&lt; ADEN)|(1 &lt;&lt; ADSC);\n  \/\/ und auf Abschluss der Konvertierung warten, Dummy-Read\n  while (ADCSRA &amp; (1 &lt;&lt; ADSC)) {\n  }\n  \/\/ Messergebnis steht in ADC, wird aber nicht ausgewertet\n\n  \/\/ Fuer die eigentliche Anwendung wird dann der ADC im \n  \/\/ Interrupt ausgewertet\n  ADCSRA |= (1 &lt;&lt; ADIE);\n  \/\/ und die naechste Messung starten\n  ADCSRA |= (1 &lt;&lt; ADSC);\n\n  \/\/ Nun stellen wir den Timer fuer die PWM ein\n  \/\/ Zunaechst wird eingestellt, bis wohin im PWM-Mode der Timer zaehlen soll\n  OCR1C = PWM_MAX_VALUE;\n  \/\/ PWM-Mode einschalten und als Non-Inverting-PWM konfigurieren\n  TCCR1 |= (1 &lt;&lt; PWM1A)|(1 &lt;&lt; COM1A1);\n  \/\/ Und die PLL als Taktquelle waehlen, als Standard ist IO-Clock die Taktquelle\n  \/\/ Als erstes muss die Aenderung des PLL-Registers freigeschaltet werden\n  \/\/ dazu das entsprechende Bit zu 1 setzen und gleichzeitig alle anderen Bits\n  \/\/ im Register loeschen.\n  PLLCSR = (1 &lt;&lt; PLLE);\n  \/\/ und dann hat man vier IO-Taktzyklen Zeit die PLL zuzuschalten\n  PLLCSR |= (1 &lt;&lt; PCKE);\n  \/\/ nun noch den Pin fuer die PWM aus Ausgang schalten damit das PWM-Signal \n  \/\/ auch am Pin anliegt\n  DDRB |= (1 &lt;&lt; PB1);\n  \/\/ und den Timer starten\n  TCCR1 |= (1 &lt;&lt; CS10);\n  \n  \/\/ fuer den ADC noch die Interrupts einschalten\n  sei();\n  for(;;){\n  }\n  return 0;\n}\nISR(ADC_vect){\n  \/\/ Der ADC soll seinen Messwert auf den maximalen PWM-Wertebereich abbilden\n  \/\/ daher hier eine kleine Umrechnung dafuer\n  OCR1A = PWM_MAX_VALUE*ADC\/1024.0\n  \/\/ ADC erneut starten\n  ADCSRA |= (1 &lt;&lt; ADSC);\n}<\/code><\/pre>\n\n\n\n<p>Mit der Variablen PWM_MAX_VALUE kann man einstellen, bis wohin der Timer z\u00e4hlen soll und somit die Geschwindigkeit und Aufl\u00f6sung der PWM einstellen. Damit kann man ein wenig spielen und sich das Verhalten n\u00e4her betrachten.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Ergebnisse<\/h2>\n\n\n\n<p>Gibt man an den Analogeingang einen Spannungssprung von 0V auf 500mV so stellt sich mit obigen Code der folgende Spannungsverlauf am PWM-Ausgang PB1 ein.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"546\" height=\"325\" src=\"http:\/\/www.skie.info\/wp-content\/uploads\/251-kHz-PWM.png\" alt=\"\" class=\"wp-image-317\" srcset=\"http:\/\/www.skie.info\/wp-content\/uploads\/251-kHz-PWM.png 546w, http:\/\/www.skie.info\/wp-content\/uploads\/251-kHz-PWM-300x179.png 300w\" sizes=\"auto, (max-width: 546px) 100vw, 546px\" \/><\/figure><\/div>\n\n\n\n<p>\u00c4ndert man obigen Code indem man die Zeilen f\u00fcr das PLLCSR auskommentiert\/l\u00f6scht so liefe der Timer f\u00fcr die PWM nicht mit 64 MHz sondern mit 1 MHz, gibt man hierbei dann einen Spannungssprung von 0V auf 500mV auf den Analogeingang f\u00fchrt dies zu folgenden Spannungsverlauf bei PB1:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"546\" height=\"325\" src=\"http:\/\/www.skie.info\/wp-content\/uploads\/4-kHz-PWM.png\" alt=\"\" class=\"wp-image-318\" srcset=\"http:\/\/www.skie.info\/wp-content\/uploads\/4-kHz-PWM.png 546w, http:\/\/www.skie.info\/wp-content\/uploads\/4-kHz-PWM-300x179.png 300w\" sizes=\"auto, (max-width: 546px) 100vw, 546px\" \/><\/figure><\/div>\n\n\n\n<p>In diesem Signal ist deutlich die PWM-Frequenz zu erkennen, man m\u00fcsste also den Filter entsprechend anpassen was aber das Signal deutlich langsamer machen w\u00fcrde. Der Tiefpass mit 1k\u03a9 und 1\u00b5F weist eine Grenzfrequenz von ca. 160Hz auf. Um die gleiche Filterwirkung bzgl. der Ripplespannung wie bei der 251 kHz Frequenz zu erhalten m\u00fcsste die Grenzfrequenz um den Faktor 64 reduziert werden, als um etwa 2.5 Hz liegen (z.B. indem man den Widerstand von 1k\u03a9 auf 64k\u03a9 erh\u00f6ht). Je nach Anwendung kann das ausreichend sein aber es kann auch viel zu langsam sein. Mit der PLL kann aber dieser Nachteil ausgeglichen werden.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Fazit<\/h2>\n\n\n\n<p>Mit der PLL kann man am ATTiny25\/45\/85 sehr schnelle PWMs erzeugen. Schade ist, dass dieses Modul nicht in jedem AVR integriert ist. Wirklich gro\u00df kann das Modul ja nicht sein da der ATTiny25\/45\/85 zu den kleinsten AVRs geh\u00f6rt. F\u00fcr gew\u00f6hnlich nutze ich bei PWM-Anwendungen mit diesen ATTiny's immer die PLL. Es kommt nat\u00fcrlich immer noch auf die konkrete Anwendung an, f\u00fcr einen Servo aus dem Modellbausektor w\u00e4re dieser PWM-Mode denkbar ungeeignet da er viel zu schnell ist.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In diesem Beitrag m\u00f6chte ich ein wenig das PWM-Modul eines ATTiny25\/45\/85 vorstellen mit Schwerpunkt der Nutzung des PLL-Moduls als Taktquelle des PWM-Timers.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[4],"tags":[20,21,22,14,24,23],"class_list":["post-314","post","type-post","status-publish","format-standard","hentry","category-programmierung","tag-attiny25","tag-attiny45","tag-attiny85","tag-avr","tag-pll","tag-pwm"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"http:\/\/www.skie.info\/index.php?rest_route=\/wp\/v2\/posts\/314","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.skie.info\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.skie.info\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.skie.info\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.skie.info\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=314"}],"version-history":[{"count":0,"href":"http:\/\/www.skie.info\/index.php?rest_route=\/wp\/v2\/posts\/314\/revisions"}],"wp:attachment":[{"href":"http:\/\/www.skie.info\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=314"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.skie.info\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=314"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.skie.info\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=314"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}