Function generator with Arduino

Hey guys, I’m new here so sorry if my question is silly.

I’m trying to create a simple function generator with an Arduino Uno.

I’ve trying to play with two codes:


void setup()

{

pinMode(8, OUTPUT);

}

void loop()

{

// A total delay of 4 ms = 1/0.004 = 250 Hz…

digitalWrite(8, HIGH);

delayMicroseconds(2000);

digitalWrite(8, LOW);

delayMicroseconds(2000);

}


It’s a simple code, so I could understand how it works. I tried to create an RC filter in order to obtain a pure wave (instead of square wave).

I got a triangular wave and couldn’t get frequency values greater than 500Hz (delay~1000ms)

This is the second code:


unsigned long t0;

void setup() {

pinMode(9, OUTPUT);

t0 = millis();

TCCR1B = 0x01;

}

void loop() {

analogWrite(9, (int) (255.0 * 0.5 *(1.0 + sin( (float) ((millis()-t0) % 1000) * 2.0 * 3.14 * 5.0 / 1000))));

}


In this case I could create the sin wave but I can’t either change it or measure it. I used the same RC filter.

My main objective with that is to get a sin wave which I can choose between 20KHz and 50KHz. I’m using ISIS Proteus as well, what allow me to create the filters and analyze the frequency.

Does anyone have some knowledge to help me with that?

Thanks.

I would guess that your 1’st problem lies with the digital pins being current limited. What did you have for an RC filter ? Can you buffer the outputs w/an op-amp and use and active RC ?

I’m more than a little surprised that your second try did anything near correct. You’re writing to the PWM timer as quick as the loop runs and trying to reset it, before it’s even finished a cycle. The pin is still outputting a digital signal and still subject to the same current limitations. Moreover IIRC the normal arduino analogWrite() function sets the PWM frequency to something under 10 kHz and then varies the duty cycle to get the “analog” output. I do believe you can get much higher PWM freqs but you’ll have to set the timer controls “manually”. See the Atmega 328 PDF. Or look at this thread;

https://forum.sparkfun.com/viewtopic.php?f=32&t=38199

felipearcaro:
Hey guys, I’m new here so sorry if my question is silly.

I’m trying to create a simple function generator with an Arduino Uno.

I’ve trying to play with two codes:


void setup()

{

pinMode(8, OUTPUT);

}

void loop()

{

// A total delay of 4 ms = 1/0.004 = 250 Hz…

digitalWrite(8, HIGH);

delayMicroseconds(2000);

digitalWrite(8, LOW);

delayMicroseconds(2000);

}


It’s a simple code, so I could understand how it works. I tried to create an RC filter in order to obtain a pure wave (instead of square wave).

I got a triangular wave and couldn’t get frequency values greater than 500Hz (delay~1000ms)

It is important to know what resistor and capacitor values you used. These determine the frequency border where the amplitude of higher frequencies start to get attenuated (reduced, I am assuming you talk about a low-pass filter). As you might know, a square wave is composed of a sine wave of the base frequency, with an essentially infinite sequence of higher (odd numbered) harmonics. A triangle wave is similar, but the higher odd harmonics are increasingly weaker and are alternately inverted (180 degree out of phase). So this looks normal for a square wave going through a RC lowpass filter.

However, these DigitalWrite commands have some execution time, and they are not always of the same duration. I used your code to generate square-waves on my Arduino Uno and looked at it with my analog oscilloscope. (No RC filter though, just the square wave) Your 2000 microsecond delays do result in about 240 Hz on my (uncalibrated) oscilloscope. The frequency counter mode of my multimeter reports 248 Hz. But with much shorter delay times the frequency seems to divert from desired. When the delays were set to 25 microseconds (20 kHz) I got about 17 kHz. Even with 2 microseconds I got a square wave, but not a sharp one, and far from the desired frequency. Can’t remember exactly, but I think 80 kHz, instead of 250kHz. So, do not rely on this method if you want reliable frequencies. Instead, direct control of the internal timer/pwm modes would get you better results.

This is the second code:


unsigned long t0;

void setup() {

pinMode(9, OUTPUT);

t0 = millis();

TCCR1B = 0x01;

}

void loop() {

analogWrite(9, (int) (255.0 * 0.5 *(1.0 + sin( (float) ((millis()-t0) % 1000) * 2.0 * 3.14 * 5.0 / 1000))));

}


In this case I could create the sin wave but I can’t either change it or measure it. I used the same RC filter.

My main objective with that is to get a sin wave which I can choose between 20KHz and 50KHz. I’m using ISIS Proteus as well, what allow me to create the filters and analyze the frequency.

Does anyone have some knowledge to help me with that?

Thanks.

I tried this also and could get a signal that looked like a sine wave, but actually looked like 2 on top of each other on my oscilloscope screen (AC-coupling). Your mathematical levelshifting and turning the result into an int isn’t working right. It still generates values higher than 255, which overflow in the AnalogWrite funtion (or PWM timer) to just above 0. Make sure you test which numbers it generates by sending it to the serial monitor. Anyway, the sine was so slow that I could not get a steady image. So I do not have a frequency measurement.

On that note however, the use of floating point operations, and trigonometry functions like sines and cosines is notoriously sloooooooooww. Calculating them for audible frequencies is not the appropriate way. It would be better to use lookup-tables to take the sine value of a certain phase angle. Even with those methods generating frequencies in the 10-100 KHz range is unlikely. You really need to resort to quick compact machine code for that. No go with Arduino functions.

Mee_n_Mac, I had seen this topic before and I’ve talked to the guy who was working on that code. He needed square waves and that is all he got. The low-pass RC filter I’m using is a simple one, with a resistor (1K Ohm) and a capacitor (1uF) in series. Since I’m using Proteus to simulate the results, I can change them easily. How can I change the timers manually? I’ve been reading about timers and PWM but I got a little confused.

I feel like I have almost all the knowledge I need to build this, because it looks pretty simple what I want, but at the same time I have no idea how to put everything together.

Valen, I was expecting the first code not to work for what I need. The second code I got from a topic in other forum, because I had to start from somewhere. I started playing with Arduino one week ago, so I get a little bit lost when you write about my code. What do you mean by compact machine code?

Also, I’ve read that for my purpose, it would be easier to create a square wave with tone() and use my low-pass RC filter to get a sin wave. Is it possible for higher frequencies such as 50KHz?

Thanks for replying me, I really appreciate that.

Felipe

Just a heads up, I’ve tried to use a really simple code with tone() function and I got really good results.

#define Q  5000
#define F1 20000


void setup() {     
pinMode(8, OUTPUT);   
pinMode(9, OUTPUT);       
digitalWrite(9,LOW);

}

// the loop routine runs over and over again forever:
void loop() {
  //tone(pin, note, duration)
    tone(8,F1,Q); 
    delay(1+Q); //delay duration should always be 1 ms more than the note in order to separate them.

    
    

}

After running it, I used this website to calculate the values of my low-pass filter: http://sim.okawa-denshi.jp/en/CRlowkeisan.htm.

With that, I designed the system on Proteus and got this:

http://oi61.tinypic.com/2pow3l1.jpg

http://i59.tinypic.com/2j2wbqo.jpg

I couldn’t post the image here because it wasn’t showing the full image. In this first oscilloscope configuration I could see the wave all the time while in the second it was one second one and about 3 seconds off, but I think this is just some Proteus configuration problem. The result it was exactly what I wanted.

Since my main objective is to create these waves to be read by a receptor, is it enough?

As you’ve discovered your 1k/1uF filter was waaaay too low in frequency. It filtered out anything over 159 Hz, reducing by a factor of 10 for each decade above 159 Hz. So 1590 Hz is down to 0.1x of it’s initial amplitude, which was already zero given a 50 kHz fundamental. You want a low pass filter (LPF) that does not attenuate the 50 kHz fundamental but then reduces all the harmonics of the square wave, which as has been said, are odd (150 kHz, 250 kHz, etc, etc).

With a simple RC LPF the frequency at the corner freq (1/2piRC) is reduced to 0.707x of it’s amplitude, that being 0.64x of the square wave amplitude. Pushing the corner of the LPF a little higher will increase your sinewave amplitude but allow slightly more harmonics to creep in and distort it.

So it all depends on how much harmonic distortion you can tolerate in your sine-from-a-square wave. Of course using an op-amp and then implementing a “2 pole” LPF allows both more fundamental and reduced harmonic content. What did you end up with … 160k and 47 pF ? That’s an RC constant of 7.52 us or a LPF corner frequency of 54.2 kHz, which seems OK to me.

felipearcaro:
Valen, I was expecting the first code not to work for what I need. The second code I got from a topic in other forum, because I had to start from somewhere. I started playing with Arduino one week ago, so I get a little bit lost when you write about my code. What do you mean by compact machine code?

I meant assembly language, the instructions that the Atmega chip executes itself, instead of higher level programming functions like Arduino. That is the best way to make fast executing code. But it’s not for the faint at heart. And not really appropriate for your level of understanding at the moment. Forget what I said, just know that the simplicity of Arduino comes with penalties in executions speed.

[Tone()

It does seem that the Tone library can generate square waves in to the multiple 10K Hz ranges. As it does make use to the hardware timers that can theoretically count in the MHz range. But looking at the [code it still looks like the pin toggling is done in software instead of a hardware output. Also, it seems to be intended for audible frequencies. So there will be a limit to it’s performance. I have never used it myself.

p.s. What is a “receptor”?](http://rogue-code.googlecode.com/files/Arduino-Library-Tone.zip)](Google Code Archive - Long-term storage for Google Code Project Hosting.)

I bought this board http://www.amazon.com/AD9850-Signal-Gen … B00AUE633Y

It will be shipped in 3 days, that should do the job.

I’ll post here the results I can get with that board.

Thanks guys.

20 Mhz bandwidth is a bit overpowered for your application, but it should produce a clean sinewave. And you can’t beat the cheapness. Seems a good idea.

Depending on the OP’s usage, it may be OK. The DAC output has a 120 kohm (typical) output impedance so it may need some buffer circuit. He hasn’t said what voltage/current/power level is needed.

A day late … ???

https://www.sparkfun.com/products/11420

felipearcaro:
I bought this board http://www.amazon.com/AD9850-Signal-Gen … B00AUE633Y

It will be shipped in 3 days, that should do the job.

I’ll post here the results I can get with that board.

Thanks guys.

I got a handful of those boards off ebay, ~$10 each in the end.

They do a good job, good enough for me anyways. When you get up into the higher freq’s, say above ~10Mhz or so, there’s a very small bit of crossover distortion barely discernible on a 100Mhz 'scope, that is if it’s exactly the same thing I’ve got. I don’t worry about it.

Also, you can’t drive anything substantial with the board. ~.6v pk-pk output. Have to use an output driver / opamp of some sort to get anything useful.

http://www.eevblog.com/forum/beginners/ … ow-freq’s/

skimask, the board is perfect for what I wanted, I got a high frequency output and around 1V. I used an op amp to amplify the voltage and another one as a buffer to increase the current.

I’m using this code to get the sine wave:

/*

*/

#define W_CLK 8 // Pin 8 - connect to AD9850 module word load clock pin (CLK)

#define FQ_UD 9 // Pin 9 - connect to freq update pin (FQ)

#define DATA 10 // Pin 10 - connect to serial data load pin (DATA)

#define RESET 11 // Pin 11 - connect to reset pin (RST).

#define pulseHigh(pin) {digitalWrite(pin, HIGH); digitalWrite(pin, LOW); }

// transfers a byte, a bit at a time, LSB first to the 9850 via serial DATA line

void tfr_byte(byte data)

{

for (int i=0; i<8; i++, data>>=1) {

digitalWrite(DATA, data & 0x01);

pulseHigh(W_CLK); //after each bit sent, CLK is pulsed high

}

}

// frequency calc from datasheet page 8 = * /2^32

void sendFrequency(double frequency) {

int32_t freq = frequency * 4294967295/125000000; // note 125 MHz clock on 9850

for (int b=0; b<4; b++, freq>>=8) {

tfr_byte(freq & 0xFF);

}

tfr_byte(0x000); // Final control byte, all 0 for 9850 chip

pulseHigh(FQ_UD); // Done! Should see output

}

void setup() {

// configure arduino data pins for output

pinMode(FQ_UD, OUTPUT);

pinMode(W_CLK, OUTPUT);

pinMode(DATA, OUTPUT);

pinMode(RESET, OUTPUT);

pulseHigh(RESET);

pulseHigh(W_CLK);

pulseHigh(FQ_UD); // this pulse enables serial mode - Datasheet page 12 figure 10

}

void loop() {

sendFrequency(50e3); // freq

while(1);

}

It provides exactly what I need, with some offset, which could be fixed with a capacitor.

Is there a simple way that allows me to sweep this frequency, determining my higher cut-off frequency, lower cut-off frequency and time (delay)?

Thanks