Estoy tratando de usar uno de los temporizadores de hardware en el ATmega 328 / p (arduino uno) para generar un pulso corto algunos microsegundos después de recibir un pulso en una entrada.
Actualmente mi código se ve así:
uint16_t pulse_delay = 12000; //half-microseconds
uint16_t pulse_length = 20;
void setup(){
pinMode(8, INPUT);
pinMode(9, OUTPUT);
TCCR1A = 0;
TCCR1B = _BV(ICNC1) //input capture noise cancel
| _BV(ICES1) //positive edge
| _BV(CS11); // /8 prescaler
TIMSK1 = _BV(ICIE1); //enable input capture interrupt
}
void loop(){}
ISR(TIMER1_CAPT_vect){
TCCR1A = _BV(COM1A0) | _BV(COM1A1); //set OC1A on match
TIMSK1 |= _BV(OCIE1A); //enable match interrupt
OCR1A = pulse_delay; //pulse begin time
TCNT1 = TCNT1 - ICR1; //TCNT1 now contains time since input pulse, even if
//the interrupt isn't run immediately
}
ISR(TIMER1_COMPA_vect){
TIMSK1 &=~ _BV(OCIE1A); //disable match interrupt
TCCR1A = _BV(COM1A1); //clear OC1A on match
OCR1A = pulse_delay + pulse_length;
}
Este código debería, en teoría, hacer la tarea, pero no produce ninguna salida en absoluto, para mi osciloscopio parece que el pin de salida solo permanece bajo.
Sin embargo, si sustituyo la última línea ( OCR1A = pulse_delay + pulse_length;
) de la interrupción de coincidencia de comparación con las siguientes dos líneas, se emite un pulso muy bien. El problema con esto es que utiliza significativamente más tiempo de CPU, y solo puede contar el tiempo desde el inicio de la interrupción, por lo que si la interrupción se ejecuta tarde, el pulso será más largo.
delayMicroseconds(pulse_length);
TCCR1C = _BV(FOC1A); //manually trigger match event
Todo lo que la primera versión está haciendo de manera diferente es desencadenar el evento del partido a través de una "alarma" establecida en el temporizador, en lugar de esperar a que se desencadene manualmente.
¿Por qué no funciona la primera versión y cómo puedo hacer que funcione?