วันอังคารที่ 27 กันยายน พ.ศ. 2559

#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 const unsigned char sine256[] PROGMEM = { 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, 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 constant // 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 clock 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 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); } //****************************************************************** // 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 information 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 }

#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
const unsigned char sine256[] PROGMEM  = {
  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, 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 constant
// 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 clock
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 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);
}
//******************************************************************
// 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 information
  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
}

ไม่มีความคิดเห็น:

แสดงความคิดเห็น