Hi all,
I'm basically working on programming for generating Sinusoidal PWM(SPWM) and simple PWM output using Arduino Uno ATMEGA 328p. To be honest, i'm new in Arduino and have little knowledge in programming. My program is mostly taken from another and not totally done by me from scratch.
My SPWM code is basically based on this link:
http://interface.khm.de/index.php/lab/experiments/arduino-dds-sinewave-generator/
My objective is to produce PWM output like figure below:
For the past few week, i have been working on this and able to produce the required PWM. Figure below shows the generated PWM using Proteus:
My problem is, when running the program after a few minutes, the square waves generated start to shifted from the filtered SPWM. FYI, the square wave is running on 50 Hz freq and the filtered SPWM is producing 100 Hz. Figure below shows the square waves are shifted when running after a few minutes:
Based on my opinion, this problem occur due to timer1 and timer2 are not oscillating in synchronize and delayed with few nano seconds. Below is my code:
/*
* DDS Sine Generator using Arduino Uno ATMEGA328P
*/
#include "avr/pgmspace.h"
// table of 256 sine values / half sine period / stored in flash memory
PROGMEM prog_uchar sine256[] = {
1,3,6,8,11,14,17,20,23,25,28,31,34,37,39,42,45,48,50,53,56,59,61,64,67,69,72,75,77,80,83,85,
88,91,93,96,98,101,103,106,108,111,113,116,118,121,123,125,128,130,132,135,137,139,142,144,
146,148,150,152,154,157,159,161,163,165,167,169,170,172,174,176,178,180,181,183,185,186,188,
190,191,193,194,196,197,199,200,201,203,204,205,207,208,209,210,211,212,214,215,216,217,217,
218,219,220,221,222,222,223,224,224,225,226,226,227,227,228,228,228,229,229,229,229,230,230,
230,230,230,230,230,230,230,230,230,229,229,229,229,228,228,228,227,227,226,226,225,224,224,
223,222,222,221,220,219,218,217,217,216,215,214,212,211,210,209,208,207,205,204,203,201,200,
199,197,196,194,193,191,190,188,186,185,183,181,180,178,176,174,172,170,169,167,165,163,161,
159,157,154,152,150,148,146,144,142,139,137,135,132,130,128,125,123,121,118,116,113,111,108,
106,103,101,98,96,93,91,88,85,83,80,77,75,72,69,67,64,61,59,56,53,50,48,45,42,39,37,34,31,28,
25,23,20,17,14,11,8,6,3,
};
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
double dfreq;
// const double refclk=320000; // =16MHz / 50Hz
const double refclk=312500; // measured
// variables used inside interrupt service declared as voilatile
volatile byte icnt; // var inside interrupt
volatile byte icnt1; // var inside interrupt
volatile byte c4ms; // counter increment
volatile unsigned long phaccu; // phase accumulator
volatile unsigned long tword_m; // dds tuning word m
boolean toggle1 = 0;
void setup()
{
pinMode(9, OUTPUT); // sets the digital pin as output
pinMode(10, OUTPUT); // sets the digital pin as output
pinMode(11, OUTPUT); // pin11= PWM output / frequency output
Setup_timer1();
cli(); //stop interrupts
//set timer1 interrupt at 100Hz
TCCR1A = 0; // set entire TCCR1A register to 0
TCCR1B = 0; // same for TCCR1B
TCNT1 = 0; //initialize counter value to 0
// set compare match register for 100hz increments
OCR1A = 155.25; // = (16*10^6) / (100*1024) - 1 (must be <65536)
// turn on CTC mode
TCCR1B |= (1 << WGM12);
// Set CS12 and CS10 bits for 1024 prescaler
TCCR1B |= (1 << CS12) | (1 << CS10);
// enable timer compare interrupt
TIMSK1 |= (1 << OCIE1A);
sei();//allow interrupts
Setup_timer2();
// disable interrupts to avoid timing distortion
cbi (TIMSK0,TOIE0); // disable Timer0 !!! delay() is now not available
sbi (TIMSK2,TOIE2); // enable Timer2 Interrupt
dfreq=1000.0; // initial output frequency = 1000.o Hz
tword_m=pow(2,32)*dfreq/refclk; // calulate DDS new tuning word
}
void loop()
{
while(1) {
if (c4ms > 256) { // timer / wait fou a full second
c4ms=0;
cbi (TIMSK2,TOIE2); // disable Timer2 Interrupt
tword_m=pow(2,32)*dfreq/refclk; // calulate DDS new tuning word
sbi (TIMSK2,TOIE2); // enable Timer2 Interrupt
}
}
}
//******************************************************************
// timer1 setup
void Setup_timer1(){
}
// timer2 setup
// set prscaler to 1, PWM mode to phase correct PWM, 16000000/510 = 31372.55 Hz clock
void Setup_timer2() {
// Timer2 Clock Prescaler to : 1
sbi (TCCR2B, CS20);
cbi (TCCR2B, CS21);
cbi (TCCR2B, CS22);
// Timer2 PWM Mode set to Phase Correct PWM
cbi (TCCR2A, COM2A0); // clear Compare Match
sbi (TCCR2A, COM2A1);
sbi (TCCR2A, WGM20); // Mode 1 / Phase Correct PWM
cbi (TCCR2A, WGM21);
cbi (TCCR2B, WGM22);
}
//******************************************************************
// Timer1 Interrupt Service at 100 Hz
//generates pulse wave of frequency 100Hz/2 = 50Hz (takes two cycles for full wave- toggle high then toggle low)
ISR(TIMER1_COMPA_vect){ //timer1 interrupt 100Hz toggles pin 9,10
if (toggle1){
digitalWrite(9,HIGH);
digitalWrite(10,LOW);
toggle1=0;
}
else{
digitalWrite(9,LOW);
digitalWrite(10,HIGH);
toggle1= 1;
}
}
// Timer2 Interrupt Service at 320 KHz = 3.125uSec
// this is the timebase REFCLOCK for the DDS generator
// FOUT = (M (REFCLK)) / (2 exp 32)
ISR(TIMER2_OVF_vect) {
phaccu=phaccu+tword_m; // soft DDS, phase accu with 32 bits
icnt=phaccu >> 24; // use upper 8 bits for phase accu as frequency information
// read value fron ROM sine table and send to PWM DAC
OCR2A=pgm_read_byte_near(sine256 + icnt);
if(icnt1++ == 1) { // increment variable c4ms
c4ms++;
icnt1=0;
}
}
I'm hoping that someone could help me to solve this problem or at least give me some idea on how to solve this. TQ ;D