NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Microcontroller Programming » Output a sine wave with the nerdkits?

August 28, 2010
by lcruz007
lcruz007's Avatar

How can I output a sine wave at a high frequency with an atmega328?

Thanks in advance.

August 29, 2010
by Rick_S
Rick_S's Avatar

If it's a pure sine wave you're looking for, the micro-controller doesn't do that. You can 'fake' a sine wave by using fast PWM and running it through some external filters to smooth it into a sine wave. I haven't done it, but here is a LINK to a resource document at Atmel describing this. I'm not sure exactly how high a frequency you can achieve with this method though.

Other than that, you may need to use external components to create a sine wave from the square wave output by the microcontroller such as was done HERE.

Good luck,

Rick

August 29, 2010
by mongo
mongo's Avatar

A sine wave is a linear function. It can be approximated like audio on a CD but even CD players have active filtering and signal conditioning to clean up the digital signal so it can resemble the analog signal.

the biggest problem with sine wave generation is harmonics. If you get a clean sine wave at one frequency, chances are that it degrades rapidly as the frequency changes. That is because the filtering circuit it more or less tuned to the target frequency and loses effectiveness as change grows.

August 31, 2010
by hapshetsut
hapshetsut's Avatar

You could also purchase a frequency to voltage converter, and using frequency as your output, assuming a linear f/v conversion: v(out) = af; so if f = sin(t), v(out) = asin(t). You could then use a voltage divider to reduce v(out) to sin(f).

The down side is you'd also have to purchase a F/V converter.

If terrific accuracy is not an issue i have a tested design for a slightly non-linear f-v converter which requires only an isolation transformer (available at radio shack), optocoupler or a photo-resistor and cds cell (as far as special components, the rest are capacitors and diodes), if you are interested. However it is not the best option in terms of accuracy.

August 31, 2010
by mrobbins
(NerdKits Staff)

mrobbins's Avatar

Hey lcruz007,

What's the frequency (or frequency range)?

What's the intended purpose of this signal (so we can get an idea of how "clean" a signal you need)?

Mike

August 31, 2010
by lcruz007
lcruz007's Avatar

Hi, Thanks all for your answers :)

Mike, I want to send remote information using FM radio waves. For example, send some characters to an LCD remotely from the computer! I heard that a sine wave is the best signal I can use for radio waves.

Thanks for your support!

September 02, 2010
by hapshetsut
hapshetsut's Avatar

For FM transmission of digital signals you may want to just built an analog transmitter/receiver and pair of sinusoidal oscillators tuned to particular frequencies, and a digitally controlled switch between each oscillator and the transmitter, so that you only transmit one frequency at a time.

Another alternative would be to acquire a voltage controlled oscillator and feed your data from a DAC into the control line, and then the VCO's output into a transmitter.

September 01, 2011
by hariharan
hariharan's Avatar

I created this program for producing 500 hertz, but i don't know whether it is working since i have a problem with my computer. if i am wrong, please correct me. Program:

void pwm_init (){
TCCR0A = (1<<COM0A1)    // non-inverting output 
       | (1<<WGM01)     // fast PWM, top=0xFF 
       | (1<<WGM00);

TCCR0B = (1<<CS00);     // no clock prescaling 
DDRD |= (1<<PD6);       // configure OC0A pin for output
 }
void sine_digi() { 
int time= 1/freq/2;
unint8_t i;
for (i=0;i<256;i++){
OCR0A = i;
}
delay(time);
for (unint8_t o=255;o>0;o--){
OCR0A = o;
}
}
int main(){
pwm_init();
int freq = 500;
while(freq){
sine_digi();
}
return 0;
}

thanks in advance!

September 01, 2011
by bretm
bretm's Avatar

I see what you're getting at---create an upward ramp, wait for a bit, then a downward ramp, wait for a bit, repeat. Not really a sine wave but an approximation, but clearly you know that.

It will hang, though:

uint8_t i;
for (i=0;i<256;i++)

Variable "i" is uint8_t so it can only take on values from 0 to 255, therefore it will always be less than 256 and the for loop will never exit.

You're not waiting again after you get to the bottom, and you can't control the slope of the ramp. This code will generate a very steep slope, so mostly you'll get +5V with 0V spikes every once in a while.

Examine the interrupt routine in the code in this article: http://interface.khm.de/index.php/lab/experiments/arduino-dds-sinewave-generator/. Ignore all the other stuff in the code--just understand how the ISR part of the code works. That gives you a good general technique for generating sine waves at a wide range of frequencies.

September 01, 2011
by hariharan
hariharan's Avatar

I am a thirteen year old, so, a bit hard for me to understand but i get that through a low pass filter, they are getting rid of 32kh samples so the signal could be more accurate, but, i came across this : http://www.youtube.com/watch?v=b-vUg7h0lpE But my concern is that i will have to use a whole register to do this. But, is my program good enough to produce tones on the peizo buzzer? (after i changed the integer types) i am trying to make a synth by doing freq/1, freq/2 and so on up to 10 like on a 4017 counter decoder IC. but, i wanted it to be achieved by the mcu.

September 01, 2011
by hariharan
hariharan's Avatar

My corrected program:

void pwm_init (){
TCCR0A = (1<<COM0A1)    // non-inverting output 
       | (1<<WGM01)     // fast PWM, top=0xFF 
       | (1<<WGM00);

TCCR0B = (1<<CS00);     // no clock prescaling 
DDRD |= (1<<PD6);       // configure OC0A pin for output
 }
void sine_digi() { 
int time= 1/freq/2;
unint16_t i;
for (i=0;i<256;i++){
OCR0A = i;
}
delay(time);
for (unint16_t o=255;o>0;o--){
OCR0A = o;
}
delay(time)
}
int main(){
pwm_init();
int freq = 500;
while(freq){
sine_digi();
}
return 0;
}
September 01, 2011
by hariharan
hariharan's Avatar

and thanks !

September 03, 2011
by hariharan
hariharan's Avatar

i modified my code, i thought creating an interval every step of the OCR0A, so i changed my code.

#define F_CPU 14745600   
#include <avr/io.h> 
#include <inttypes.h> 
#include <avr/interrupt.h>

#include "../libnerdkits/delay.h" 
#include "../libnerdkits/lcd.h"   
#define freq 500
void pwm_init (){ 
TCCR0A = (1<<COM0A1)// non-inverting output     
    | (1<<WGM01)     // fast PWM, top=0xFF   
      | (1<<WGM00); 
  TCCR0B = (1<<CS00);     // no clock prescaling 
 DDRD |= (1<<PD6);       // configure OC0A pin for output
  } 
  void sine_digi() {
  int time= 1/freq/255; 
  int i;
 for (i=0;i<256;i++){ 
 OCR0A = i;
 delay_ms(time);
 }

 for (int o=255;o>0;o--){
 OCR0A = o;
 delay_ms(time);
 }

 }

  int main(){
  pwm_init();
  while (freq) {
  sine_digi();
  delay_ms(1000);
  }
  }

but i got this error: In function 'sine_digi':

    'for' loop initial declaration outside C99 mode

it would be great if u can help me, thanks!

September 03, 2011
by bretm
bretm's Avatar

The definition of the "C" language has changed over the years. C99 refers to the version of C where they decided to allow you to declare the iteration variable inside the "for" statement. By default the avr-gcc compiler doesn't let you do that. You have to say

int o;
for (o=255; o>0; o--)

instead of

for (int o=255; o>0; o--)

But instead of doing either of those I would just re-used the "i" variable that you already declared and used for the previous loop.

int time=1/freq/255;

is also a problem. This will always be zero. You might try 1000000/freq/255 and then use delay_us instead of delay_ms.

And this will produce a triangle wave.

September 04, 2011
by hariharan
hariharan's Avatar

thanks bretm!

September 04, 2011
by hariharan
hariharan's Avatar

but in order to use variable 'i'for both for loops, should i declare it as volatile integer?

September 04, 2011
by bretm
bretm's Avatar

No, you're not using interrupts for anything. You only need volatile for variables that you're sharing between an interrupt and the mainline code, or two different interrupts.

June 29, 2012
by live4the1
live4the1's Avatar

By using this code, I do get a tone but it is very faint. Should it be more audible or will I need to amplify it? What would be the preferred method of amplification?

Post a Reply

Please log in to post a reply.

Did you know that you can build a circuit to convert the "dit" and "dah" of Morse code back into letters automatically? Learn more...