Ultrasonic tones generate audible static

Hi, just started with my first ardiuno leonardo to create a tone generator that sweeps from 20khz to 25khz. When doing this, I get some popping and static. Is there something I can do to fix it? Would using a sound shield and playing a wav file of these tones get better results? Thanks for any suggestions.

Here's the code I tried:

void loop() {
int minVal = 20000;
int maxVal = 25000;

for(int i = minVal; i < maxVal; i+=100) {
tone(7,i);
delay(2);
}
}

Would using a sound shield and playing a wav file of these tones get better results?

No because a sound shield will not produce sound that high a frequency.

It sounds like the tone function has not got so fine frequency control at that high a frequency.
It would be better to use an external tone generator chip for this sort of thing.

Search for my post "piano tones micros" to see how I created a bunch of tones using blink without delay style programming. Can do the same with 1/2 periods ranging from
20KHz = 25uS half period
25KHz = 20uS half period

Hi CrossRoads,

I looked at your post but I don't exactly understand what I am looking at (and there is a bunch of unrelated note code). Based on some other readings, I assume you are changing some timers/clocks to generate the desired frequencies? BTW, I have an Atmega32U4 (leonardo) vs. the Uno. I am getting errors when trying to compile some samples that play with the timers.

Here is my sample code that basically generates a sweep through the desired frequencies when debug = 0, and an audible 5k range when debug != 0; How can I achieve the same without generating static popping artifacts in the audio? Maybe using analogWrite()?

int debug = 1;
int pinOut = 7;
int minFreq = 20000;
int maxFreq = 25000;
int freq = minFreq;
int wait = 10;
int freqIncr = wait * 10;

void setup() {
  if(debug != 0) {
    minFreq = 1000;
    maxFreq = 6000;
    freq = minFreq;
  }

  //Serial.begin(9600);
}

void loop() {
  
  //Serial.println(freq);
  
  tone(pinOut,freq);
  delay(wait);
    
  freq += freqIncr;
  if(freq > maxFreq) {
    freq = minFreq;
    //delay(3000);
  }
}

Is it possible to get static free audio from my arduino? Or should I be looking for some other hardware?

Could be a code problem with tone. For a while there was a bug with tone, where you needed to add this (for pin 6 for example):
noTone(6); //apparent known bug - need this for the tone to play next.

For example, I have this to make a warble output

for (thisNote = 0; thisNote < 8; thisNote++) 
  {
    // to calculate the note duration, take one second 
    // divided by the note type.
    //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
    noteDuration = 1000/noteDurations[thisNote];
    noTone(6);       //apparent known bug - need this for the tone to play next.
    tone(6, melody[thisNote],noteDuration);
    // to distinguish the notes, set a minimum time between them.
    // using the note's duration + 10%:
    pauseBetweenNotes = noteDuration * 1.10;
    delay(pauseBetweenNotes);
    // stop the tone playing:
    noTone(6); 
  }

My other program just uses blink without delay style programming to watch time pass and change the state of the output pin. That has no static in the output. You could do the same, so something like this:

// define variable, setup, etc. All time related variables are unsigned long.
void loop(){
currentMicros = micros();
elapsedTone = currentMicros - previousTone; // how long since last output change
elapsedTime = currentMicros - previousTime; // how long since last period (frequency) change
if (elapsedTone >= halfPeriod){
previousTone = previousTone + halfPeriod;
PIND = 0b00000100; // PORTD, bit 2 for an  output for example
}
if (elapsedTime >= 10mS){
previousTime = previousTime + 10mS;
halfPeriod = halfPeriod + 10; // or whatever the change amount is
if (halfPeriod >= maxPeriod){ halfPeriod = minPeriod;}
}
// add debug test in as needed
}

Thanks CrossRoads, I hope to play with the code tonight. I am not exactly sure what the PIND statement does yet, so I'll have to do some reading.

Thanks for the examples.

writing a 1 to the PINx (A,B,C,D) register toggles that bit.
Its a form of Direct Port Manipulation.

Could also try
PIND = PIND | 0b00000100;

or keep track of the state of the bit and manipulate it this way:

if (time to change the output, to paraphrase){
tonebit = 1 - toneBit;   // result is 1,0,1,0
if (toneBit ==0){
PORTD = PORTD & 0b11111011; // clear bit 2
  }
else{
PORTD = PORTD | ob00000100; // set bit 2
  }
}

Hi CrossRoads,

I tried the PIND method and was able to generate tones, but I am getting more static from the device than with tone().

I am thinking of trying to use a 555 instead.

Thanks for the help.

Ready to try reply #1 yet?

hello, am working on a mosquito repellent device, on using the tone library i set the frequency to 35kHz. but the output sound on a piezo buzzer is very audible and loud, but it is said that ultrasonic sounds can't be heard by human. please i need help if am doing anything wrong

void loop() {
analogWrite(red, 250);
analogWrite(green, 70);
delay(1000);
tone(3, 35000, 20000); //seting the freq to 40KHz on pin 3 for 20s
delay(200);
}

kernelk:
Hi, just started with my first ardiuno leonardo to create a tone generator that sweeps from 20khz to 25khz. When doing this, I get some popping and static. Is there something I can do to fix it?

You are hearing real sounds that the tone generator is making - it is not band-limiting the output so the glitches at tone start and end have low frequency components, which you can hear. Starting a square wave from scratch has a substantial energy component across all frequencies.

You could use a high-pass filter with quite a steep cutoff to pass 20kHz and block 16kHz - this isn't easy.

A better approach is to use a DDS tone generator - changing the frequency then is done with phase continuity which reduces splatter vastly, except at start up - for that you need to ramp up the amplitude envelope smoothly.

Please note this is a thread from 2014 and the OP is no longer a member.