Duda sobre Arduino + pwm y filtro pasa bajos

buenas.

estoy tratando de sacar una onda senoidal utilizando la tecnica de tablas y pwm desde un arduino mega, y mi idea es filtrar el pwm por medio de un filtro pasa bajas, y que el mismo este en resonancia, o sea que me filtre la señal pwm y se quede oscilando a su frecuencia de resonancia, es posible esto? he estado realizando las simulaciones, segun mis calculos mi programa me deberia de dar una onda senoidal (despues del filtro) de 5khz, pero esta solo sale a aprox. 550hz, estoy mal en concepto? adjunto programa, y screenshot del circuito en proteus.

Código:
/*frecuencia de senoidal= 5 kHz
  periodo= 180 uS
  calcular duty cycle cada: periodo/180= 1uS
*/

const int pwmPin=11;
const int seno[180]={127,131,135,140,144,149,153,157,162,166,170,174,178,182,186,190,194,198,201,205,208,211,215,218,221,224,227,229,232,234,236,239,241,243,244,246,247,249,250,
                  251,252,252,253,253,253,254,253,253,253,252,252,251,250,249,247,246,244,243,241,239,236,234,232,229,227,224,221,218,215,211,208,205,201,198,194,190,186,182,
                  178,174,170,166,162,157,153,149,144,140,135,131,127,122,118,113,109,104,100,96,91,87,83,79,75,71,67,63,59,55,52,48,45,42,38,35,32,29,26,24,21,19,17,14,12,10,
                  9,7,6,4,3,2,1,1,0,0,0,0,0,0,0,1,1,2,3,4,6,7,9,10,12,14,17,19,21,24,26,29,32,35,38,42,45,48,52,55,59,63,67,71,75,79,83,87,91,96,100,104,109,113,118,122};
void setup() {
  pinMode(pwmPin,OUTPUT);
   TCCR1B = (TCCR1B & 0xF8) | 0x01 ; //cambio de frec. del pwm a 31.374 kHz
  
}

void loop() {
  for (int i=0;i<180;i++){
    analogWrite(pwmPin,seno[i]);
    delayMicroseconds(1);
  }

}
 

Adjuntos

  • seno.jpg
    seno.jpg
    113.2 KB · Visitas: 33
Última edición:
hola! gracias por responder. sabes como sacar el archivo dsn en proteus 8?

aqui estan los archivos de simulacion



aqui esta el archivo dsn
 

Adjuntos

  • Simulacion y hex .rar
    55 KB · Visitas: 10
  • ROOT.rar
    15.1 KB · Visitas: 5
Última edición:
ya hice el mio pero les servirá al los demás para seguir el tema.
Primero el periódo es de 200useg y no 180. Tal vez para simplificar elegiste 180uS asi luego usas 1useg entre muestra y muestra.
Eso puede mejorarse.
Creo que el problema es tu frecuencia portadora.
Estoy en eso. Creo que debe ser mayor a lo que estas usando.
 
Este código funciona perfecto. Es para un UNO. Tiene algunas cosas que mejoraria como pow(2,32) que es superlento.
Pero funciona bien y generará tu F de 5Khz
usa un potenciometro conectado a A0 asi que modifica o quita esa parte.
no lo pruebes con el MEGA si no ajustas los timers y sus etiquetas porque no va a funcionar. No se llaman igual en MEGA y UNO.

Código:
/*
 *
 * DDS Sine Generator mit ATMEGS 168
 * Timer2 generates the  31250 KHz Clock Interrupt
 *
 * KHM 2009 /  Martin Nawrath
 * Kunsthochschule fuer Medien Koeln
 * Academy of Media Arts Cologne

 */

#include "avr/pgmspace.h"

// table of 256 sine values / one sine period / stored in flash memory
PROGMEM  const unsigned char 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,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 ledPin  = 13;                 // LED pin 7
int testPin = 7;
int t2Pin   = 6;
byte bb;

double dfreq;
// const double refclk=31372.549;  // =16MHz / 510
const double refclk = 31376.6;      // 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 incremented all 4ms
volatile unsigned long phaccu;   // pahse accumulator
volatile unsigned long tword_m;  // dds tuning word m

void setup()
{
  pinMode(ledPin, OUTPUT);      // sets the digital pin as output
  Serial.begin(115200);        // connect to the serial port
  Serial.println("DDS Test");

  pinMode(6, OUTPUT);      // sets the digital pin as output
  pinMode(7, OUTPUT);      // sets the digital pin as output
  pinMode(11, OUTPUT);     // pin11= PWM  output / frequency output

  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 = 5000.0;                    // initial output frequency = 5000.o Hz
  tword_m = pow(2,32)*dfreq/refclk;  // calulate DDS new tuning word 

}
void loop()
{
  while(1) {
     if (c4ms > 250) {                 // timer / wait fou a full second
      c4ms=0;
      dfreq=analogRead(0);             // read Poti on analog pin 0 to adjust output frequency from 0..1023 Hz
                                                 // quita esta linea para que no se modifique con un pote

      cbi (TIMSK2,TOIE2);              // disble Timer2 Interrupt
      tword_m=pow(2,32)*dfreq/refclk;  // calulate DDS new tuning word
      sbi (TIMSK2,TOIE2);              // enable Timer2 Interrupt 

      Serial.print(dfreq);
      Serial.print("  ");
      Serial.println(tword_m);
    }

   sbi(PORTD,6); // Test / set PORTD,7 high to observe timing with a scope
   cbi(PORTD,6); // Test /reset PORTD,7 high to observe timing with a scope
  }
 }
//******************************************************************
// 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);
}

//******************************************************************
// Timer2 Interrupt Service at 31372,550 KHz = 32uSec
// 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,7);          // Test / set PORTD,7 high to observe timing with a oscope

  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++ == 125) {  // increment variable c4ms all 4 milliseconds
    c4ms++;
    icnt1=0;
   }   

 cbi(PORTD,7);            // reset PORTD,7
}

No merezco el crédito por nada. Extraido de un link que tengo guardado. De hecho tengo este generador DDS en un NANO para uso personal.
Enlace a DDS
 
Última edición:
Muchas gracias SURbyte, ya hanbia visto esta pagina investigando hace unos dias, y como dijiste, no funciona en el mega, y la verdad no entiendo mucho el codigo, por lo que desisti en usar el mismo y tratar de hacer uno yo mismo, pero no me salio la jugada...:rolleyes:
 
La buena noticia es que mas alla que los pines son distintos entre UNO y MEGA lo que he leido es que la funcionalidad es la misma. Sin embargo cambié pines y no funciona.
 
yo tambien estuve modificando algo el codigo y no funciona, si no me equivoco se tendria que modifcar el registro TCCR2A por TCCR2B para utilizar el timer 2 y cambiar al pin 10.... entre otras cosillas pero no funciona jajaja
 
Pero TCCR2A y TCCR2B se llaman igual en el UNO y en el MEGA.

The Arduino has 3 timers and 6 PWM output pins. The relation between timers and PWM outputs is:

Pins 5 and 6: controlled by Timer0
Pins 9 and 10: controlled by Timer1
Pins 11 and 3: controlled by Timer2
On the Arduino Mega we have 6 timers and 15 PWM outputs:

Pins 4 and 13: controlled by Timer0
Pins 11 and 12: controlled by Timer1
Pins 9 and10: controlled by Timer2
Pin 2, 3 and 5: controlled by timer 3
Pin 6, 7 and 8: controlled by timer 4
Pin 46, 45 and 44:: controlled by timer 5
 
osea que todos los registros relacionados con los timers se llaman igual?



muchisimas gracias por tu ayuda SURbyte, ya logre que funcione, me canse y copie de nuevo el codigo y solo modifique el pin del pwm y funca... que JODA!:LOL:

adjunto codigo (aunque no haga falta) para los que se topen con este post y tengan el mismo problema...

Código:
/*
 *
 * DDS Sine Generator mit ATMEGS 168
 * Timer2 generates the  31250 KHz Clock Interrupt
 *
 * KHM 2009 /  Martin Nawrath
 * Kunsthochschule fuer Medien Koeln
 * Academy of Media Arts Cologne

 */

#include "avr/pgmspace.h"

// table of 256 sine values / one sine period / stored in flash memory
PROGMEM  const unsigned char 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,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 ledPin  = 13;                 // LED pin 7
int testPin = 7;
int t2Pin   = 6;
byte bb;

double dfreq;
// const double refclk=31372.549;  // =16MHz / 510
const double refclk = 31376.6;      // 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 incremented all 4ms
volatile unsigned long phaccu;   // pahse accumulator
volatile unsigned long tword_m;  // dds tuning word m

void setup()
{
  pinMode(ledPin, OUTPUT);      // sets the digital pin as output
  Serial.begin(115200);        // connect to the serial port
  Serial.println("DDS Test");

  pinMode(6, OUTPUT);      // sets the digital pin as output
  pinMode(7, OUTPUT);      // sets the digital pin as output
  pinMode(10, OUTPUT);     // pin10= PWM  output / frequency output

  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 = 5000.0;                    // initial output frequency = 5000.o Hz
  tword_m = pow(2,32)*dfreq/refclk;  // calulate DDS new tuning word 

}
void loop()
{
  while(1) {
     if (c4ms > 250) {                 // timer / wait fou a full second
      c4ms=0;
     // dfreq=analogRead(0);             // read Poti on analog pin 0 to adjust output frequency from 0..1023 Hz
                                                 // quita esta linea para que no se modifique con un pote

      cbi (TIMSK2,TOIE2);              // disble Timer2 Interrupt
      tword_m=pow(2,32)*dfreq/refclk;  // calulate DDS new tuning word
      sbi (TIMSK2,TOIE2);              // enable Timer2 Interrupt 

      Serial.print(dfreq);
      Serial.print("  ");
      Serial.println(tword_m);
    }

   sbi(PORTD,6); // Test / set PORTD,7 high to observe timing with a scope
   cbi(PORTD,6); // Test /reset PORTD,7 high to observe timing with a scope
  }
 }
//******************************************************************
// 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);
}

//******************************************************************
// Timer2 Interrupt Service at 31372,550 KHz = 32uSec
// 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,7);          // Test / set PORTD,7 high to observe timing with a oscope

  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++ == 125) {  // increment variable c4ms all 4 milliseconds
    c4ms++;
    icnt1=0;
   }   

 cbi(PORTD,7);            // reset PORTD,7
}



ahora.. viste la ganancia que se manda?? :eek: no deberia de haber una pequeña atenuacion?:eek:
 

Adjuntos

  • funca!.jpg
    funca!.jpg
    95.1 KB · Visitas: 14
Última edición:
Hasta donde se el pwm del arduino va a 1kHz más o meno, así que no tiene sentido meterle datos más rápido de esa frecuencia. Hay que mirar la documentación porque creo que no todos los pines van a la misma frecuencia.
Otra cosa es que se haga el pwm por software
 
Hasta donde se el pwm del arduino va a 1kHz más o meno, así que no tiene sentido meterle datos más rápido de esa frecuencia. Hay que mirar la documentación porque creo que no todos los pines van a la misma frecuencia.
Otra cosa es que se haga el pwm por software

Pero La portadora esta a casi 32k y se puede más modificando El prescaler.
 
Hasta donde se el pwm del arduino va a 1kHz más o meno, así que no tiene sentido meterle datos más rápido de esa frecuencia. Hay que mirar la documentación porque creo que no todos los pines van a la misma frecuencia.
Otra cosa es que se haga el pwm por software

En los atmega se puede, incluso yo llegué a levantar audio con 8kHz de muestreo y el PWM a 30 y pico de kHz, lo que resultaba fácil después para filtrarlo con un RC en 3 y pico de kHz.
 
Para el arduino due hay una librería de audio usando los dos dac que lleva.

Para 50Hz debería de valer con 1kHz, supongo.
 
ya solucionado el problema del software gracias al amigo SURbyte, me tope con otro inconveniente, con esos valores de L y C que estuve usando, funca al 100% segun la simulacion, pero 10,13mH como que seria una bobina muy grande, asi que recalcule los valores para el filtro aumentando el valor del capacitor, y resulta que con los nuevos valores no entra en resonancia (los 5khz de la fundamental), simplemente aplique la formula Fc=1/(2piSQRT(LC)), estoy dejando pasar algo por alto?
 
Última edición:
Ese filtro L-C está en una configuración de pasa bajos, cuya frecuencia de corte es lo que pusiste arriba.

Directamente probá con un filtro pasa bajos R-C, como tu frecuencia de muestreo es de 640kHz (5kHz * 128 muestras), solo tenés que preocuparte por la 1er armónica de 31 kHz del PWM, casi vas a tener 20dB de atenuación, un montón. Si lo querés mejorar aún más, implementá un filtro R-C de segundo grado usando un operacional.
 
hola cosmefulanito04, el problema es que necesito que sea un filtro LC o uno LR, veras, esta es la etapa de "prueba" para lo que va ser un cargador de baterias inalambrico, y mi idea es hacer que la bobina del filtro sea a la vez la bobina emisora, por lo que necesito que el cto. este en resonancia para la max. transferencia de energia, esta mal en este caso calcular los valores de L y C directamente para la frecuencia de corte de 5Khz?
por el momento solo quiero prender aunque sea un led para ver como funciona la cuestion.
 
Atrás
Arriba