Timer0 y Timer2 configuración en atmega1280

0

Quiero configurar Timer0 y Timer2 para controlar la intensidad del LED (L) en el Arduino Atmega1280.

La frecuencia debe ser de 10 kHz y el ciclo de trabajo se controlará mediante un interruptor o mediante una comunicación en serie a través de uart (incremento y decremento); Actualmente, la única parte en la que tengo problemas es al inicializar los temporizadores y no estoy seguro de si mi enfoque es el correcto, que es el siguiente:

Dado que necesito control sobre la frecuencia y en el ciclo de trabajo, creo que necesito usar dos temporizadores, he buscado si se puede hacer usando solo uno, pero la mayoría de los tutoriales y guías solo se enfocan en cambiar la frecuencia o el deber así que he llegado a la conclusión de que al usar un temporizador solo puedes controlar la frecuencia o el ciclo de trabajo.

Mi plan es usar Timer2 como el reloj de 10 khz para Timer0, cuando Timer0 se desborda, cambiará su señal, el ciclo de trabajo se controla mediante OCROA y la frecuencia para Timer2 se establece con el escalador previo siendo 8 y OCR2A = 200 :

$$ f_ {pwm} = \ frac {f_ {clk}} {N \ cdot R_ {OCR0A}} $$ $$ 10000 = \ frac {16000000} {8 \ cdot 200} $$

He configurado Timer0 para que no tenga fuente de reloj, ya que lo estaré incrementando manualmente con TIMER2_OVF_vect , aquí está la rutina que configura ambos temporizadores.

/**
 * Configures a PWM with variying duty cycle at 10Khz.
 * 
 * First we set Timer2 to be the 10khz clock source:
 *     f = 16e6 / (8 * 200) 
 *
 * Second we set Timer0 to be the duty cycle specifier
 * Timer2 is incremented by each tick of Timer0 and the one that 
 * sends the signal to the Led (L)
 * 
 */
void setupPWM(void) {
    // Timer2
    // Set the top to be 200
    OCR2A = (uint8_t) 200;

    // Set the clock source to use Pre-scale 8
    CLR_BIT(TCCR2B, CS20);
    SET_BIT(TCCR2B, CS21);
    CLR_BIT(TCCR2B, CS22);

    // Set the Waveform generation mode to OVF on top
    SET_BIT(TCCR2A, WGM20);
    SET_BIT(TCCR2A, WGM21);
    SET_BIT(TCCR2B, WGM22);

    // We don't need to set COM2A, because 
    // we won't use wiring, we'll use 
    // interrupts as a counter inc for Timer0
    SET_BIT(TIMSK2, TOIE2);


    // Timer0
    // Set PB7 for output and clear the value
    SET_BIT(DDRB, PB7);
    CLR_BIT(PORTB, PB7);

    // Disable the internal clock source, we will clock it with the TOVI
    CLR_BIT(TCCR0B, CS00);
    CLR_BIT(TCCR0B, CS01);
    CLR_BIT(TCCR0B, CS02);  

    // Set waveform gen to FPWM with OCRA as the 
    // top, OCRA will be set by the duty cycle functions
    // We start at 50%
    SET_BIT(TCCR0A, WGM00);
    SET_BIT(TCCR0A, WGM01);
    SET_BIT(TCCR0B, WGM02);

    // Set COM mode to toggle the output on
    // OCROA match
    SET_BIT(TCCR0A, COM0A0);
    CLR_BIT(TCCR0A, COM0A1);

    SET_BIT(TIMSK0, TOIE0);

    OCR0A = (uint8_t) 128; // Set it to 50% duty initially
    TCNT0 = 0;
}

Timer2 se desborda correctamente, sin embargo, Timer0 parece no estar funcionando como debería suponer, ya que los bits CS0:2 son 0, el TIMER0_OVF_vect ISR no se activa, sin embargo, no estoy seguro de que si configuro Timer0 en PWM rápido voy a perder la frecuencia 10khz.

Cualquier ayuda es realmente apreciada.

    
pregunta Tristian

2 respuestas

1

Creo que es trivial controlar la frecuencia y PWM usando un temporizador incluso sin interrupción. Necesita seleccionar el modo de temporizador que admita el valor TOP para especificar la frecuencia con precisión (el temporizador de 16 bits puede hacerlo con mayor precisión, pero no creo que sea tan crítico para el LED). FastPWM es suficiente, por lo tanto, seleccione el modo 7 . OCRnA especifica la frecuencia f = fclk / (N * (OCRxA + 1)) . El pin de salida se selecciona como OCnx (x > A) y el ciclo de trabajo se controla mediante el registro de OCRnx (x > A) en el rango (0 .. OCRnA ). Es necesario seleccionar el modo de salida comparar correcto (cómo se comporta el pin de salida) pero está bien especificado en la hoja de datos. También existen problemas como el búfer doble porque existe una condición de carrera potencial, ya que está cambiando parámetros en tiempo de ejecución, pero no es tan crítico.

    
respondido por el TMa
0

Entonces, después de pensar más en ello, el problema principal fue que no pude controlar la frecuencia del Timer0 con los desbordamientos del Timer2. Sin embargo, después de leer más en la sección Timer0, podemos configurar el Timer0 para usar T0 como un externo. Fuente de reloj marcada en el flanco ascendente o descendente. T0 está conectado al puerto D, por lo que tenemos que configurar el puerto D correctamente como salida.

void setupTimer0(void) {
    // Set the clock source to be T0 (PD7)
    SET_BIT(TCCR0B, CS00);
    SET_BIT(TCCR0B, CS01);
    SET_BIT(TCCR0B, CS02);

    // Set waveform gen to FPWM with OCRA as the 
    // top, OCRA will be set by the duty cycle functions
   // We start at 50%
   SET_BIT(TCCR0A, WGM00);
   SET_BIT(TCCR0A, WGM01);
   SET_BIT(TCCR0B, WGM02);

   // Set COM mode to toggle the output on
   // OCROA match
   SET_BIT(TCCR0A, COM0A0);
   CLR_BIT(TCCR0A, COM0A1);
}

void setupTimer2(void) {
    // f = 16e6 / (8 * 200)
    // Set the top to be 200
    OCR2A = (uint8_t) 200;

    // Set the clock source to use Pre-scale 8
    CLR_BIT(TCCR2B, CS20);
    SET_BIT(TCCR2B, CS21);
    CLR_BIT(TCCR2B, CS22);

    // Set the Waveform generation mode to OVF on top
    SET_BIT(TCCR2A, WGM20);
    SET_BIT(TCCR2A, WGM21);
    SET_BIT(TCCR2B, WGM22);

    // Disconnect OC2A as we don't use it
    CLR_BIT(TCCR2B, COM2A0);
    CLR_BIT(TCCR2B, COM2A0);

    // Set PD7 (T0) for output
    SET_BIT(DDRD, PD7);
    CLR_BIT(PORTD, PD7);

    // Enable the timer2 overflow interrupt
    SET_BIT(TIMSK2, TOIE2);
}

ISR ( TIMER2_OVF_vect ) {
    SET_PIN(PIND, PD7); // Toggle the pin value to create a 'tick'
}

Aquí está la tabla CS0:2 para referencia

    
respondido por el Tristian

Lea otras preguntas en las etiquetas