Das Infolexikon
...und Blog über die Uni FrankfurtInformatik und Kram
Da wir lange nicht wußten, wo wir das für die Uni ausgearbeitete Material unterbringen sollten und auch einen schrecklichen Drang hatten der Welt diverse Sachen aufzudrücken...
| Atmega Music |
Ich hatte mal wieder bisschen Zeit, also dachte ich mir, dass es doch geil wär, den Atmega-Projekten ein bisschen Musik zu spendieren, ne Gameboy Melodie oder so. Ich hab vier Tage bis zum ersten Ton gebraucht, deshalb dachte ich, dass es nen Aritkel wert ist, wo ich so wenig zusammenhängedes Material für N00bs wie mich gefunden hab. Ich wollte nämlich kein groß angelegtes Projekt mit DDS oder Wavetables mit Widerstandsnetzwerken etc. machen, sondern einfach nur mit der PWM vom Atmega bissl rumdudeln.
Töne
Manchen ist es vllt sofort klar, bei mir wars nicht so:Töne können weitgehend durch Sinus-Wellen erzeugt werden. Töne liegen wohl irgendwo zwischen 200Hz und 1,5kHz (ich hab mit Frequenzen zwischen 300Hz und 800Hz rumgespielt). Annähernd reale Töne, also z.B. von Musikinstrumenten erfordern aber Überlagerungen dieser Sinus-Wellen, sowie Hüllkurven etc.
Hier wie gesagt, ganz easy: eine einzige Sinus-Welle, ein sauberer 8-bit Ton!
Die PWM
PWM = PulsWeitenModulation. Wichtig zum Verständnis: die PWM ändert ihre Frequenz NIE, NIEMALS! Alles was sich ändert, sind die Pulsweiten, also die high/low-Phasen, in denen der Ausgang (Atmega8: PB1=OCR1A) getoggelt wird. Die PWM besitzt einen Counter, der ständig hochzählt, bei 8 bit von 0 bis 255.Um die Pulsweite zu bestimmen, kann man nun einen Vergleichswert setzen. Ist dieser 0 gibt es keine high-phase, ist er 255, gibt es nur high-phasen. Bei 128 sind die high-phasen z.B. genauso lang wie die low-phasen.
Wie macht man damit jetzt ne Sinus-Welle? Indem man die Pulsweiten periodisch erhöht, dann wieder erniedrigt, ich hab dazu mal ein kleines Bild gemalt:
Also erstellt man erstmal eine Tabelle für die Sinus-Werte, und die wird dann direkt ins Programm kodiert, so muss der Atmega nur noch i.d. Tabelle für die Werte nachschauen.
Rechnen
Ich benutze den Atmega8, mit dem 8-bit Counter f.d. PWM. Das heisst, man braucht 256 Werte (8-bit), die zwischen 0 und 255 liegen.Die Frequenz der PWM beträgt mit 8Mhz und 8-bit Counter ca. 15625kHz ( eine Periode ist immer einmal hochzählen zum Compare-Wert, toggeln, und anschliessend runterzählen bis zum compare-wert, toggeln, runterzählen bis 0, von vorne). Dieses nette Bild veranschaulicht das ganze hoffentlich besser, als ich es erklären kann (Quelle:http://www.mikrocontroller.net/wikifiles/a/a9/PWM_Theorie_3.gif, danke an Lars N!)
Angenommen, man erstellt eine Tabelle mit genau einer Sinuswelle, so heisst dass, dass bei jedem Durchlauf der 256 Werte genau diese eine Sinuswelle abgespielt wird.
(Ich habe mir ein kleines C++-Programm geschrieben, dass die Sinus-Funktion der math.h benutzt, und 256 Werte in eine Datei schreibt.)
Dementsprechend hat man dann als Frequenz für den Sinus:
15625khz/256 = 62,5, man hätte also eine Ton-Frequenz von 62,5Hz.
Dudeln
Da man nicht für jeden möglichen Ton so eine Tabelle mit anderer Frequenz speichern kann, ändert man einfach die Abtast-Abstände. Würde man bei der Sinuswelle von oben jeden Wert abtasten, den Index-Counter also immer um 1 erhöhen, so erhält man wie bereits erwähnt einen 62,5Hz-Ton.Tastet man jetzt aber jeden 2. Wert ab, verdoppelt sich die Frequenz schon, man hat einen 125Hz-Ton.
Das ganze ist proportional zueinander, also tolle Sache.
Leider bin ich noch nicht dahintergekommen, wie man Zwischenschritte coden könnte, also z.B. 1.5 oder so, da bin ich für jeden Tip dankbar!
Video
Hier erstmal wie versprochen das Video, es hat sich einiges getan! Danke den Jungs von mikrocontroller.net hab ichs dann letztendlich geschafft, dem atmega saubere Töne zu entlocken.Das Vid ist vom Handy, also net böse sein wegen der miesen quali.
Program
Und hier erstmal der Code, alles in einem file, net allzugroß, soll ja nur "nebenher" laufen:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include <stdint.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include "lcd-routines.h"
// Noten-Frequenzen,
// berechnet für 8Mhz und PWM ohne Prescaler
#define c 542
#define cis 574
#define d 608
#define dis 644
#define e 682
#define f 722
#define fis 765
#define g 810
#define gis 858
#define a 908
#define b 962
#define h 1019
#define p 0 // Pause
struct notendauer
{
uint16_t note;
uint16_t dauer;
};
struct notendauer entchen[28] =
{
{c,1200},{d,1200},{e,1200},{f,1200},{g,1600},
{g,1600},{a,800},{a,800},{a,800},{a,800},
{g,1600},{a,800},{a,800},{a,800},{a,800},
{g,1600},{f,1200},{f,1200},{f,1200},
{f,1200},{e,1200},{e,1600},{d,1200},
{d,1200},{d,1200},{d,1200},{c,1600},
{p,60000}
};
// einfache Sinuswelle in 256 diskreten Werten
const uint8_t sinewave[1][256] PROGMEM=
{
{
0x80,0x83,0x86,0x89,0x8c,0x8f,0x92,0x95,0x98,0x9c,0x9f,0xa2,0xa5,0xa8,0xab,0xae,
0xb0,0xb3,0xb6,0xb9,0xbc,0xbf,0xc1,0xc4,0xc7,0xc9,0xcc,0xce,0xd1,0xd3,0xd5,0xd8,
0xda,0xdc,0xde,0xe0,0xe2,0xe4,0xe6,0xe8,0xea,0xec,0xed,0xef,0xf0,0xf2,0xf3,0xf5,
0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfc,0xfd,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfd,0xfc,0xfc,0xfb,0xfa,0xf9,0xf8,0xf7,
0xf6,0xf5,0xf3,0xf2,0xf0,0xef,0xed,0xec,0xea,0xe8,0xe6,0xe4,0xe2,0xe0,0xde,0xdc,
0xda,0xd8,0xd5,0xd3,0xd1,0xce,0xcc,0xc9,0xc7,0xc4,0xc1,0xbf,0xbc,0xb9,0xb6,0xb3,
0xb0,0xae,0xab,0xa8,0xa5,0xa2,0x9f,0x9c,0x98,0x95,0x92,0x8f,0x8c,0x89,0x86,0x83,
0x80,0x7c,0x79,0x76,0x73,0x70,0x6d,0x6a,0x67,0x63,0x60,0x5d,0x5a,0x57,0x54,0x51,
0x4f,0x4c,0x49,0x46,0x43,0x40,0x3e,0x3b,0x38,0x36,0x33,0x31,0x2e,0x2c,0x2a,0x27,
0x25,0x23,0x21,0x1f,0x1d,0x1b,0x19,0x17,0x15,0x13,0x12,0x10,0x0f,0x0d,0x0c,0x0a,
0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x03,0x02,0x01,0x01,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x02,0x03,0x03,0x04,0x05,0x06,0x07,0x08,
0x09,0x0a,0x0c,0x0d,0x0f,0x10,0x12,0x13,0x15,0x17,0x19,0x1b,0x1d,0x1f,0x21,0x23,
0x25,0x27,0x2a,0x2c,0x2e,0x31,0x33,0x36,0x38,0x3b,0x3e,0x40,0x43,0x46,0x49,0x4c,
0x4f,0x51,0x54,0x57,0x5a,0x5d,0x60,0x63,0x67,0x6a,0x6d,0x70,0x73,0x76,0x79,0x7c
}
};
uint16_t i=0;
uint8_t tone=0;
volatile uint16_t scale=523;
// Interrupt-Funktion, die den "Zeiger" hochzählt
// je nach gewünschter Frequenz wird "scale" verändert,
// und somit die Sinuswelle schneller (hoher ton)
// oder langsamer (tiefer Ton) abgelaufen
ISR(TIMER1_COMPA_vect){
OCR1A=pgm_read_byte(&sinewave[tone][(i>>8)]);
i += scale;
}
int main(void)
{
// PWM-INIT -----------------------------------
// Alle B-Pins als Ausgänge
DDRB=0xFF;
// Anfangswert der PWM
OCR1A=0x80;
//Output compare OC1A 8 bit non inverted PWM
// Timer Counter Control Register!
// Bit: 7 6 5 4 3 2 1 0
// Bed: COM1A1 COM1A0 COM1B1 COM1B0 FOC1A FOC1B WGM11 WGM10
// Hier: 1 0 0 1 0 0 0 1
TCCR1A=0x91;
// Timer ohne Prescaler starten
TCCR1B=0x01;
// Einschalten des Ausgangs-Vergleichs-Interrupts auf OCR1A (PB1)
// Timer/Counter Interrupt Mask!
// Bit: 7 6 5 4 3 2 1 0
// Bed: OCIE2 TOIE2 TICIE1 OCIE1A OCIE1B TOIE1 ------ TOIE0
// Hier: 0 0 0 1 0 0 0 0
TIMSK=0x10;
//enable global interrupts
sei();
// MAIN-LOOP ----------------------------------
while(1)
{
// durch das Noten-Array laufen und nacheinander
// die Töne in jeweiliger Länge abspielen
// da "scale" global definiert ist, kann es einfach
// hier geändert werden!
for(int y=0;y<26;y++){
scale = entchen[y].note;
_delay_ms(entchen[y].dauer);
// Interrupt kurz ausschalten, gibt kurze Pause
// so werden die Töne getrennt
cli();
_delay_ms(400);
i=0;
sei();
}
}//while(1)
return 0;
}
| Erstellt | 5. September 2008 12:06:07 | Geändert | 9. Januar 2009 22:09:46 |
|---|---|---|---|
| Von | Tobias Weis | Kategorien | Technik Robostuff |
| 20 Kommentar(e) | |||
Kommentare
Ja ich versuch dem schon seid jahren zu erzählen mal anständigen code zu schreiben, aber der weigert sich einfach immer!
can i haz a coda-cola plz?
Es geht ja vorrangig um die zahlreichen Fehler im Text.
8 bit sind zwar 256 Werte, da aber bei 0 begonnen wird, gehts von 0 bis 255!! Ebenso die Frequenz der PWM.
8 bit sind zwar 256 Werte, da aber bei 0 begonnen wird, gehts von 0 bis 255!! Ebenso die Frequenz der PWM.
hab die von dir erwähnten Punkte im Artikel geändert, hoffe, dass jetzt alles stimmt?!
Jetzt wäre es noch gut wenn deine Kommentare aussagekräftiger wären^^
z.B.: "// 122,10546875 ist "einfacher" Sinus mit 8Mhz und 8-bit PWM
"
Wo kommt da das 122,10546875 her. Das weiss ein Anfänger sicherlich nicht [ und du in einem Jahr bestimmt auch nicth mehr ;) ]
Die Sache mit deinem TCCR1A=0x91; gefällt mir auch nicht, ist aber geschmackssache. Ich finde es nur umständlich die HEX-Werte in binäre umrechnen zu müssen um zu wissen welche Bits gesetzt wurden, deswegen mach ich das immer wie schon oben beschrieben. Wenn du dich damit nicht anfreunden kannst, dann mach wenigstens den Kompromiss binäre werte zu verwenden wenn du in Register schreibst (also statt dem 0x91 eben 0b10010001, ist zwar länger aber ich weiss sofort welche Bits gesetzt werden).
z.B.: "// 122,10546875 ist "einfacher" Sinus mit 8Mhz und 8-bit PWM
"
Wo kommt da das 122,10546875 her. Das weiss ein Anfänger sicherlich nicht [ und du in einem Jahr bestimmt auch nicth mehr ;) ]
Die Sache mit deinem TCCR1A=0x91; gefällt mir auch nicht, ist aber geschmackssache. Ich finde es nur umständlich die HEX-Werte in binäre umrechnen zu müssen um zu wissen welche Bits gesetzt wurden, deswegen mach ich das immer wie schon oben beschrieben. Wenn du dich damit nicht anfreunden kannst, dann mach wenigstens den Kompromiss binäre werte zu verwenden wenn du in Register schreibst (also statt dem 0x91 eben 0b10010001, ist zwar länger aber ich weiss sofort welche Bits gesetzt werden).
Jaaaa, zeigs ihm :D Aber die 0b10101101 schreibweise kenn ich in C gar nicht und ein test hat mir auch "error: invalid suffix "b10010" on integer constant" beim compilieren entgegengeworfen (gcc), ist das ein avr-gcc ding, oder stell ich mich zu doof an? hab einfach mal: int a = 0b0010101; versucht aber das will nich, klär mich auch... ich persönlich bevorzuge aber auch eher einfach a = (1<
joa, 0b0010101 ging bei mir auch noch nie, ich hätts auch viel lieber so geschrieben..und den Rest, ja, beim nächsten Projekt trenn ichs dann sauber auf!
Ah jo, aber ich kenn das auch immer will man die blöden XYZJ-Bezeichnugngen auch nich schreiben - aber zumindestens ein a = (1<<4)|(1<<6) verschafft schon ein mörder vorteil gegenüber 0x50... gesetzte bits sehen, da hat unser "gast" schon recht...
bei mir (AVR Studio+GCC) klappt sowas ohne Probleme:
"uint8_t z=0b00000101;"
So eone Schreib weise nehm ich aber auch eher seltener, meist nur wenns um Bit-geschiebe geht^^
"uint8_t z=0b00000101;"
So eone Schreib weise nehm ich aber auch eher seltener, meist nur wenns um Bit-geschiebe geht^^
hmm kann mir vorstellen, dass AVR Studio das noch über nen eigenen preprozessor laufen läßt, würde sich auch anbieten, da es für die hardwarecoderei eh oft auf 0bXXXXXXXX hinaus läuft würde sich das glatt anbieten... Hab jetzt auch nochmal speziell bissi rumgegoogelt und rausgefunden, dass es sich hierbei um eine nicht standard-gcc-extension handelt, also kein ANSI-C standard, eigentlich schade.
ich muss jetzt trotzdem noch mal auf diesem Kommentar rumreiten sry:
"// 122,10546875 ist "einfacher" Sinus mit 8Mhz und 8-bit PWM
"
1. Wie errechnest du die einzelnen Frequenzen (wäre für einen Anfänger wichtig, vor allem wenn er andere Frequenzen benötigt)
2. wo kommen dann die 122,... her
3. der µC arbeitet bestimmt mit 8MHz, aber sicherlich nicht der Sinus, oder?
4. woher bzw. wie hast du die Sinus Tabelle erstelle (falls man dieser aufbohren möchte)
5. warum ein 2 dimensionales array für den sinus, hat sich ja eigentlich nun erledigt, da du es anders gelöst hast
6. sry für das ganze Gemeker/Nörgeln
"// 122,10546875 ist "einfacher" Sinus mit 8Mhz und 8-bit PWM
"
1. Wie errechnest du die einzelnen Frequenzen (wäre für einen Anfänger wichtig, vor allem wenn er andere Frequenzen benötigt)
2. wo kommen dann die 122,... her
3. der µC arbeitet bestimmt mit 8MHz, aber sicherlich nicht der Sinus, oder?
4. woher bzw. wie hast du die Sinus Tabelle erstelle (falls man dieser aufbohren möchte)
5. warum ein 2 dimensionales array für den sinus, hat sich ja eigentlich nun erledigt, da du es anders gelöst hast
6. sry für das ganze Gemeker/Nörgeln
Keine Sorge, das brauch der :D Ausserdem ist konstruktive Kritik doch mal echt nützlich! Wenn der das mal alles anständig zu "Papier" bringen würde, dann könnte man das dann sicher auch mit unseren neuen fancy Suchfunktion finden^^ blingbling
"( eine Periode ist immer einmal hochzählen zum Compare-Wert, und anschliessend runterzählen)."
ist so nicht ganz richtig, eine Periode ist eigentlich hochzählen bis zm Vergleichswert, dann Schalten, dann weiterzählen bis zur Obergrenze (bei dir 255), dann wieder runterzählen, beim Vergleichswert wieder Schlaten, bis 0 weiterzählen und dann wieder von vorn. Also nicht nur bis zum Compare Wert zählen, sondern schon bis zur Obergrenze, halt nur beim Compare Wert die entsprechende Aktion ausführen (je nachdem ob invertierend oder nicht). Schau dir am Bestem mal das Bild hier an:http://www.mikrocontroller.net/wikifiles/a/a9/PWM_Theorie_3.gifZitat von oben:
"eine Periode bei der PWM besteht immer aus einmal hochzählen und dann wieder runterzählen. Jeweils beim eingestellten camparewert wird dann eine Aktion ausgeführt (je nach gesetzten Registern)"
ist so nicht ganz richtig, eine Periode ist eigentlich hochzählen bis zm Vergleichswert, dann Schalten, dann weiterzählen bis zur Obergrenze (bei dir 255), dann wieder runterzählen, beim Vergleichswert wieder Schlaten, bis 0 weiterzählen und dann wieder von vorn. Also nicht nur bis zum Compare Wert zählen, sondern schon bis zur Obergrenze, halt nur beim Compare Wert die entsprechende Aktion ausführen (je nachdem ob invertierend oder nicht). Schau dir am Bestem mal das Bild hier an:http://www.mikrocontroller.net/wikifiles/a/a9/PWM_Theorie_3.gifZitat von oben:
"eine Periode bei der PWM besteht immer aus einmal hochzählen und dann wieder runterzählen. Jeweils beim eingestellten camparewert wird dann eine Aktion ausgeführt (je nach gesetzten Registern)"
haha, du bist halt echt geil - du hast den text bestimmt öfter (oder auch einfach aufmerksamer gelesen) als wir alle zusammen^^ aber ne findsch klasse, ich sauge so zusatzinfos auf - meeeehr wissen ... Aber, wenn man Kritik übt, darf man gerne auch seinen Namen sagen, Herr "gast"^^ wir beißen weniger oft als es den Anschein hat
ich bin hier eher zufällig reingestolpert, da ich mich auch wegen sinuserzeugung mit AVR beschäftigt habe und den thread auf www.mikrocontroller.net gefunden hab. muss leider zugeben, dass ich so genau gar nicht gelesen hab, aber zahlen stechen im text dann schon heraus und da liest man auch mal genauer.
gerade da waren dann auch die kleinen ungenauigkeiten.
ich muss auch zugeben, dass ich eine pwm beim avr bis jetzt auch noch nie gebraucht/benutzt habe, aber durch den thread auf mikrocontroller.net und den hier hab ich mich mal eingelesen. durch die kritische diskussion mit euch hab ich dann auch noch einiges dazugelernt und tobias hoffentlich auch ;)
man(n) schaut sich die entsprechenden register und deren funktion ja dann auch mal genauer an. will ja auch nichts falsches schreiben.
mich würde trotzdem interessieren, wie die sinus tabelle erstellt wurde. das waren zwischendurch ja auch mal 2 tabellen (mit 100 und 300 hz). dies ist aber keine der beiden. also wie wurde diese erstellt und bei welcher frequenz? (da ich nicht weiss welche tonleiter du verwendest - hast ja die "frequenzen"/scalewerte im code definiert). in der c-dur tonleiter hat ein c ja 132hz (c' 264hz und c'' 528hz). würde ja bedeuten, dass deine definierten 542 einer frequenz von 132hz entsprechen würden, oder? macht dann ca ein verhältnis von 4,1 (also 132*4,1=542). richtig?
ach ja, mein name ist lars n.
gerade da waren dann auch die kleinen ungenauigkeiten.
ich muss auch zugeben, dass ich eine pwm beim avr bis jetzt auch noch nie gebraucht/benutzt habe, aber durch den thread auf mikrocontroller.net und den hier hab ich mich mal eingelesen. durch die kritische diskussion mit euch hab ich dann auch noch einiges dazugelernt und tobias hoffentlich auch ;)
man(n) schaut sich die entsprechenden register und deren funktion ja dann auch mal genauer an. will ja auch nichts falsches schreiben.
mich würde trotzdem interessieren, wie die sinus tabelle erstellt wurde. das waren zwischendurch ja auch mal 2 tabellen (mit 100 und 300 hz). dies ist aber keine der beiden. also wie wurde diese erstellt und bei welcher frequenz? (da ich nicht weiss welche tonleiter du verwendest - hast ja die "frequenzen"/scalewerte im code definiert). in der c-dur tonleiter hat ein c ja 132hz (c' 264hz und c'' 528hz). würde ja bedeuten, dass deine definierten 542 einer frequenz von 132hz entsprechen würden, oder? macht dann ca ein verhältnis von 4,1 (also 132*4,1=542). richtig?
ach ja, mein name ist lars n.
wow, cool, endlich mal interessierte Leser :-)
Das PWM-Pic hab ich direkt mal übernommen, hatte ich bis jetzt selbst noch nie gesehn, danke! Die Erklärung hab ich auch entsprechend abgeändert.
Die Sinus-Tabelle hab ich mir mit nem c++-Programm erstellt (hab ich grad nicht hier, folgt am Dienstag). Dazu habe ich eine enzige komplette Sinuswelle in 256 Werte kodiert. Ich hab dann mit obiger Rechnung (256 Werte pro PWM-Durchlauf ) ausgerechnet, welche Frequenz das im Endeffekt gibt.
Die Frequenzen für die Noten stimmen glaube ich gar nicht, kanns aber auch nicht mehr nachvollziehen, die Gleichungen stehen alle auf meinem Whiteboard, die schreibe ich am Dienstag dann auch nochmal hier rein!
Das PWM-Pic hab ich direkt mal übernommen, hatte ich bis jetzt selbst noch nie gesehn, danke! Die Erklärung hab ich auch entsprechend abgeändert.
Die Sinus-Tabelle hab ich mir mit nem c++-Programm erstellt (hab ich grad nicht hier, folgt am Dienstag). Dazu habe ich eine enzige komplette Sinuswelle in 256 Werte kodiert. Ich hab dann mit obiger Rechnung (256 Werte pro PWM-Durchlauf ) ausgerechnet, welche Frequenz das im Endeffekt gibt.
Die Frequenzen für die Noten stimmen glaube ich gar nicht, kanns aber auch nicht mehr nachvollziehen, die Gleichungen stehen alle auf meinem Whiteboard, die schreibe ich am Dienstag dann auch nochmal hier rein!
hi,
i'd like to reuse some source for the µC open source project located at www.ethersex.de. Unfortunately you have not mentioned any license for the source. Best would be GPLv2+ ort GPLv3+ and so we could add your code for good.
If interested please reply my mail send to your email-address.
char
i'd like to reuse some source for the µC open source project located at www.ethersex.de. Unfortunately you have not mentioned any license for the source. Best would be GPLv2+ ort GPLv3+ and so we could add your code for good.
If interested please reply my mail send to your email-address.
char
hi habo!
sry, i didnt receive a mail regarding this project...however, if you come to read this again, here's my answer, for you and everyone else:
please use this project in any way you want, do whatever you want with it, and, if you are willing to do so, please leave a comment telling us what you've done with it!
sry, i didnt receive a mail regarding this project...however, if you come to read this again, here's my answer, for you and everyone else:
please use this project in any way you want, do whatever you want with it, and, if you are willing to do so, please leave a comment telling us what you've done with it!
Warum hochzählen und wieder runterzählen? Im Fast PWM Mode zählt der µC nur hoch und beginnt dann bei 0 -> doppelte Frequenz wie Phase Correct PWM Mode(hoch und runterzählen)

nicht 256 sonder 255
"Das heisst, man braucht 256 Werte (8-bit), die zwischen 0 und 256 liegen"
die Werte liegen zwischen 0 und 255
"Die Frequenz der PWM beträgt mit 8Mhz und 8-bit Counter ca. 32kHz."
eine Periode bei der PWM besteht immer aus einmal hochzählen nd dann wieder runterzählen. Jeweils beim eingestellten camparewert wird dann eine Aktion ausgeführt (je nach gesetzten Registern).
d.h Ausgangsfrequenz = (Quarzfrequenz/Prescale ) /(Timerauflösung*2)
Hier ist das *2 wichtig, dadurch hast du nämlich nur die halbe Frequenz. Also statt 31250Hz, hast du eine PWM mit 15625Hz.
Um den Code übersichtlich zu gestalten solltest du sowas TCCR1B=0x01; vermeiden, damit kannst du und auch kein anderer was mit anfangen. Da muss man ja das komplette Register im Kopf haben. Wenn du dir den Code in einem Jahr noch mal anschaust, siehst du gar nicht mehr durch. Schreib lieber sowas :
TCCR1B = (1<
Ich möchte dich hier nicht entmutigen, ist schon ein klasse Einsteigerprojekt. Hoffe es macht dir Spaß. Weiter so...