TOP ist in dem Fall kein Akronym. Top = oben
Ich habe oben zwei Artikel verlinkt. Da wird das mit Timer0 erklärt. Mit Oszi-Bildern und Code. Das muss man nur für Timer1 anpassen. Timer1 ist ein 16 Bit Timer und die Register sind etwas anders, aber das Prinzip ist genau das gleiche
Dazu brauchst du noch das Datenblatt:
https://cdn-shop.adafruit.com/datasheets/ATMEGA328P.pdf
Es gibt auch neuere Datenblätter, da Atmel inzwischen zu Microchip gehört, aber ich finde das etwas besser. z.B. steht die Register-Abkürzung in der Überschrift und nicht nur der vollständige Name.
Die Registerbeschreibung für Timer1 gibt es ab Seite 132
Grundeinstellungen, nicht getestet:
void setup()
{
pinMode(9, OUTPUT); //Pin auf Ausgang
ICR1 = 11110; //TOP = CPU Freq / Prescaler / gewünschte Frequenz - 1
TCCR1A = _BV(COM1A1) | _BV(WGM11); //Kanal A nicht-invertierend, Mode 14
TCCR1B = _BV(WGM12) | _BV(WGM13) | _BV(CS11); //Mode 14, Prescaler = 8
}
Das -1 wird oft in Tutorials unterschlagen. Ist auch nicht superwichtig da man selten eine extrem genaue PWM Frequenz braucht.
Duty Cycle wird über OCR1A eingestellt. Das ist ein 16 Bit Register, aber der gültige Wert geht von 0 bis <= TOP. Du kannst z.B. einen Prozent Wert von 0-100 auf 0-TOP umsetzen.
Eine weitere Kleinigkeit die man eventuell beachten muss ist dass auch bei OCR1A = 0 ein kurzer Impuls erzeugt wird. Siehe Datenblatt:
The extreme values for the OCR1x Register represents special cases when generating a PWM waveform output in the fast PWM mode. If the OCR1x is set equal to BOTTOM (0x0000) the output will be a narrow spike for each TOP+1 timer clock cycle.
Das ist nicht intuitiv. Die Arduino Software löst das einfach indem sie bei 0 den Pin mit digitalWrite() auf LOW setzt. Dadurch wird PWM automatisch deaktiviert. Das kannst du auch tun. Danach muss man wieder das COM1A1 Bit setzen damit wieder PWM läuft!
Am besten mit einem Oszilloskop überprüfen was da rauskommt, sonst ist es schwierig manche Problem festzustellen