Sie sind auf Seite 1von 8

#include "avr/pgmspace.

h"
#include "avr/io.h"
// Look Up table of a single sine period divied up into 256 values. Refer to PWM
to sine.xls on how the values was calculated
PROGMEM prog_uchar sine256[] = {
127,130,133,136,139,143,146,149,152,155,158,161,164,167,170,173,176,178,181,18
4,187,190,192,195,198,200,203,205,208,210,212,215,217,219,221,223,225,227,229,23
1,233,234,236,238,239,240,
242,243,244,245,247,248,249,249,250,251,252,252,253,253,253,254,254,254,254,25
4,254,254,253,253,253,252,252,251,250,249,249,248,247,245,244,243,242,240,239,23
8,236,234,233,231,229,227,225,223,
221,219,217,215,212,210,208,205,203,200,198,195,192,190,187,184,181,178,176,17
3,170,167,164,161,158,155,152,149,146,143,139,136,133,130,127,124,121,118,115,11
1,108,105,102,99,96,93,90,87,84,81,78,
76,73,70,67,64,62,59,56,54,51,49,46,44,42,39,37,35,33,31,29,27,25,23,21,20,18,
16,15,14,12,11,10,9,7,6,5,5,4,3,2,2,1,1,1,0,0,0,0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9,
10,11,12,14,15,16,18,20,21,23,25,27,29,31,
33,35,37,39,42,44,46,49,51,54,56,59,62,64,67,70,73,76,78,81,84,87,90,93,96,99,
102,105,108,111,115,118,121,124};
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
int PWM_OUT_1 =11; // PWM output on pin 11
int PWM_OUT_2 =10; // PWM output on pin 10
int PWM_OUT_3 =12; // PWM output on pin 9
int LED_PIN =13; // LED status on pin 13
int TEST_PIN =7; // Scope trigger on pin 7
int POTEN_IN =A0; // Potentiometer on pin 0
int OFFSET_1 =85; // Offset for second-phase
int OFFSET_2 =170; // Offset for third-phase
double dfreq;
const double refclk = 31376.6; // measured
const uint64_t twoTo32 = pow(2, 32); // compute value at startup and use as cons
tant
// variables used inside interrupt service declared as voilatile
volatile uint8_t icnt; // var inside interrupt
volatile uint8_t icnt1; // var inside interrupt
volatile uint8_t c4ms; // counter incremented every 4ms
volatile uint32_t phase_accum; // pahse accumulator
volatile uint32_t tword_m; // dds tuning word m
//******************************************************************
void setup()
{
pinMode(LED_PIN, OUTPUT); // sets the digital pin as output
Serial.begin(115200); // connect to the serial port
Serial.println("DDS Test");
pinMode(TEST_PIN, OUTPUT); // sets the digital pin as output
pinMode(PWM_OUT_1, OUTPUT); // PWM output / frequency output
pinMode(PWM_OUT_2, OUTPUT); // PWM output / frequency output
pinMode(PWM_OUT_3, OUTPUT); // PWM output / frequency output
// Setup the timers
setup_timer1();
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.0 Hz

tword_m = twoTo32 * dfreq / refclk; // calulate DDS new tuning word


}
//******************************************************************
void loop()
{
if (c4ms > 250) // timer / wait for a full second
{
c4ms = 0;
dfreq = analogRead(POTEN_IN); // read Poti on analog pin 0 to adjust output freq
uency from 0..1023 Hz
cbi (TIMSK2, TOIE2); // disble Timer2 Interrupt
tword_m = twoTo32 * dfreq / refclk; // calulate DDS new tuning word
sbi (TIMSK2, TOIE2); // enable Timer2 Interrupt
Serial.print(dfreq);
Serial.print(" ");
Serial.println(tword_m);
}
}
//******************************************************************
// timer1 setup
// set prscaler to 1, PWM mode to phase correct PWM, 16000000/512 = 31.25kHz clo
ck
void setup_timer1(void)
{
// Timer1 Clock Prescaler to : 1
sbi (TCCR1B, CS10);
cbi (TCCR1B, CS11);
cbi (TCCR1B, CS12);
// Timer0 PWM Mode set to Phase Correct PWM
cbi (TCCR1A, COM1A0); // clear Compare Match
sbi (TCCR1A, COM1A1);
cbi (TCCR1A, COM1B0); // clear Compare Match
sbi (TCCR1A, COM1B1);
sbi (TCCR1A, WGM10); // Mode 1 / Phase Correct PWM
cbi (TCCR1A, WGM11);
cbi (TCCR1B, WGM12);
cbi (TCCR1B, WGM13);
}
//******************************************************************
// timer2 setup
// set prscaler to 1, PWM mode to phase correct PWM, 16000000/512 = 31.25kHz clo
ck
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);
}
//******************************************************************
// Timer2 Interrupt Service at 31.25kHz = 32us
// this is the timebase REFCLOCK for the DDS generator
// FOUT = (M (REFCLK)) / (2 exp 32)

// runtime : 8 microseconds ( inclusive push and pop)


ISR(TIMER2_OVF_vect)
{
sbi(PORTD, TEST_PIN); // Test / set PORTD,TEST_PIN high to observe timing with a
oscope
phase_accum += tword_m; // soft DDS, phase accu with 32 bits
icnt = phase_accum >> 24; // use upper 8 bits for phase accu as frequency inform
ation
OCR2A = pgm_read_byte_near(sine256 + icnt); // read value fron ROM sine table an
d send to PWM DAC
OCR1A = pgm_read_byte_near(sine256 + (uint8_t)(icnt + OFFSET_1));
OCR1B = pgm_read_byte_near(sine256 + (uint8_t)(icnt + OFFSET_2));
if (icnt1++ == 125) // increment variable c4ms every 4 milliseconds
{
c4ms++;
icnt1 = 0;
}
cbi(PORTD, TEST_PIN); // reset PORTD,TEST_PIN

#include <avr/pgmspace.h> //Store data in flash (program) memory instead of SRAM


// Look Up table of a single sine period divied up into 256 values. Refer to PWM
to sine.xls on how the values was calculated
PROGMEM prog_uchar sine256[] = {
127,130,133,136,139,143,146,149,152,155,158,161,164,167,170,173,176,178,181,18
4,187,190,192,195,198,200,203,205,208,210,212,215,217,219,221,223,225,227,229,23
1,233,234,236,238,239,240,
242,243,244,245,247,248,249,249,250,251,252,252,253,253,253,254,254,254,254,25
4,254,254,253,253,253,252,252,251,250,249,249,248,247,245,244,243,242,240,239,23
8,236,234,233,231,229,227,225,223,
221,219,217,215,212,210,208,205,203,200,198,195,192,190,187,184,181,178,176,17
3,170,167,164,161,158,155,152,149,146,143,139,136,133,130,127,124,121,118,115,11
1,108,105,102,99,96,93,90,87,84,81,78,
76,73,70,67,64,62,59,56,54,51,49,46,44,42,39,37,35,33,31,29,27,25,23,21,20,18,
16,15,14,12,11,10,9,7,6,5,5,4,3,2,2,1,1,1,0,0,0,0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9,
10,11,12,14,15,16,18,20,21,23,25,27,29,31,
33,35,37,39,42,44,46,49,51,54,56,59,62,64,67,70,73,76,78,81,84,87,90,93,96,99,
102,105,108,111,115,118,121,124
};
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) //define a bit to have the p
roperties of a clear bit operator
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))//define a bit to have the pro
perties of a set bit operator
int PWM1= 11;// PWM1 output, phase 1
int PWM2 = 3; //[WM2 ouput, phase 2
int PWM3 = 10; //PWM3 output, phase 3
int offset_1 = 85; //offset 1 is 120 degrees out of phase with previous phase, R
efer to PWM to sine.xls
int offset_2 = 170; //offset 2 is 120 degrees out of phase with offset 1. Refer
to PWM to sine.xls
int program_exec_time = 6; //monitor how quickly the interrupt trigger
int ISR_exec_time = 7; //monitor how long the interrupt takes

double dfreq;
const double refclk=31376.6;

// measured output frequency

// variables used inside interrupt service declared as voilatile


volatile byte current_count;
// Keep track of where the current cou
nt is in sine 256 array
volatile byte ms4_delay;
//variable used to generate a 4ms delay
volatile byte c4ms;
// after every 4ms this variable is incremented
, its used to create a delay of 1 second
volatile unsigned long phase_accumulator; // pahse accumulator
volatile unsigned long tword_m; // dds tuning word m, refer to DDS_calculator (
from Martin Nawrath) for explination.
void setup()
{
pinMode(PWM1, OUTPUT);
//sets the digital pin as output
pinMode(PWM2, OUTPUT);
//sets the digital pin as output
pinMode(PWM3, OUTPUT);
//sets the digital pin as output
pinMode(program_exec_time, OUTPUT);
//sets the digital pin as output
pinMode(9, OUTPUT);
//sets the digital pin as output
sbi(PORTD,program_exec_time); //Sets the pin
Setup_timer1();
Setup_timer2();
//Disable Timer 1 interrupt to avoid any timing delays
cbi (TIMSK0,TOIE0);
//disable Timer0 !!! delay() is now not avail
able
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)
{
sbi(PORTD,program_exec_time); //Sets the pin
if (c4ms > 250) // c4ms = 4ms, thus 4ms *250 = 1 second delay
{
c4ms=0;
//Reset c4ms
dfreq=analogRead(0);
//Read voltage on analog 1 to see desir
ed output frequency, 0V = 0Hz, 5V = 1.023kHz
cbi (TIMSK2,TOIE2);
//Disable Timer2 Interrupt
tword_m=pow(2,32)*dfreq/refclk; //Calulate DDS new tuning word
sbi (TIMSK2,TOIE2);
//Enable Timer2 Interrupt
}
}
}
//Timer 1 setup
//Set prscaler to 1, PWM mode to phase correct PWM, 16000000/510 = 31372.55 Hz
clock
void Setup_timer1(void)
{
// Timer1 Clock Prescaler to : 1
sbi (TCCR1B, CS10);
cbi (TCCR1B, CS11);
cbi (TCCR1B, CS12);

// Timer1 PWM Mode set to Phase Correct PWM


cbi (TCCR1A, COM1A0);
sbi (TCCR1A, COM1A1);
cbi (TCCR1A, COM1B0);
sbi (TCCR1A, COM1B1);
// Mode 1 / Phase Correct PWM
sbi (TCCR1A, WGM10);
cbi (TCCR1A, WGM11);
cbi (TCCR1B, WGM12);
cbi (TCCR1B, WGM13);
}
//Timer 1 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);
cbi (TCCR2A, COM2B0);
sbi (TCCR2A, COM2B1);
// Mode 1 /
sbi (TCCR2A,
cbi (TCCR2A,
cbi (TCCR2B,

Phase Correct PWM


WGM20);
WGM21);
WGM22);

}
//Timer2 Interrupt Service at 31372,550
//This is the timebase REFCLOCK for the
//FOUT = (M (REFCLK)) / (2 exp 32)
//Runtime : 8 microseconds
ISR(TIMER2_OVF_vect)
{
cbi(PORTD,program_exec_time); //Clear
sbi(PORTD,ISR_exec_time);
//

KHz = 32uSec
DDS generator

the pin
Sets the pin

phase_accumulator=phase_accumulator+tword_m; //Adds tuning M word to previoud


phase accumulator. refer to DDS_calculator (from Martin Nawrath) for explination
.
current_count=phase_accumulator >> 24;
// use upper 8 bits of phase_accumu
lator as frequency information
OCR2A=pgm_read_byte_near(sine256 + current_count); // read value fron ROM sine
table and send to PWM
OCR2B=pgm_read_byte_near(sine256 + (uint8_t)(current_count + offset_1)); // re
ad value fron ROM sine table and send to PWM, 120 Degree out of phase of PWM1
OCR1A =
ead value
OCR1B =
ead value

pgm_read_byte_near(sine256 +
fron ROM sine table and send
pgm_read_byte_near(sine256 +
fron ROM sine table and send

(uint8_t)(current_count +
to PWM, 120 Degree out of
(uint8_t)(current_count +
to PWM, 120 Degree out of

offset_2));// r
phase of PWM2
offset_2));// r
phase of PWM2

//increment variable ms4_delay every 4mS/125 = milliseconds 32uS


if(ms4_delay++ == 125)
{
c4ms++;
ms4_delay=0; //reset count
}
cbi(PORTD,ISR_exec_time);
}

//Clear the pin

#include "avr/pgmspace.h"
#include "avr/io.h"
// Look Up table of a single sine period divied up into 256 values. Refer to PWM
to sine.xls on how the values was calculated
PROGMEM prog_uchar sine256[] = {
127, 130, 133, 136, 139, 143, 146, 149, 152, 155, 158, 161, 164, 167, 170, 173
, 176, 178, 181, 184, 187, 190, 192, 195, 198, 200, 203, 205, 208, 210, 212, 215
, 217, 219, 221, 223, 225, 227, 229, 231, 233, 234, 236, 238, 239, 240,
242, 243, 244, 245, 247, 248, 249, 249, 250, 251, 252, 252, 253, 253, 253, 254
, 254, 254, 254, 254, 254, 254, 253, 253, 253, 252, 252, 251, 250, 249, 249, 248
, 247, 245, 244, 243, 242, 240, 239, 238, 236, 234, 233, 231, 229, 227, 225, 223
,
221, 219, 217, 215, 212, 210, 208, 205, 203, 200, 198, 195, 192, 190, 187, 184
, 181, 178, 176, 173, 170, 167, 164, 161, 158, 155, 152, 149, 146, 143, 139, 136
, 133, 130, 127, 124, 121, 118, 115, 111, 108, 105, 102, 99, 96, 93, 90, 87, 84,
81, 78,
76, 73, 70, 67, 64, 62, 59, 56, 54, 51, 49, 46, 44, 42, 39, 37, 35, 33, 31, 29
, 27, 25, 23, 21, 20, 18, 16, 15, 14, 12, 11, 10, 9, 7, 6, 5, 5, 4, 3, 2, 2, 1,
1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 5, 5, 6, 7, 9, 10, 11, 12, 14, 1
5, 16, 18, 20, 21, 23, 25, 27, 29, 31,
33, 35, 37, 39, 42, 44, 46, 49, 51, 54, 56, 59, 62, 64, 67, 70, 73, 76, 78, 81
, 84, 87, 90, 93, 96, 99, 102, 105, 108, 111, 115, 118, 121, 124
};
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
int PWM_OUT_1 = 11; // PWM output on pin 11
int PWM_OUT_2 = 10; // PWM output on pin 10
int PWM_OUT_3 = 12; // PWM output on pin 9
int LED_PIN = 13; // LED status on pin 13
int TEST_PIN = 7; // Scope trigger on pin 7
int POTEN_IN = A0; // Potentiometer on pin 0
int OFFSET_1 = 85; // Offset for second-phase
int OFFSET_2 = 170; // Offset for third-phase
double dfreq;
const double refclk = 31376.6; // measured
const uint64_t twoTo32 = pow(2, 32); // compute value at startup and use as cons
tant
// variables used inside interrupt service declared as voilatile
volatile uint8_t icnt; // var inside interrupt
volatile uint8_t icnt1; // var inside interrupt
volatile uint8_t c4ms; // counter incremented every 4ms
volatile uint32_t phase_accum; // pahse accumulator
volatile uint32_t tword_m; // dds tuning word m
//******************************************************************
void setup()

{
pinMode(LED_PIN, OUTPUT); // sets the digital pin as output
Serial.begin(115200); // connect to the serial port
Serial.println("DDS Test");
pinMode(TEST_PIN, OUTPUT); // sets the digital pin as output
pinMode(PWM_OUT_1, OUTPUT); // PWM output / frequency output
pinMode(PWM_OUT_2, OUTPUT); // PWM output / frequency output
pinMode(PWM_OUT_3, OUTPUT); // PWM output / frequency output
// Setup the timers
setup_timer1();
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.0 Hz
tword_m = twoTo32 * dfreq / refclk; // calulate DDS new tuning word
}
//******************************************************************
void loop()
{
if (c4ms > 250) // timer / wait for a full second
{
c4ms = 0;
dfreq = analogRead(POTEN_IN); // read Poti on analog pin 0 to adjust output
frequency from 0..1023 Hz
cbi (TIMSK2, TOIE2); // disble Timer2 Interrupt
tword_m = twoTo32 * dfreq / refclk; // calulate DDS new tuning word
sbi (TIMSK2, TOIE2); // enable Timer2 Interrupt
Serial.print(dfreq);
Serial.print(" ");
Serial.println(tword_m);
}
}
//******************************************************************
// timer1 setup
// set prscaler to 1, PWM mode to phase correct PWM, 16000000/512 = 31.25kHz clo
ck
void setup_timer1(void)
{
// Timer1 Clock Prescaler to : 1
sbi (TCCR1B, CS10);
cbi (TCCR1B, CS11);
cbi (TCCR1B, CS12);
// Timer0 PWM Mode set to Phase Correct PWM
cbi (TCCR1A, COM1A0); // clear Compare Match
sbi (TCCR1A, COM1A1);
cbi (TCCR1A, COM1B0); // clear Compare Match
sbi (TCCR1A, COM1B1);
sbi (TCCR1A, WGM10); // Mode 1 / Phase Correct PWM
cbi (TCCR1A, WGM11);
cbi (TCCR1B, WGM12);
cbi (TCCR1B, WGM13);
}
//******************************************************************
// timer2 setup
// set prscaler to 1, PWM mode to phase correct PWM, 16000000/512 = 31.25kHz clo
ck
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);
}
//******************************************************************
// Timer2 Interrupt Service at 31.25kHz = 32us
// this is the timebase REFCLOCK for the DDS generator
// FOUT = (M (REFCLK)) / (2 exp 32)
// runtime : 8 microseconds ( inclusive push and pop)
ISR(TIMER2_OVF_vect)
{
sbi(PORTD, TEST_PIN); // Test / set PORTD,TEST_PIN high to observe timing with
a oscope
phase_accum += tword_m; // soft DDS, phase accu with 32 bits
icnt = phase_accum >> 24; // use upper 8 bits for phase accu as frequency info
rmation
OCR2A = pgm_read_byte_near(sine256 + icnt); // read value fron ROM sine table
and send to PWM DAC
OCR1A = pgm_read_byte_near(sine256 + (uint8_t)(icnt + OFFSET_1));
OCR1B = pgm_read_byte_near(sine256 + (uint8_t)(icnt + OFFSET_2));
if (icnt1++ == 125) // increment variable c4ms every 4 milliseconds
{
c4ms++;
icnt1 = 0;
}
cbi(PORTD, TEST_PIN); // reset PORTD,TEST_PIN
}

const byte sine256[] PROGMEM = {


const unsigned char sine256[] PROGMEM = {
const uint8_t sine256[] PROGMEM = {

Das könnte Ihnen auch gefallen