Go Down

Topic: Ultrasonic tones generate audible static (Read 2951 times) previous topic - next topic

kernelk

Jan 24, 2014, 10:38 am Last Edit: Jan 26, 2014, 08:01 pm by kernelk Reason: 1
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);
 }
}

Grumpy_Mike

Quote
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.

CrossRoads

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
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

kernelk

#3
Jan 25, 2014, 07:17 am Last Edit: Jan 25, 2014, 11:26 am by kernelk Reason: 1
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()?

Code: [Select]

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);
 }
}


kernelk

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

CrossRoads

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
Code: [Select]

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:
Code: [Select]

// 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
}
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

kernelk

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.

CrossRoads

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:
Code: [Select]

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
  }
}
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

kernelk

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.

Grumpy_Mike


Go Up