Tones

It seems that there are "blind spots" in the continuum of lower frequencies. I have tried to fudge and compensate to no avail. 936 Hz is the current mystery, I can achieve 932 and 939, but nothing in-between.

I have tried desktop and web editor, tone and PWM.

tone(13,932,30000);
delay(100);

Any help??

What do you mean by "nothing in-between"? No output at all or just no change in the output?
What are you outputting the tone to?

I'm trying to generate a continuous 936Hz DC pulse, I'm reading results with a Newport frequency counter.
I program 933, 934, 935, 936, 937, 938 etc, and the only frequency emitted is 939. Programming 932Hz generates a 932 signal.

This is a mathematical artifact of the particular method that Arduino uses on the AVRs to generate the tone. One of the Timer peripherals (Usually Timer2 for these kinds of things) is used to create a periodic interrupt, and each time the interrupt occurs the output pin is toggled.

I assume you are using an Uno, Mega, Leonardo, or a derivative of one of those. Without going into the derivation, the formula for calculating the output frequency is this:

Tone = F_CPU / 2 / PRESCALER / (TOP+1)

The tone function goes through the trouble of calculating the Prescaler and Top values for you, so you never see this part of it. As I'll show you though, you can't ignore this part under the hood because it's what's causing what you see.

F_CPU on most AVR Arduino boards is 16 MHz. Some are clocked at 8 MHz, but those are usually specialty variants like a Pro Mini.

The prescaler is used to slow down the clock from the main 16 MHz frequency. On Timer2 it can only have a value of 1, 8, 32, 64, 128, 256, or 1024.

Top sets the period of the signal, and can be an integer value between 0 and 255 inclusive.

Because the Top and Prescaler values are in the denominator of the calculation instead of the numerator, the output frequencies are not distributed equally in the range. Reducing the Top value increases the frequency, and because it has such a small range there will obviously be gaps between the outputs for adjacent inputs. I ran the calculations in Excel for different Prescaler and Top values and this is what showed up in the /64 prescaler table:

TOP | Frequency

130 | 954.1984733
131 | 946.969697
132 | 939.8496241
133 | 932.8358209
134 | 925.9259259
135 | 919.1176471
136 | 912.4087591

That explains your gap. Because it's not possible for Top to be between 132 and 133, it's not possible for the tone() function, as it is currently written, to generate a frequency between 932 Hz and 939 Hz.

Also note that this has nothing to do with "high" or "low" frequencies. Due to the effect of the prescaler, this distribution will be repeated through a few octaves.

It could probably be improved by using the 16-bit Timer1, which would let it use a lower prescaler setting and thus have less spacing between the frequency outputs, but this would require writing a new library if one has not already been written. Not an impossible task, but one that would require some study.

The best method for precise frequency generation is to use a numerically controlled oscillator that uses the phase accumulation technique. The AD9833 is one such chip that can also do direct digital synthesis of square and sine waves with an integrated DAC. With a 25 MHz clock, it can generate any frequency between 0 - 12.5 MHz in 0.1 Hz increments. A 1 MHz clock lets you specify 0.004 Hz increments, a truly insane level of precision. With phase accumulation, the frequency output is directly proportional to the setting, not inversely proportional, so the frequency outputs are all evenly spaced.

If you just want to make beeps with a speaker, using an external NCO/DDS chip is way overkill. Stick with tone(), flaws and all, since its' free. But if you're trying to DIY a piece of test equipment (like a function generator), you probably want the extra precision of an NCO.

AD9833 - Programmable Waveform Generator.pdf (687 KB)

Jiggy-Ninja:
It could probably be improved by using the 16-bit Timer1, which would let it use a lower prescaler setting and thus have less spacing between the frequency outputs, but this would require writing a new library if one has not already been written. Not an impossible task, but one that would require some study.

http://playground.arduino.cc/Code/ToneAC

I knew there had to be one.

Wow! Thank you both! I will pursue both possibilities. Yes, I have Uno.

I downloaded the ToneAC but am not able to verify a sketch with it. Are there elements here that I need to discard?

#include <toneAC.h>

void setup() {} // Nothing to set up, just start playing!

void loop() {
for (unsigned long freq = 150; freq <= 15000; freq += 10){
toneAC(936); // Play the frequency (150 Hz to 15 kHz).
delay(1); // Wait 1 ms so you can hear it.
}
toneAC(0); // Turn off toneAC, can also use noToneAC().

while(1); // Stop.
}

Please use code tags (</> button on the toolbar) when you post code or warning/error messages. The reason is that the forum software can interpret parts of your code as markup, leading to confusion, wasted time, and a reduced chance for you to get help with your problem. This will also make it easier to read your code and to copy it to the IDE or editor. Using code tags and other important information is explained in the How to use this forum post. Please read it.

When you encounter an error you'll see a button on the right side of the orange bar "Copy error messages". Click that button. Paste the error in a message here using code tags.

How many cycles of 150Hz tone do you expect to see in 1ms?

Thank you all for all the information and help! I eventually accomplished all I needed with PWM in microseconds. :slight_smile: