Can arduino uno generate sine wave?

dlloyd:
In the video, you're updating the pwm about once per second. This should at minimum 2.5x faster than the pwm frequency, which is about 500Hz. Therefore you should do an analogWrite() at least 1250 times per second. So the lowest sine wave frequency you could generate would be about 1250/37 Hz.

Your code shows delayMicroseconds(1) which is much faster. What sine wave frequency are you trying to get?

50HZ..

Then you'll need to write all the data in the array 50 times per second.

Does there are other arduino board can output a pure sine wave?
May be I will buy another arduino board, but not arduino uno again.

Also, How to increase the frequency of PWM.
It is limited to 490Hz in Pin11.

int PWMpin = 11;
int sineA[] =
{ 128 , 139 , 150 , 160 , 171 , 181 , 191 , 201 , 209 , 218 , 225 ,
232 , 238 , 243 , 247 , 251 , 253 , 255 , 255 , 255 , 253 , 251 ,
247 , 243 , 238 , 232 , 225 , 218 , 209 , 201 , 191 , 181 , 171 ,
160 , 150 , 139 , 128 , 116 , 105 , 95 , 84 , 74 , 64 , 54 ,
46 , 37 , 30 , 23 , 17 , 12 , 8 , 4 , 2 , 0 , 0 ,
0 , 2 , 4 , 8 , 12 , 17 , 23 , 30 , 37 , 46 , 54 ,
64 , 74 , 84 , 95 , 105 , 116 , 127 };
void setup()
{
pinMode(PWMpin, OUTPUT);
}
void loop()
{
int i;
for (i=0; i<74;i++)
{
analogWrite(PWMpin, sineA*);*
delayMicroseconds(270);
}
}
It is the last code of me program.
How I can change the frequency of PWM?

leung199767:
Does there are other arduino board can output a pure sine wave?
May be I will buy another arduino board, but not arduino uno again.

You'd need to find a board that has an onboard digital-to-analog converter. I don't think arduino's have an onboard digital-to-analog converter. But maybe there's a add-on module (aka arduino 'shield') that has a d-to-a.

Otherwise, just need to use the PWM encoded sinewave (with external low pass filter) method; or the other method....which involves writing sine-wave amplitude encoded code-words to an external digital-to-analog (eg. resistor ladder) converter, which would require some external low pass filtering as well.

Note that the 'sine-wave' in a wave-table (ie. a table that contains instantaneous amplitudes of the sine-wave at various equally-spaced time intervals) is not an ideal sinewave. This sine-wave needs to encoded with a positive DC-level offset, since the arduino UNO doesn't deal with negative voltages. So basically the encoded signal must be a DC-shifted sinewave.

The Arduino Due and Zero have a built in D/A converter, these are 3V3 boards. But the problem is the same as you are failing to grasp here. You will not get a full 3V sin wave and it will not go below zero volts.

All these things have been explained to you several times but you are simply not engaging with the answers.

Please read this:-
How to use this forum it will tell you what to do if you get an answer you don't understand. Clearly you have understood little of what has been told you so far. You have even ignored the link which is the full solution to your problem, which is http://interface.khm.de/index.php/lab/interfaces-advanced/arduino-dds-sinewave-generator/

leung199767:
Does there are other arduino board can output a pure sine wave?
May be I will buy another arduino board, but not arduino uno again.

Teensy boards have a 12 Bit Analog Output, you can used the Arduino IDE with them. Really nice boards.

https://www.pjrc.com/teensy/teensy31.html

Grumpy_Mike:
You will not get a full 3V sin wave and it will not go below zero volts.

That's a really good point GM. A dc blocker/filter combo and an external amplifier would be needed.

Thanks for mentioning those two arduino boards that have A/D converters. I think the OP has some good info for his project from all these info.

leung199767:
50HZ..

If you're ever interested to generate PWM encoded "DC-offsetted sinewave" using interrupts and wave-table, then you could tinker with this following code, which generates a PWM signal having a time-varying duty cycle. The mathematical time-averaged PWM signal will be proportional to the encoded DC-offsetted sinewave's instantaneous amplitude.

This code produces a PWM signal having a duty cycle dependent on instantaneous amplitudes of a sinewave. For this example, one full cycle of the 'pwm-encoded' sinewave is 25.5 seconds....a frequency of 0.039 Hz, which is really quite a low frequency. If you want much higher frequency (like 50 Hz), then you'll need to use a smaller value for the frequency divider (prescaler), instead of divide-by-1024.

Once you've achieved higher frequency signals, you would then have to put the PWM signal through an external RC low-pass filter, followed by a buffer, and then through a DC blocker (eg, capacitor). This basically 'demodulates' the PWM signal in order to yield (produce) the sinewave.

Anyway, without using external filtering for the moment, you can take a multimeter and measure the voltage at digital pin 3 (when the code is running). You'll be able to see the voltage at pin 3 change with time. It'll take around 25.5 seconds to go through a cycle. It's basically the time-changing instantaneous amplitude of the DC-offsetted sinewave, even though the multimeter is actually measuring a PWM signal. RMS multimeters basically does some 'time averaging' of whatever signal it is measuring. The multimeter can at least show us something interesting to see when the PWM duty doesn't change too quickly, such as in this example.

Code for UNO :

// PIN 13 will have a 2.5 Hz square wave on it.
// PIN 3 will have a PWM signal on it, with a duty cycle that keeps changing in time. The mathematical 'time-average' of the PWM signal's amplitude will be proportional to the instantaneous amplitude of a DC-offsetted sinewave.

// NOTE that the frequency in this example is very low. The interrupt frequency is only 10 Hz, which means an interrupt every 0.1 second. If we have 256 values for our DC-offsetted sinewave (from the wave-table), then each 'amplitude' voltage will be generated with 1 second gaps, which means it would take a long time (such as 25.5 seconds) for a full cycle of the amplitude values.
// 

boolean toggle1 = 0;

int pwmPin_timer1 = 3;

volatile int indexer = 0;


unsigned char sinewave[] =                // Preset 256 values of a binary conversions of a sine wave having a POSITIVE DC OFFSET. It represents sinewave with a positive DC offet. This is done because the arduino doesn't handle NEGATIVE voltages.
{
0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x02,0x02,0x03,0x04,0x05,0x06,0x06,0x07,0x09,
0x0a,0x0b,0x0c,0x0e,0x0f,0x11,0x12,0x14,0x16,0x17,0x19,0x1b,0x1d,0x1f,0x21,0x23,
0x25,0x28,0x2a,0x2c,0x2f,0x31,0x34,0x36,0x39,0x3c,0x3e,0x41,0x44,0x46,0x49,0x4c,
0x4f,0x52,0x55,0x58,0x5b,0x5e,0x61,0x64,0x67,0x6a,0x6d,0x70,0x73,0x77,0x7a,0x7d,
0x80,0x83,0x86,0x89,0x8d,0x90,0x93,0x96,0x99,0x9c,0x9f,0xa2,0xa5,0xa8,0xab,0xae,
0xb1,0xb4,0xb7,0xba,0xbc,0xbf,0xc2,0xc4,0xc7,0xca,0xcc,0xcf,0xd1,0xd4,0xd6,0xd8,
0xdb,0xdd,0xdf,0xe1,0xe3,0xe5,0xe7,0xe9,0xea,0xec,0xee,0xef,0xf1,0xf2,0xf4,0xf5,
0xf6,0xf7,0xf9,0xfa,0xfa,0xfb,0xfc,0xfd,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfd,0xfc,0xfb,0xfa,0xfa,0xf9,0xf7,
0xf6,0xf5,0xf4,0xf2,0xf1,0xef,0xee,0xec,0xea,0xe9,0xe7,0xe5,0xe3,0xe1,0xdf,0xdd,
0xdb,0xd8,0xd6,0xd4,0xd1,0xcf,0xcc,0xca,0xc7,0xc4,0xc2,0xbf,0xbc,0xba,0xb7,0xb4,
0xb1,0xae,0xab,0xa8,0xa5,0xa2,0x9f,0x9c,0x99,0x96,0x93,0x90,0x8d,0x89,0x86,0x83,
0x80,0x7d,0x7a,0x77,0x73,0x70,0x6d,0x6a,0x67,0x64,0x61,0x5e,0x5b,0x58,0x55,0x52,
0x4f,0x4c,0x49,0x46,0x44,0x41,0x3e,0x3c,0x39,0x36,0x34,0x31,0x2f,0x2c,0x2a,0x28,
0x25,0x23,0x21,0x1f,0x1d,0x1b,0x19,0x17,0x16,0x14,0x12,0x11,0x0f,0x0e,0x0c,0x0b,
0x0a,0x09,0x07,0x06,0x06,0x05,0x04,0x03,0x02,0x02,0x01,0x01,0x01,0x00,0x00,0x00
};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
void setup(){
  Serial.begin(9600);
  pinMode(pwmPin_timer1, OUTPUT); //configured a valid pin for PWM output

cli();//stop interrupts
  

//NOTE: registers TCCR1A, TCCR1B, TCNT1, OCR1A etc. are PREDEFINED within a header file. They are registers related the setup of the arduino timers.
  TCCR1A = 0;// initialise to zero.
  TCCR1B = 0;// same for TCCR1B
  TCNT1  = 0;//initialise counter value to 0
  
  OCR1A = 1563;   // timer compare value;   = [(16*10^6) / (10*1024)] - 1 (must be <65536) = MAXCOUNT = [(raw timer clock frequency) / (desired_interrupt_freq * prescale_divisor)] - 1, which comes from formula: prescaled_clockperiod = 1/prescaled_clockfreq; desired_interrupt_period = 1/10 = n.prescaled_clockperiod; maxcount = N = OCR0A = n-1; n is new divisor; prescaled_clockperiod = 1/(16MHz/prescale_divisor); a prescale_divisor of 1024 is set by CS10, CS11, CS12 of TCCR1B register.
  TCCR1A |= 0; 
    
  // set up timer with prescaler = 1 and turn on CTC mode; CS10 CS11 and CS12 are bit0, bit1, and bit2 of the TCC1B register, respectively. Example prescaler options: Making CS11=1 and CS10=1 yields divide by 64. Making CS12=1 and CS11=1 yields divide by 1024. Refer to timer1 prescale table in a user manual for other combinations.
  //TCCR1B |= (1 << WGM12)|(1 << CS11)|(1 << CS10);     //use this for divide by 64 (ie. 'prescaler 64')
  TCCR1B |= (1 << WGM12)|(1 << CS12)|(1 << CS10);     //use this for divide by 1024
  //TCCR1B |= (1 << WGM12)|(1 << CS11);     //use this for divide by 8
  //TCCR1B |= (1 << WGM12)|(1 << CS10);     //use this for divide by 1  


  // turn on CTC mode
  //TCCR1B |= (1 << WGM12); //WGM12 is bit3 of the TCCR1B register (4th bit from the right). This turns on CTC mode (timer mode 4)

  //Timer1 has 2 separate control registers. Each one contains bits for setting up features associated with timer1. Some bits, like the set of Waveform Generation WG bits are scattered so that some of the bits are in one register, while the other bits are in the second register.
  
  // enable timer compare interrupt
  TIMSK1 |= (1 << OCIE1A);

  sei();//allow interrupts

}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
void loop()
{
//put things here if needed
}


ISR(TIMER1_COMPA_vect){//timer1 interrupt with frequency of 10Hz will toggle pin 13 (LED)
  //this service routine generates pulse wave of frequency 10Hz/2 = 2.5Hz (takes two cycles for full wave- toggle high then toggle low) at digital pin 13
  //analogWrite(pwmPin_timer1,128);  //setPwmDuty(pwmPin_timer1, dutycycle)
  
  //also generates PWM encoded DC-offsetted sinewave at digital pin 3
  //write some code here .....

// pin 3, sinewave (plus positive DC offset) instantaneous amplitude encoded as PWM signals. The mathematical time-average of the constantly changing PWM signal will be the instantaneous amplitude of the encoded sine-wave. Therefore, it will be necessary to low-pass filter the PWM signal in order to 'observe' the encoded sine-wave.
  analogWrite(pwmPin_timer1, sinewave[indexer]);
  indexer++;
  if (indexer == 256) {
  indexer = 0;
  }

// pin 13, square-wave signal;  note that the frequency of the squarewave will be half of the interrupt frequency, due to the toggling. So if the interrupt frequency is 10 Hz, then the square wave's frequency will be 2.5 Hertz.
  if (toggle1){
    digitalWrite(13,HIGH);
    toggle1 = 0;
  }
  else{
    digitalWrite(13,LOW);
    toggle1 = 1;
  }
  
}

Well of course we can !
We can use two approaches.....1) Generating sine wave by PWM 2) Sine wave output from a DAC

Here is a simple code for Sine and Cosine wave output from an Arduino by PWM (with scope for other improvements)....

#define sin_out_put_pin 5
#define cos_out_put_pin 6

void setup()
{
  // Serial.begin(9600);
}

const float rad_per_deg = 0.01745329251;      // value of a radian per degree
float theta = 0;
int pulse_width_sin = 0;
int pulse_width_cos = 0;
int sign = 1;                           // to control the increments or decrements of angle parameter

void loop()
{
  analogWrite( sin_out_put_pin , pulse_width_sin );    // PWM output at the given pins
  analogWrite( cos_out_put_pin , pulse_width_cos );
  
  if (theta == 3.14159265359) sign = -1;   // keep increasing the value of theta till pi and the decrease till zero
  else if (theta == 0) sign = 1;
  
  theta = theta + (rad_per_deg * sign);
  
  pulse_width_sin = 255 * sin(theta);
  pulse_width_cos = 255 * cos(theta);

  // Serial.print(pulse_width_sin);
  // Serial.print(',');
  // Serial.print(pulse_width_cos);

  pulse_width_sin = abs(pulse_width_sin);
  pulse_width_cos = abs(pulse_width_cos);

  // Serial.print(',');
  // Serial.print(pulse_width_sin);
  // Serial.print(',');
  // Serial.println(pulse_width_cos);
  
  delay(10);  // control the frequency here
}

Yes of course it can ! A simple way of doing it by generating sine modulated PWM. The PWM can be then "Integrated" using an R-C circuit to get smoother sine wave.

Here is the basic code (with scope for some improvements)...

#define sin_out_put_pin 5
#define cos_out_put_pin 6

void setup()
{
  // Serial.begin(9600);
}

const float rad_per_deg = 0.01745329251;
float theta = 0;
int pulse_width_sin = 0;
int pulse_width_cos = 0;
int sign = 1;

void loop()
{
  analogWrite( sin_out_put_pin , pulse_width_sin );    // write modulated PWM value at the pins
  analogWrite( cos_out_put_pin , pulse_width_cos );
  
  if (theta == 3.14159265359) sign = -1;  // increase theta from zero to pi and then decrease to zero
  else if (theta == 0) sign = 1;
  
  theta = theta + (rad_per_deg * sign);     // keep incrementing or decrementing theta
  
  pulse_width_sin = 255 * sin(theta);        // max duty cycle (ie: 255) modulated in terms of sin
  pulse_width_cos = 255 * cos(theta);       // max duty cycle (ie: 255) modulated in terms of cos

//  Serial.print(pulse_width_sin);
//  Serial.print(',');
//  Serial.print(pulse_width_cos);

  pulse_width_sin = abs(pulse_width_sin);   // always +ve as analogWrite takes +ve value for duty cycle
  pulse_width_cos = abs(pulse_width_cos);

//  Serial.print(',');
//  Serial.print(pulse_width_sin);
//  Serial.print(',');
//  Serial.println(pulse_width_cos);
  
  delay(10);     // control the frequency here
}

2 posts were split to a new topic: Arduino based Oscilliscope