¿Cómo borrar manualmente OC1A y OC1B?

En el arduino uno (= ATmega328/P ), ¿cómo puedo borrar manualmente la señal de comparación de salida del temporizador 1?

El propósito del código es generar algunos pulsos de salida después de un intervalo preciso desde el pulso de entrada. Hay dos canales de salida que deben controlarse, potencialmente con diferentes retrasos. La longitud del pulso no es crítica, solo debe tener una duración de al menos 8 µs, pero la sincronización para el flanco ascendente debe ser precisa.

Actualmente mi código se ve así:

#define MAINS_PERIOD 16667 // in microseconds

ISR(TIMER1_CAPT_vect) {
    GTCCR = _BV(TSM);
    TCNT1 = TCNT1 - ICR1 - MAINS_PERIOD + 1 + 300;
    GTCCR = 0;
}
ISR(TIMER1_COMPA_vect) {
    delayMicroseconds(8);
    OC1A = 0; // <---------- what do I do here?
}
ISR(TIMER1_COMPB_vect) {
    delayMicroseconds(8);
    OC1B = 0; // <---------- what do I do here?
}

void setup() {
    TCCR1A = _BV(COM1A0) | _BV(COM1A1) | _BV(COM1B0) | _BV(COM1B1); // set output on compare match, normal mode, prescaler /8
    TCCR1B = _BV(CS11) | _BV(ICNC1) | _BV(ICES1); // input capture noise cancel, positive edge
    TIMSK1 = _BV(ICIE1) | _BV(OCIEA1), | _BV(OCIEB1); // generate interrupts for input capture, A/B compare match

    pinMode(8, INPUT);  //set data direction
    pinMode(9, OUTPUT); 
    pinMode(10, OUTPUT);
}

Potencialmente, podría reconfigurar el modo de salida del temporizador para borrar la coincidencia y luego forzar una coincidencia, pero parece que debería haber una forma más sencilla de hacerlo:

ISR(TIMER1_COMPA_vect) {
    delayMicroseconds(8);

    TCCR1A &=~ _BV(COM1A0);
    TCCR1C = _BV(FOC1A);
    TCCR1A |= _BV(COM1A0);
}

Simplemente borrar el bit de registro del pin de salida ( PORTB &=~ _BV(PORTB1);) no funcionará en este caso porque el registro del puerto se ignora cada vez que se habilita una función alternativa (como la salida del temporizador) en el pin.

Alternativamente, si hay una manera de hacer que las salidas del temporizador se despejen en caso de desbordamiento (¿algún tipo de modo PWM de 16 bits no documentado?), Eso sería aún mejor, pero dudo que haya una manera de hacerlo.

No tengo muy claro exactamente lo que estás tratando de lograr aquí. ¿Quieres un pulso de un solo disparo después de un disparador externo? ¿O un tren de pulsos tras un disparador externo? ¿O algo más otra vez? ¿Con qué frecuencia desea este/estos pulso/s?

Respuestas (2)

Es posible configurar el temporizador para alternar OC1A con

TCCR1A |= (1 << COM1A0);

Dentro de la rutina de interrupción, utilice el registro de control para activar un evento de comparación adicional. Esto NO tiene efectos secundarios como cambiar el valor del temporizador.

TCCR1C |= (1 << FOC1A);

Para cambiar inmediatamente, configure el tipo para borrar o configurar el modo y active un cambio

TCCR1A = (1 << COM1A0);
TCCR1C |= (1 << FOC1A);

ver https://www.sparkfun.com/datasheets/Components/SMD/ATMega328.pdf p.137

ISR(TIMER1_COMPA_vect) {
    delayMicroseconds(8);
    OC1A = 0; // <---------- what do I do here?
}

tener los retrasos en el isr no sería demasiado bueno para la codificación.

Múltiples formas de hacerlo. y aquí hay uno:

1) configure la base de tiempo, no inicie el temporizador todavía;

2) configurar la comparación para la salida deseada, interrupción habilitada. pin OC1A/B configurado/limpiado según sus necesidades;

3) configure la interrupción para ver su pulso de entrada.

4) en el pulso de entrada isr, inicie el temporizador;

5) en el isr de comparación de salida, borre/establezca el pin OC1A/B, deshabilite la interrupción de comparación de salida y restablezca/desactive el temporizador.

editar: debe tenerse en cuenta que el enfoque anterior asume una cantidad trivial de gastos generales de isr. para duraciones cortas o procesadores lentos, ese puede no ser el caso.

Mi pregunta es sobre cómo se borra OC1A/B. Sé que usar un retraso en una interrupción es una mala idea, y lo cambiaré más tarde, pero necesito alguna forma de borrar los bits de salida.