Go Down

Topic: 50,000 sine waves from 400 square pulses? I'm baffled. (Read 609 times) previous topic - next topic

CosmickGold

Apr 20, 2015, 06:28 pm Last Edit: Apr 20, 2015, 10:02 pm by CosmickGold
I needed a low-frequency sine-wave generator, and after 5 days of focussed effort and research, finally have exactly what I need. But the process brought up some mind-bogglinq questions, the answers to which could possibly save me from 5 days of struggling in the future.

QUESTION 1:
The Arduino project at:
http://www.instructables.com/id/Arduino-Waveform-Generator/
states that using the Arduino UNO "It outputs four waveshapes: sine, triangle, pulse, and saw, each waveshape ranges in frequency from 1Hz-50kHz."
Yet the project at:
http://www.arduino.cc/en/Tutorial/DueSimpleWaveformGenerator
states that even using the Arduino DUO for it's much greater speed over the UNO, "maximum frequency for the signal with this sketch is around 170 Hz". Why the HUGE discrepency in how fast a board is needed, and how high a sine frequency can be produced?

QUESTION 2:
I have only the Arduino UNO board, on which my scope shows the analog output pins as pulsing rectangular waves at 400 pulses a second. Can this be made faster? The UNO project above shows 8 analog outputs linked together with resistors to get the 50,000 cps sine wave. But even 8 * 400 is only 3,200.  How is it possible to get a 50,000 cps sine wave out of even 3,200 square pulses?  (I must admit I didn't finish building this project, bumping into too many questions and inconsistancies along the way.)


(The 8-pin chip shown is an LM386 Low Voltage Audio Power Amplifier, for a strong ouput signal.)

QUESTION 3:
The sketch for the uno prject above did not reveal even one "pinMode()" or "analogWrite()". So I was unable to figure out how the eight output pins were being communicated with by the sketch.  Where can I fnd "lessons" that teach such "advanced" Arduino programming techniques? I was at a total loss, when trying to understand this sketch.

--------------

As I said at the top, after 5 days, I finally came up with the answer to my project needs. I'm designing a brainwave monitor, and needed a sine-wave generator to test the input circuitry.  Thus, I only needed to produce sine waves in the range of 0.5 to 40 cps.

I modified the little sketch at:
https://www.sparkfun.com/tutorials/329
to produce the sketch shown here, which does the job:

Code: [Select]

float in, out;
const int LED = 11;
unsigned long Mils = millis();
byte multiplier = 1;

void setup()
{
pinMode(2, INPUT_PULLUP);
pinMode(3, INPUT_PULLUP);
pinMode(4, INPUT_PULLUP);
pinMode(5, INPUT_PULLUP);
}

void loop()
{
  if (digitalRead(2) == LOW)
    multiplier = 1;
  else if (digitalRead(3) == LOW)
    multiplier = 10;
  else if (digitalRead(4) == LOW)
    multiplier = 20;
  else if (digitalRead(5) == LOW)
    multiplier = 40;
  for (in = 0; in < 6.283; in += (multiplier * 0.006283))
  {
    while ((millis() - Mils) < 1) {};
    Mils += 1;
    out = sin(in) * 127.5 + 127.5; // 127.5
    analogWrite(LED,out);
  }
}


In order to remove the 400 cps square pulses that produce the sine-wave, I used the low-pass filter circuit and calculator shown below, and located at:
http://www.wa4dsy.net/robot/active-filter-calc



I entered 50 in both the resistor-value and cut-off frequency boxes and clicked "COMPUTE". It then showed me I needed .1 and a .05 as the matching capacitor values. This circuit on the Arduino UNO then worked perfectly for my purposes.

I use a 10K pot to control the amplitude of the sine wave. (The end terminals connecting to the Arduino output pin, and to ground. The center tap connected to the input of the curcuit shown above.)

"Multiplier" (in the sketch) is the number of cycles of the sine wave produced per second. You can set these to be whatever frequencies you want the input pins to select, adding more pins (and thus frequencies) if you choose. Then, when running it, moving a grounded jumper cable to any of these Arduino inputs will produce the selected frequency output.


robtillaart

#1
Apr 20, 2015, 09:43 pm Last Edit: Apr 20, 2015, 09:46 pm by robtillaart
you might also use a dedicated chip like - http://datasheets.maximintegrated.com/en/ds/MAX038.pdf

or - https://www.google.nl/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0CCIQFjAA&url=http%3A%2F%2Fwww.analog.com%2Fmedia%2Fen%2Ftechnical-documentation%2Fdata-sheets%2FAD9850.pdf&ei=HFc1VeXzJtfgavKWgMAL&usg=AFQjCNFgI31uPPL_T82FZ4B2fnkuJA4rLg&sig2=Mw4_LSqBkYJjSRHiR8WMzQ&bvm=bv.91071109,d.d2s

Sorry for that URL, google the AD9850

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

CosmickGold

#2
Apr 20, 2015, 10:17 pm Last Edit: Apr 21, 2015, 02:17 am by CosmickGold
Hey thanks Rob!  With your help, I just found your chip on eBat y.com.  It's already in a module and listed as:

"Sine/Square AD9850 DDS Signal Function Generator Module 0-40MHz for Arduino
$6.99

Can't beat that!

PS -   I just ordered two.

MarkT

Q1:

The project at http://www.arduino.cc/en/Tutorial/DueSimpleWaveformGenerator
is just a proof of concept, I think it will go more like 30kHz these days as analogRead()
has been improved for the Due by orders of magnitude since the early days, but don't
use it without fixing the timebase it uses.

If you see delay or delayMicroseconds being used its not going to be a good timebase
as the speed is not defined since the delay is not all the loop time.

If you see micros() or millis() and comparisons beinf used to set the timebase, or
timer-driven interrupt to set the timebase, it will at least run at a well-defined speed.

Jitter is another question.

Q2:  Read up in the datasheet for the ATmega328 if you want to drive Uno timers directly, there are also various libraries such as TimerOne which may be useful directly.

The Uno PWM pins run at either 16,000,000/64/510 = 490.2Hz for timers 1 and 2, or
16,000,000/64/256 = 976.6Hz for timer0.  The factor of 64 is the prescaler value which
can be set to various other powers of two.  If you don't care about PWM you can configure
timers how you like, but timer0 does millis() and delay() too
[ I will NOT respond to personal messages, I WILL delete them, use the forum please ]

Grumpy_Mike

Quote
The sketch for the uno prject above did not reveal even one "pinMode()" or "analogWrite()". So I was unable to figure out how the eight output pins were being communicated with by the sketch.  Where can I fnd "lessons" that teach such "advanced" Arduino programming techniques? I was at a total loss, when trying to understand this sketch.
http://playground.arduino.cc/Learning/PortManipulation

pito

QUESTION 2:
I have only the Arduino UNO board, on which my scope shows the analog output pins as pulsing rectangular waves at 400 pulses a second. Can this be made faster? The UNO project above shows 8 analog outputs linked together with resistors to get the 50,000 cps sine wave. But even 8 * 400 is only 3,200.  How is it possible to get a 50,000 cps sine wave out of even 3,200 square pulses?  (I must admit I didn't finish building this project, bumping into too many questions and inconsistancies along the way.)
You may generate analog signals basically:
1. pwm + low pass filter = that is about 490Hz frequency which is PWMed (the duty cycle of that frequency changes, and filtered out gives you an analog level
2. build in DAC
3. resistors based R/2R or binary R network which is connected to 8 (or more) digital output pins, the value put on the port will create a voltage at the resistor's network output immediately - the same as the built in DAC - that is the answer to your Question2..

CrossRoads

Or use blink without delay on non-PWM pins, using micros() instead of millis().
50,000  Hz = 20uS.
Code: [Select]

previous1Time = micros();
previous2Time = micros();
previous3Time = micros();
while (1){                            // sit in while avoid main() and loop() time overhead. May see some
                                          // jitter from micros() and millis() interrupts
currentTime = micros();
if ((currentTime - previousTime1) >= 20){
previous1Time = currentTime;
PIND = 0b00000100; // write 1 to D2 to toggle the output
}
if ((currentTime - previousTime2) >= 30){
previous1Time = currentTime;
PIND = 0b00001000; // write 1 to D3 to toggle the output
}
if ((currentTime - previousTime2) >= 40){
previous2Time = currentTime;
PIND = 0b00010000; // write 1 to D4 to toggle the output
}

}

That should yield pretty close to 50KHz, 33.3KHz and 25Kz at the same time.
Should be able to get a few of these done in 20uS to have multiple outputs. Try it.
All time elements are unsigned long.

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.

CosmickGold

#7
May 29, 2015, 08:54 pm Last Edit: May 29, 2015, 09:02 pm by CosmickGold
My primary mistake in my original comment at the top, was a failure to understand the output is not Pulse Width Modulation (PWM) at all.

Instead, it uses eight High/Low digital outputs to present each of the eight bits of the output byte. The resistors between these eight outputs control how siginificant the voltage on each bit is. This results in a final output voltage on last resistor that is a true analog-level representation of the byte.

Silly me!  I had no idea what all the resistors were for.  And thanks for the education each of your answers have provided.

michinyon

You can generate digital on-off signals from Arduinos much faster than that.

If you don't already know,   any repetitive waveform,  which isn't sinusoidal to start with,  such as a "square wave",  is going to be resolved by fourier transforms ( and related transforms ) into a bunch of super-imposed sinusoidal waveforms.

Go Up