Go Down

Topic: Generating a 20khz sine wave (Read 10262 times) previous topic - next topic

specialjack

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!

CrossRoads

Use micros();
Code: [Select]

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

specialjack

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

larryd

#3
Feb 05, 2014, 01:43 am Last Edit: Feb 05, 2014, 08:07 pm by LarryD Reason: 1
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.
No technical PMs.
If you are asked a question, please respond with an answer.
If you are asked for more information, please supply it.
If you need clarification, ask for help.

CrossRoads

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

larryd

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)
No technical PMs.
If you are asked a question, please respond with an answer.
If you are asked for more information, please supply it.
If you need clarification, ask for help.

CrossRoads

Yeah, might have missed by one.
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.

CrossRoads

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

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

specialjack


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

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?

TRGT8

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.

CrossRoads

#10
Feb 12, 2014, 03:05 am Last Edit: Feb 12, 2014, 03:15 am by CrossRoads Reason: 1
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.
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.

visualxl

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.

Code: [Select]

#include <toneAC.h>

int frequency = 20000;

void playFrequency() {
  toneAC(frequency);
}

void setup() {
}

void loop() {
  playFrequency();
}

DVDdoug

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.

Grumpy_Mike

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.

Go Up