First, the idiom for setting up control registers is to use the constants that avr-libc defines, eg
TCCR1A = _BV(COM1B0) // toggle OC1B on compare match
| _BV(WGM10)
| _BV(WGM11);
TCCR1B = _BV(WGM12)
| _BV(WGM13); // Fast PWM mode, OCR1A as TOP
(
_BV(x) is defined as
(1 << (x)))
Second, since we are just generating a square wave, I would toggle on compare match instead of setting OCR1A/B to 50% of the top value. Since we are changing top, lets use OCR1A as top because it is double buffered.
I would avoid floats entirely, so here's how to convert for toggle on compare match:
65Hz = F_CPU / ((top + 1) * 2 * prescale value)
solving for top we have
top = (F_CPU / (65Hz * 2 * prescale)) - 1
top = (16,000,000 / (65Hz * 2 * prescale = 1)) - 1 = 123075
ok, so a prescale value of 1 is too fine a resolution (the max for top is 0xFFFF = 65535). Let's try a div 8 prescale:
top = (16,000,000 / (65Hz * 2 * prescale =

) - 1 = 15383
ok, now for 2k:
top = (16,000,000 / (2000Hz * 2 * prescale =

) - 1 = 499
ok, so top is going from 15383 to 499, and the prescale is div 8.
void setup() {
pinMode(10, OUTPUT);
TCCR1A = _BV(COM1B0) // toggle OC1B on compare match
| _BV(WGM10)
| _BV(WGM11);
TCCR1B = _BV(WGM12)
| _BV(WGM13); // Fast PWM mode, OCR1A as TOP
OCR1B = 0; // toggle when the counter is zero
OCR1A = 15383; // set top to the initial 65Hz
TCCR1B |= _BV(CS11); // set prescale to div 8 and start the timer
}
void loop() {
for (uint16_t top = 15383; top >= 499; top--) {
OCR1A = top;
delay(10);
}
}