Cambiar frecuencia PWM

Hola, estoy intentando cambiar la frecuencia PWM, he probado varias formas y con distintos Timer y no obtengo ningun resultado:

Opcion 1) --> Timer 0

TCCR0A = _BV(COM0A1) | _BV(COM0B1) | _BV(WGM00); // CONFIGURACION PHASE-CORRECT

TCCR0B = _BV(CS00); // FACTOR DE ESCALA = 1

(info de la configuracion de los registros sacada de Arduino Playground)

Se supone que modificando los registros del Timer 0 de esta manera podria obtener en una de las salidas que maneja este Timer una frecuencia de 31.25 kHz, segun la formula del Datasheet de Atmel

F_phase_correct= (fclock / pres-scaler*510)


Opcion 2) ---> Timer 1

TCCR1A = 0x00;

TCCR1B = 0x11; // Modo Phase-correct , pre-scaler = 1

ICR1 = 214; // valor TOP

con esta opcion se supone que obtendria una frecuencia en una de las salidas que maneja este Timer de 37,38 kHz, segun la formula :

F_phase_correct= (fclock / pres-scaler2ICR1)

(esta info la he sacado de una web que me he encontrado por ahi)

Si me podeis ayudar, Gracias 1000!!! :smiley:

Este tutorial es muy bueno y de facil entendimiento

Mira este tutorial de Nick Gammon del Moderador Global de arduino.

Lo que me ocurre con el segundo tutorial es que Nick Gammon dice que su sketch asi funciona y no he logrado que lo haga.
En cambio con el primero no tengo problemas.
Una cosa es setear los timers y sus registros como tu has hecho y otra es prescindir de la ISR correspondiente.
Sin una rutina de interrupción no he logrado que funcionen.
Con el AVR si lo hacía.

Ok, voy a echar un vistazo a ver si me aclaro y te comento, ya decia yo que tan facil no podia ser...jejejej, gracias de nuevo por cotestar.

Es facil cuando se entiende al 100%.
Puntualmente el tutorial de Gammon a mi me deja como si le faltara algo pero leo los comentarios y pienso que ese algo es que yo no se habilitar determinado registro. No me doy cuenta.
Ahora cuando probé esos ejemplos con una subrutina de interrupción funcionaron sin problemas.

con estas 3 lineas de codigo puestas en el Setup, cambias la frecuencia de arduino del pin 9 a 37 khz.

TCCR1A = 0x00; // modifica el TCCR (timer 1) (pin A) = pin digital 9
TCCR1B = 0x11; // y este modifica el preescalado
ICR1 = 214; //valor maximo de analogwrite modificarlo, tambien modificaria la frecuencia de 37 khz otra cualquiera.

esta modificacion no cambia ningun valor en el timer de arduino que controla el delay. Dejo tambien la formula por si interesa algun cambio.

// Fórmula: Fpwm(KHz) = 16000KHz [clock de la arduino] / (2 * N* ICR1)

Donde ICR1 es el valor maximo de analogWrite y N es el factor de reescalado dentro de estos posibles.
(TCCR1B=0x11 -->N=1; TCCR1B=0x12 -->N=8; TCCR1B=0x13 -->N=64, etc)

dejo la Fuente

Una pregunta al respecto de la frecuencia. Mido en el osciloscopio la fecuencia de la señal de entrada de un mando de RC (freq= 62.5 Hz) con un periodo (T=16ms).

Lo mido o calculo tambien en arduino mediante el capturador de ventos externosdel Timer 1 de Arduino y obtengo la misma frecuencia (62.5 Hz) , hago la inversa para calcular el periodo y es distinto periodo (T= 20ms) , 4 ms más que en el osciloscopio.

Como puede ser eso??.

pego aqui el codigo de captura de frecuencia:

volatile boolean primero; 
volatile boolean disparo; 
volatile unsigned long overflowCount; // desbordamiento de contador
volatile unsigned long tiempo_inicio; // inicio tiempo
volatile unsigned long tiempo_final; // final tiempo

// here on rising edge
void isr () 
{
 unsigned int contador = TCNT1;  //(contador de disparos), TCNT1 se va incrementando en 1 
                                // cada vez que salta la imnterrupcion
 
 // wait until we noticed last one
 if (disparo)
   return;

 if (primero)
   {
   tiempo_inicio = (overflowCount << 16) + contador;
   primero = false;
   return;  
   }
   
 tiempo_final = (overflowCount << 16) + contador; 
 disparo = true;
 detachInterrupt(0);   
}  // end of isr

// timer overflows (every 65536 counts)
ISR (TIMER1_OVF_vect) 
{
 overflowCount++;
 
}  // end of TIMER1_OVF_vect



void prepareForInterrupts ()
 {
 
 EIFR = _BV (INTF0);  // (limpia registro para interrupcion 0 , pin 2)
 primero = true;
 disparo = false;  // se `pone a false para la proxima lectura
 attachInterrupt(0, isr, RISING);     
 }  
 

void setup () {
 
 Serial.begin(9600);  
 Serial.println("Frequency Counter");
 
//  // reset Timer 1
 TCCR1A = 0;
  
 TCCR1B = 0;
 
//  // Timer 1 - interrumpir desbordamiento
 TIMSK1 = _BV (TOIE1);   // Habilita interrupcion Timer 1
   

 TCNT1 = 0;   

//  // iniciar Timer 1
 TCCR1B =  _BV (CS20);  //  no prescaling
   

 
 prepareForInterrupts ();   
 
} 

void loop () 
 {

 if (!disparo)
   return;

 unsigned long tiempo_transcurrido = tiempo_final - tiempo_inicio;
 float freq = 1.0 / ((float (tiempo_transcurrido) * 62.5e-9));  // each tick is 62.5 nS
 
 float T = 1.0/freq;
 
 Serial.print ("Tiempo inicial : ");
 Serial.print ("  ");
 Serial.println (tiempo_inicio);
 
 Serial.print ("Tiempo final : ");
  Serial.print ("  ");
 Serial.println (tiempo_final);
   
 Serial.print ("Took: ");
 Serial.print ("  ");
 Serial.println (tiempo_transcurrido);
 
 Serial.print ("Frequency: ");
 Serial.print (freq);
 Serial.println (" Hz. ");
 
 Serial.print ("Periodo: ");
 Serial.print (T);
 Serial.println (" seg. ");
 
 
// Serial.println (" seg. ");


 // so we can read it  
 delay (1000);

 prepareForInterrupts ();   
}   // end of loop

Obviamente el Osciloscopio esta bien y el código comete algun error en principio, dicho esto por lógica pura.

Bueno el problema es mas simple de lo que uno imagina.
Serial.print con los float redondea a 2 decimales, entonces un resultado como 0.016 bien calculado se redondea a 0.02 seg
La solución es que en lugar de calcular T = 1/freq; hagas esto

 T = float(tiempo_transcurrido * 62.5e-6); // expresado en mseg

Ok, gracias 1000!.

Poco a poco haber si me voy quedando con estos pequeños detalles.
Gracias.

Saludos a Todos, soy nuevo en el Foro.

Por si alguien puede ayudarme, necesito generar por ejemplo en el pin 9 una salida de 7,83 Hz (2 decimales) con un 50% de Duty Cicle, y también la misma frecuencia pero con un ancho de pulso del 10%.

Gracias.

Necesito Ayuda PWM con decimales.

Saludos a Todos, soy nuevo en el Foro.

Por si alguien puede ayudarme, necesito generar por ejemplo en el pin 9 una salida de 7,83 Hz (2 decimales) con un 50% de Duty Cicle, y también la misma frecuencia pero con un ancho de pulso del 10%.

Gracias.

Teslatronica si con lo expuesto en este hilo no resolviste tu problema entonces no se como?

7.83Hz será dificil de lograr. Tampoco es un valor que tenga un período entero, porque da 1/7.83 = 127.714 milisegundos
raro muy raro.
Deberías haber preguntado en un hilo propio no en uno que tiene 1 año sin movimientos (esto anotalo para la próxima).
Veamos como genero 7.83 hz.. dificil.
Con Timer en modo Compare mach interrupt tienes este cálculo
Valor 1 = 16Mhz/256/7.83=
Valor 1 = 16000000/256/7.83= 7982.12 asi que puedes usar 7982 o 7983. El mas cercano es 7982

OCR1A = 7982;            [color=#7e7e7e]// compare match register[/color] [color=#7e7e7e]16MHz/256/2Hz[/color]
#define ledPin 13

void setup()
{
  pinMode(ledPin, OUTPUT);
  
  // initialize timer1 
  noInterrupts();           // deshabilito interrupciones
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1  = 0;

  OCR1A = 7982;            // compare match register 16MHz/256/7.83Hz
  TCCR1B |= (1 << WGM12);   // CTC mode
  TCCR1B |= (1 << CS12);    // 256 prescaler 
  TIMSK1 |= (1 << OCIE1A);  // habilito timer compare interrupt
  interrupts();             // habilito todas las interrupciones
}

ISR(TIMER1_COMPA_vect)          // timer compare interrupt service routine
{
  digitalWrite(ledPin, digitalRead(ledPin) ^ 1);   // basculo el pin LED a 7.83 aprox
}

void loop()
{
  // resto del programa acá...
}

El resto hazlo tu

MUCHAS GRACIAS POR LA AYUDA "surbyte", ya te comentaré el resultado.

Saludos