Here is a Frequency Sweep example I wrote a while back, modified slightly to better fit your requirements.
const uint32_t HighestFrequency = 5000;
const uint32_t LowestFrequency = 500;
const uint32_t LowestDivisor = (F_CPU / HighestFrequency) / 2;
const uint32_t HighestDivisor = (F_CPU / LowestFrequency) / 2;
const uint32_t TotalSteps = HighestDivisor - LowestDivisor;
const uint32_t MicrosecondsForSweep = 500000ul;
void setup()
{
Serial.begin(115200);
delay(200);
// Stop Timer/Counter1
TCCR1A = 0; // Timer/Counter1 Control Register A
TCCR1B = 0; // Timer/Counter1 Control Register B
TIMSK1 = 0; // Timer/Counter1 Interrupt Mask Register
// Set to Timer/Counter1 to Waveform Generation Mode 12: CTC, TOP in ICR1
TCCR1B |= (1 << WGM13) | (1 << WGM12);
// Enable OCR1A (Pin 9) Toggle on Compare match
pinMode(9, OUTPUT);
TCCR1A |= (1 << COM1A0);
OCR1A = 8;
}
void loop()
{
const uint32_t MAX_TOP = 0xFFFFUL;
for (uint32_t divisor = HighestDivisor; divisor > LowestDivisor; divisor--)
{
// Clear the clock select bits
TCCR1B &= ~((1 << CS12) | (1 << CS11) | (1 << CS10));
if (divisor <= MAX_TOP)
{
ICR1 = divisor;
TCCR1B |= (1 << CS10);
}
else if ((divisor / 8) <= MAX_TOP)
{
ICR1 = divisor / 8;
TCCR1B |= (1 << CS11);
}
else if ((divisor / 64) <= MAX_TOP)
{
ICR1 = divisor / 64;
TCCR1B |= (1 << CS11) | (1 << CS10);
}
else if ((divisor / 256) <= MAX_TOP)
{
ICR1 = divisor / 256;
TCCR1B |= (1 << CS12);
}
else
{
ICR1 = divisor / 1024;
TCCR1B |= (1 << CS12) | (1 << CS10);
}
delayMicroseconds(MicrosecondsForSweep / TotalSteps); // Adjust to get the desired sweep time.
}
}