ATtiny85, modo PWM e interrupción overflow

  • Autor Miembro eliminado 356005
  • Fecha de inicio
M

Miembro eliminado 356005

Buenas...

Tengo un ATtiny85, 128 Khz, CLKDIV8 desactivado.

Usando el Timer/Contador 1, con un preescalado de /8192, y ajustando los contadores OCR1A y OCR1C, y ajustando el modo de comparación a modo alternante de las salidas, consigo que salga una perfecta señal cuadrada por PB0 y PB1 con un ciclo de trabajo de 6 segundos (3 segundos abajo, 3 arriba).

Lo que quiero es que se dispare la interrupción por comparación OCIE1A cuando el contador TCNT1 llega a OCR1A (mitad del ciclo de trabajo), y que se dispare la interrupción por desborde cuando el contador llegue a OCR1C (fin del ciclo de trabajo).

El problema es... que he probado de mil formas, y no encuentro la manera.

He conseguido que se dispare TIM1_COMPA_vect a la mitad del ciclo, e incluso he probado que TIM1_OVF_vect también se dispara si al principio del programa establezco TCNT1 a 250 (unos pocos ciclos de ejecución más tarde se llega al desborde $FF ➝ $00). En la siguiente vuelta, cuando TNCT1 llega al final del ciclo de trabajo (TCNT1 == OCR1C), se reinicia y vuelve a $00, y según la documentación,
«In PWM mode (either PWM1A=1 or PWM1B=1) the bit TOV1 is set (one) when compare match occurs between Timer/Counter1 and data value in OCR1C - Output Compare Register 1C. When the SREG I-bit, and TOIE1 (Timer/Counter1 Overflow Interrupt Enable), and TOV1 are set (one), the Timer/Counter1 Overflow interrupt is executed».

¿Alguien puede ayudarme?
¿No será otro bug del ATtiny85?
¿Es que acaso las dos interrupciones son incompatibles?
¿Tengo que activar algo más o he activado demás?

C:
/*
* Ciclos de trabajo de 6 segundos
*
* Joaquín Ferrero, 2018-02-25
*
*/

#define F_CPU 128000UL

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>

int main(void) {
    //           76543210
    DDRB   = 0b00011011;         // 0: entrada / 1: salida
    PORTB  = 0b00100100;         // Si DDRx es 0: PullUp 0: no / 1: sí / Si DDRx es 1: salida 0/1

    TCNT1  = 250;                // iniciar contador para probar que funciona el desborde
    OCR1A  = 48;                // 3 segundos, medio ciclo
    OCR1C  = 96;                // 6 segundos ciclo completo

    TCCR1 = 0
          | _BV(CTC1)            // reiniciar contador después de un compare match
          | _BV(PWM1A)            // PWMA activado
          | (0b1110 << CS10)    // prescalado a CK/8192
          | (0b01 << COM1A0)    // compare mode 0b01 : alternar pines OC1A y ¬OC1A
          ;

    TIMSK |= 0
          | _BV(OCIE1A)            // Interrupción para PWMA (compare match)
          | _BV(TOIE1)            // Interrupción para OCR1C (desborde)
          ;

    SREG  |= 0b10000000;        // Activar interrupciones

    while (1) {
    }
}

ISR(TIM1_COMPA_vect)
{
    // Final del medio ciclo
    PINB |= _BV(PINB3);            // Parpadeo de PB3
}

ISR(TIM1_OVF_vect)
{
    // Final de todo el ciclo
    PINB |= _BV(PINB4);            // Parpadeo del PB4
}
No pongo el esquema, porque es sencillamente el ATtiny85 con cuatro LED: en PB0, PB1, PB3 y PB4.

P.D.: Muchas gracias al administrador del sitio, por incluir por fin soporte para código fuente.
 
Última edición por un moderador:
Estas con el modo CTC "Clear Timer/Counter on Compare Match" activado y en este modo TCNT1 se reinicia cuando TCNT1 es igual a OCR1A con lo cual jamas tendremos un Overflow (TCNT1 = OCR1C).
Código:
•   Bit 7 – CTC1 : Clear Timer/Counter on Compare Match
When the CTC1 control bit is set (one), Timer/Counter1
is reset to $00 in the CPU clock cycle after a compare
match with OCR1A register. If the control
bit is cleared, Timer/Counter1 cont
inues counting and is unaffected by a
compare match.

saludos.
 
Última edición:
En la hoja de datos del ATtiny85, dice otra cosa: se refiere al registro OCR1C:
Bit 7 – CTC1 : Clear Timer/Counter on Compare Match
When the CTC1 control bit is set (one), Timer/Counter1 is reset to $00 in the CPU clock cycle after a compare match with OCR1C register value. If the control bit is cleared, Timer/Counter1 continues counting and is unaffected by a compare match.
Pero da igual: si lo quito, sigue sin generar la interrupción de fin de ciclo.

La única forma que veo que funciona la interrupción de overflow es cuando no uso el modo PWM
 
Última edición por un moderador:
Estuve simulando en isis y por lo que pude ver la interrupción por overflow solo ocurre cuando TCNT1 llega al máximo valor, quisas una posible solución seria usar la interrupción del registro OCR1B. Adjunto código con algunas modificaciones.

C:
/*
* Ciclos de trabajo de 6 segundos
*
* Joaquín Ferrero, 2018-02-25
*
*/

#define F_CPU 128000UL

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>

int main(void) {
    //           76543210
    DDRB   = 0b00011011;         // 0: entrada / 1: salida
    PORTB  = 0b00100100;         // Si DDRx es 0: PullUp 0: no / 1: sí / Si DDRx es 1: salida 0/1

    TCNT1  = 0;                // iniciar contador para probar que funciona el desborde
    OCR1A  = 48;
    OCR1B  = 96;// 3 segundos, medio ciclo
    OCR1C  = 96;                // 6 segundos ciclo completo

    TCCR1 = 0
          | _BV(CTC1)            // reiniciar contador después de un compare match
          | _BV(PWM1A)            // PWMA activado
          | (0b1110 << CS10)    // prescalado a CK/8192
          | (0b01 << COM1A0)    // compare mode 0b01 : alternar pines OC1A y ¬OC1A

          ;

    TIMSK =0
          | _BV(OCIE1A)            // Interrupción para PWMA (compare match)
          | _BV(OCIE1B)            // Interrupción para PWMB (compare match)
          //| _BV(TOIE1)            // Interrupción para OCR1C (desborde)
          ;

    SREG  |= 0b10000000;        // Activar interrupciones

    while (1) {
    }
}

ISR(TIM1_COMPA_vect)
{
    // Final del medio ciclo
    PINB |= _BV(PINB3);            // Parpadeo de PB3
}

ISR(TIM1_COMPB_vect)
{
    // Final de todo el ciclo
    PINB |= _BV(PINB4);            // Parpadeo del PB4
}

saludos.
 
¡AAAAAGGGGGGggggrrrrrr!

Acabo de ejecutar el programa en el simulador del Atmel Studio 7, ¡y funciona!

O sea... que el error no está en el programa, ¡sino en el propio ISIS!

Mi versión es la 7.9. ¿Y la tuya?
 
Atrás
Arriba