Hello I am interested in generating a square wave to do a sweep from 10Hz to say 500KHz. Ideally I would like the step size to be 10 Hz in the lower frequency range and it can be 100Hz in the higher frequency range (flexible on this) but want to capture as much of the lower frequency as possible. I found this code but can only get it to go from 15Hz to 4Khz with pre scale factor of 8, and if I play around with the pre scale factor (pre scale factor of 1) I can go up to 32Khz, but my lower end frequency starts at 100Hz or so. Any help would be appreciated.
Here's the accompanying comments that came from the original author, note he was referring to different frequency range: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1231029366
"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 = 8)) - 1 = 15383
ok, now for 2k:
top = (16,000,000 / (2000Hz * 2 * prescale = 8)) - 1 = 499"
void setup() {
pinMode(9, OUTPUT);
TCCR1A = _BV(COM1A0)
| _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 i left this alone i didn't mess with it
TCCR1B |= _BV(CS11); // set prescale to div 8 and start the timer
}
void loop() {
unsigned int top;
for (unsigned int note_val = 15; note_val < 4000; note_val++) // g from 15hz to 4KHz
{
top = (16000000 / (note_val * 2 * 8)) -1;
OCR1A = top;
delay(100);
}
}
I think you will have to change the prescale value on the fly to get the full range. A good starting point would be the built-in tone() function. You can greatly simplify it by using a specific timer.
// frequency (in hertz) and duration (in milliseconds).
void tone(uint8_t _pin, unsigned int frequency, unsigned long duration)
{
uint8_t prescalarbits = 0b001;
long toggle_count = 0;
uint32_t ocr = 0;
int8_t _timer;
_timer = toneBegin(_pin);
if (_timer >= 0)
{
// Set the pinMode as OUTPUT
pinMode(_pin, OUTPUT);
// if we are using an 8 bit timer, scan through prescalars to find the best fit
if (_timer == 0 || _timer == 2)
{
ocr = F_CPU / frequency / 2 - 1;
prescalarbits = 0b001; // ck/1: same for both timers
if (ocr > 255)
{
ocr = F_CPU / frequency / 2 / 8 - 1;
prescalarbits = 0b010; // ck/8: same for both timers
if (_timer == 2 && ocr > 255)
{
ocr = F_CPU / frequency / 2 / 32 - 1;
prescalarbits = 0b011;
}
if (ocr > 255)
{
ocr = F_CPU / frequency / 2 / 64 - 1;
prescalarbits = _timer == 0 ? 0b011 : 0b100;
if (_timer == 2 && ocr > 255)
{
ocr = F_CPU / frequency / 2 / 128 - 1;
prescalarbits = 0b101;
}
if (ocr > 255)
{
ocr = F_CPU / frequency / 2 / 256 - 1;
prescalarbits = _timer == 0 ? 0b100 : 0b110;
if (ocr > 255)
{
// can't do any better than /1024
ocr = F_CPU / frequency / 2 / 1024 - 1;
prescalarbits = _timer == 0 ? 0b101 : 0b111;
}
}
}
}
#if defined(TCCR0B)
if (_timer == 0)
{
TCCR0B = prescalarbits;
}
else
#endif
#if defined(TCCR2B)
{
TCCR2B = prescalarbits;
}
#else
{
// dummy place holder to make the above ifdefs work
}
#endif
}
else
{
// two choices for the 16 bit timers: ck/1 or ck/64
ocr = F_CPU / frequency / 2 - 1;
prescalarbits = 0b001;
if (ocr > 0xffff)
{
ocr = F_CPU / frequency / 2 / 64 - 1;
prescalarbits = 0b011;
}
if (_timer == 1)
{
#if defined(TCCR1B)
TCCR1B = (TCCR1B & 0b11111000) | prescalarbits;
#endif
}
#if defined(TCCR3B)
else if (_timer == 3)
TCCR3B = (TCCR3B & 0b11111000) | prescalarbits;
#endif
#if defined(TCCR4B)
else if (_timer == 4)
TCCR4B = (TCCR4B & 0b11111000) | prescalarbits;
#endif
#if defined(TCCR5B)
else if (_timer == 5)
TCCR5B = (TCCR5B & 0b11111000) | prescalarbits;
#endif
}
// Calculate the toggle count
if (duration > 0)
{
toggle_count = 2 * frequency * duration / 1000;
}
else
{
toggle_count = -1;
}
// Set the OCR for the given timer,
// set the toggle count,
// then turn on the interrupts
switch (_timer)
{
#if defined(OCR0A) && defined(TIMSK0) && defined(OCIE0A)
case 0:
OCR0A = ocr;
timer0_toggle_count = toggle_count;
bitWrite(TIMSK0, OCIE0A, 1);
break;
#endif
case 1:
#if defined(OCR1A) && defined(TIMSK1) && defined(OCIE1A)
OCR1A = ocr;
timer1_toggle_count = toggle_count;
bitWrite(TIMSK1, OCIE1A, 1);
#elif defined(OCR1A) && defined(TIMSK) && defined(OCIE1A)
// this combination is for at least the ATmega32
OCR1A = ocr;
timer1_toggle_count = toggle_count;
bitWrite(TIMSK, OCIE1A, 1);
#endif
break;
#if defined(OCR2A) && defined(TIMSK2) && defined(OCIE2A)
case 2:
OCR2A = ocr;
timer2_toggle_count = toggle_count;
bitWrite(TIMSK2, OCIE2A, 1);
break;
#endif
#if defined(TIMSK3)
case 3:
OCR3A = ocr;
timer3_toggle_count = toggle_count;
bitWrite(TIMSK3, OCIE3A, 1);
break;
#endif
#if defined(TIMSK4)
case 4:
OCR4A = ocr;
timer4_toggle_count = toggle_count;
bitWrite(TIMSK4, OCIE4A, 1);
break;
#endif
#if defined(OCR5A) && defined(TIMSK5) && defined(OCIE5A)
case 5:
OCR5A = ocr;
timer5_toggle_count = toggle_count;
bitWrite(TIMSK5, OCIE5A, 1);
break;
#endif
}
}
}