That solves a similar problem that I am trying to deal with, so I want to use this kind of code, except use the prescaler 1 instead of the prescaler 8, and extend the range to be 1500 Hz to 20,000 Hz, or top = about 10,000 to 800.
I tried uploading the code in that topic, but it didn't work, so i may be missing parts. In general I am not familiar with that kind of code, so I'm looking for help understanding what does what, so that i can start to tweak and modify it, and how I can use the fast pwm function to make the frequency generator (with sweep function)
my current code uses delayMicroseconds, but the frequency resolution is horrible in the desired range
I tried uploading the code in that topic, but it didn't work, so i may be missing parts.
"It didn't work" is awfully value, and could encompass everything from a failure to compile due to a missing library to complete destruction of your Arduino. Care to narrow it down a little?
It compiled, with an attached speaker there was no audio output.
You have other sketches that successfully make noise come out of the speaker? In other words, do you know it is a software, rather than a hardware, issue?
yes, i have other sketches that work, the problem is the frequency resolution,
my last code used delayMicroseconds for a 50% duty square wave output
but this only works with even integer periods, for example:
50 us/50 us = 100 us period = 10,000 Hz
49 us/49 us = 98 us period = 10,204 Hz, with no way to tune in between
and it gets worse at higher frequencies
The fast pwm function should give me much better resolution, i already used the formula to calculate the available frequency outputs, it's not perfect but it's better, i'll get 3 Hz resolution up to 7 kHz.
So now I just need help to learn how to use the fast pwm function, please.
If you want to generate frequencies, PWM is just an unnecessary complication. The three AtMega timers can be set to CTC (clear timer on compare match) mode and this is what you want for frequency generation. Timer1 (16-bit) will you give you both a wide range and excellent resolution.
If you create a small spreadsheet, the formula to key in is as follows:
f = F_CPU / prescaler / 2 / (t1_value + 1)
F_CPU is CPU frequency (16MHz on Duemillanove) and t1_value is the counter compare value in the range from 0 to 65535. Prescaler can be either 1, 8, 64, 128, 256 or 1024.
For a specific frequency, you could calculate the actual frequency using any of the prescalers and then choose the best match.
To write a program for this, you need to read up on AtMega timers (either the datasheet, google or check the forum for help).
If you haven't done so already, you should also check out the Arduino Tone function which may come close to what you need.
that formula is effectively the same as the one used by fast pwm, i have already calculated out the exact values in a spread sheet
i have looked in the tech sheet, and read about timers, and searched the forums, and tone functions are not applicable, the topic i posted in the first post is almost exactly what i am trying to do except i want help adjusting it and understanding it
The problem with using PWM is that you must maintain a 50% duty cycle. This need to maintain the 50% duty cycle limits your resolution and range significantly. PWM is for pulse width modulation, not frequency generation, which to your advantage is much simpler.
This is from the post you referred to:
So for a 50% on/off squarewave OCR1A should equal /2 of ICR1. I think this is right anyway. I only bought a Arduino a couple of weeks ago and the atmel pdf is heavy going.
He doesn't really know what he's doing and although you may put in the effort to follow where he left off there is a better and simpler way.
Ok, thank you for your wisdom, I will look into the CTC timer function on the tech sheet and see what i can learn, do you know of the right keywords i would use to find an example of this function being used?
Here's a small test program to generate frequencies in the range from 1 to 65535 Hz on digital pin 9. This program is using timer1 in CTC mode 5. Use "play(0)" to disable frequency output.
void setup()
{
Serial.begin(57600);
Serial.println("Frequency Generator");
// configure timer1 for CTC operation
// frequency will be on digital pin 9
TCCR1A = _BV(COM1A0); // toggle pin 9 on compare match
TCCR1B = _BV(WGM12) | _BV(CS10); // CTC mode 5, prescale = 1
}
void play(word frequency)
{
if (frequency == 0) { // stop frequency output
DDRB &= ~_BV(PORTB1); // disable output on digital pin 9
return;
}
// calculate timer compare value for desired frequency
OCR1A = F_CPU / 1 / 2 / frequency - 1;
DDRB |= _BV(PORTB1); // enable output on digital pin 9
}
void loop()
{
// sweep frequencies in 1kHz increments and 1s intervals from 1kHz to 20kHz
for (byte i = 1; i <= 20; i++) {
play(i * 1000);
Serial.print(i, DEC);
Serial.print("kHz (");
Serial.print(F_CPU / 1 / 2 / (OCR1A + 1),DEC);
Serial.println(")");
delay(1000);
}
}
For each step, the desired and actual frequency is displayed (actual in parenthesis). An improvement might be to reconfigure on the fly for the optimum prescaler based on desired frequency.