Generating a 20khz sine wave

Hi, I'm trying to generate a 20khz tone that could be picked up by speakers around a small room.

I have tried just using the tone function, but I seem to be getting a lot of subharmonics also and the sound it makes is really annoying. Ideally, the sound will be inaudible for most people.

However, I've also been just using some cheap computer speakers. I'm not really sure, but I think I may need to use something like a super horn tweeter or something instead.

So, (I know very little about all this) my questions are:

  1. What is the best way to generate the sound with an arduino uno?
  2. What type of speaker would be ideal to play the sound from?

Thanks!

Use micros();

// declare variables, pinMode, etc.
void loop(){
while(1){
if ( (micros() - nextMicros) >=25){ // 20KHz = 50uS period
  nextMicros = nextMicros + 25;
  PIND = 0b00000100;  // output on PortD-2 (is D3?)
  }
 }
}

Will measure 20.0004 to 20.0008 KHz or so on a frequency analyzer. I have an Uno running this right now.

Could you post the full code? I don't really know how micros() works or much about arduino programming in general.

If you want a sine wave you will need to integrate the o/p signal seen on the Arduino as it is 0V 5V digital.

// declare variables, pinMode, etc.
unsigned long nextMicros;
void setup(){
pinMode (3, OUTPUT);
}
void loop(){
while(1){
if ( (micros() - nextMicros) >=25){ // 20KHz = 50uS period
  nextMicros = nextMicros + 25;
  PIND = 0b00000100;  // output on PortD-2 (is D3?)
  }
 }
}

I think that's all you need.

For D3, on the UNO, rather than:
PIND = 0b00000100; // output on PortD-2 (is D3?)
I believe Crossroads means:
PIND = 0b00001000; // output on PortD-3 (is D3)

Or use:
pinMode (2, OUTPUT);
. . .
PIND = 0b00000100; // output on PortD-2 (is D2)

Yeah, might have missed by one.

Here's the code I actually have running - was on a different PC than my original submittal:

const byte triggerOut = 2;

unsigned long nextMicros;
//unsigned long duration = 200UL; // flip every 200uS = 2.5KHz pulse
unsigned long duration = 25UL; // flip every 50uS = 20KHz pulse

void setup(){
  pinMode (triggerOut, OUTPUT);
  digitalWrite(triggerOut, LOW);
}
void loop(){
  while (1){
    if ((micros() - nextMicros) >= duration){
      nextMicros = nextMicros + duration;
      PIND = 0b00000100; // toggle output by writing PINx register
    }
  }
}

CrossRoads:
Here's the code I actually have running - was on a different PC than my original submittal:

const byte triggerOut = 2;

unsigned long nextMicros;
//unsigned long duration = 200UL; // flip every 200uS = 2.5KHz pulse
unsigned long duration = 25UL; // flip every 50uS = 20KHz pulse

void setup(){
  pinMode (triggerOut, OUTPUT);
  digitalWrite(triggerOut, LOW);
}
void loop(){
  while (1){
    if ((micros() - nextMicros) >= duration){
      nextMicros = nextMicros + duration;
      PIND = 0b00000100; // toggle output by writing PINx register
    }
  }
}

hmm so when I run this code, I'm still getting a lot of other frequencies playing which I assume are subharmonics. any idea how to stop this?

My experience - you can't reach 20 kHz inside "loop" function.
You should modify the timer behavior of one of the timers and attache a interrupt function with your sampler code to this timer.

Specialjack, the '328Ps only 0-5V outputs, so you need to filter out the high frequencies that make up the corners.

TRTG8 - the code I posted makes 20 KHz - I have posted oscilloscope shots of it.

DS0017.BMP (1.37 MB)

I don't quite understand your question. But if I understand correctly, you want to generate a sound in 20kHz using an Uno?

If so, you may refer to my code below. I used it to generate an inaudible sound using PKM34EW piezo speaker. However, the range is very short. The piezo speaker has to be connected to pin 10, and 9 of the UNO.

#include <toneAC.h>

int frequency = 20000;

void playFrequency() {
  toneAC(frequency);
}

void setup() {
}

void loop() {
  playFrequency();
}

The PWM output will usually have subharmonics, but a square wave from a digital output will only have regular (higher frequency) harmonics which are not audible at 20kHz. However, non-linearity in your piezo or speaker might create audible subharmonics or resonances.

If you want a true sine wave, you'll need a DAC or audio shield (which has a DAC), or you can filter a square wave, but to filter-out all (or nearly all) of the harmonics, you'd need an active filter.

Is there any reasion why it has to be an arduino generating the tone? A simple hardware oscillator is so much eiser.

The extra sound you here are not sub harmonics but noise caused by jitter, caused by the interrupts going off that amongst other things update the millis and micros timers.