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