AVR: uso de ATmega328 Timer1 para crear un retraso [duplicado]

Tengo algunos problemas para entender esto, y podría ser un pequeño error en alguna parte, que sigo omitiendo... pero tal como está, estoy tratando de crear un "retraso" de hardware que pueda ejecutarse al mismo tiempo. se ejecuta el código.

Para fines de práctica, simplemente estoy tratando de hacer parpadear un LED en PD4 en un intervalo de 1 segundo.

He usado la siguiente fórmula para determinar el preescalador y el valor del Registro de comparación de salida A (OCR1A):

Fórmula para el cálculo

Usando un prescaler de 256, obtengo un valor para OCR1A de 62499:

resultado del calculo

Mirando los registros TCCR1A y ​​TCCR1B en la hoja de datos, configuré los bits del modo de generación de forma de onda (WGM) para usar CTC y los bits de selección de reloj para usar el preescalador 256.

Ahora, en mi función principal, comienzo encendiendo el LED y luego llamo a mi función que debe iniciar el temporizador. Luego verifico si el indicador de desbordamiento se ha configurado en TIFR1 y, si es así, apago el LED y escribo un 1 lógico en TOV1 para restablecer el indicador de desbordamiento.

int main(void) {
   DDRD = 0xFF;
   PORTD = 0x00;

   while (1) {

      // Turn on LED at PD4
      PORTD |= (1 << PD4);

      oneSecondDelay();

      // Checking to see if the overflow flag has been set
      if (TOV1 == 1) {

         // Turn off LED at PD4
         PORTD &= ~(1 << PD4);

         // Set 1 in the Output Compare A Flag to reset the overflow flag
         TIFR1 = (1 << TOV1);
      }
   }

   return 0;
}

En mi función, empiezo configurando OCR1A en el valor que calculé anteriormente. Luego configuro los bits en el registro TCCR1B que deben configurarse para usar el preescalador específico y el modo CTC, y luego creo un bucle mientras espero que ocurra el evento de desbordamiento; que imagino debería tomar un segundo.

void oneSecondDelay() {
   // Set the target value to 62499
   OCR1A = 0xF423;

   // Set prescaler to 256 and start the timer
   TCCR1B |= (1 << WGM12) | (1 << CS12);

   // Waiting for the overflow event
   while ((TIFR1 & (1 <<  OCF1A))) {

   }
}

TLDR: Ahora, el problema es que no importa lo que pueda soñar, el LED está constantemente encendido, y no estoy seguro de si estoy configurando los valores incorrectos en los registros, o si solo estoy teniendo algunos pedos cerebrales.

Apagas el led después de un segundo pero luego, sin ningún "retraso", vuelves a encender el led.
¡Muchas gracias @BenceKaulics! Usar la interrupción es algo que no había encontrado, así que esto fue de gran ayuda y finalmente creo que lo entiendo :)
G36 ya dio una pista y le sugiero que use un ISR para el temporizador 1 (ISR (TIMER1_COMPA_vect)) donde alterna su LED conPORTD ^= 1 << PD4;
Intenté hacer lo que dijo G36, pero eso no funcionó para mí, sin embargo, usar el ISR funcionó. ¡Simplemente no sabía sobre el ISR antes de que @BenceKaulics lo mencionara! :) Pero gracias por la respuesta!

Respuestas (1)

void oneSecondDelay() {

la construcción de esa función no es terriblemente óptima. fácilmente podría haber hecho que tomara un parámetro para determinar la duración del retraso, sin mencionar otros problemas.

Una solución rápida sería algo como esto: todavía tiene problemas, pero al menos funciona.

//create a user-specified delay
//dly-duration in timer ticks
//timer1 presummed running, running at 256:1 prescaler
void myDelay(uint16_t dly) {
   // Set the target value to 62499
   OCR1A = TCNT1 + dly - 1;     //0xF423;

   // Set prescaler to 256 and start the timer
   //TCCR1B |= (1 << WGM12) | (1 << CS12);
   TCCR1B = (TCCR1B &~0x07) | (TMR1_PS256x & 0x07); //set timer1 prescaler to 256:1

   // Waiting for the overflow event
   while ((TIFR1 & (1 <<  OCF1A)) == 0) {

   }

   TIFR1 |= (1<<OCF1A);         //clear the flag

}

ese fragmento de código en acción cuando se alimenta TMR1_PS100ms como parámetro:

ingrese la descripción de la imagen aquí

el objetivo de escribir cualquier pieza de código es que no tengas que volver a escribirlo. De esa manera, cualquier cosa que escribas es una inversión, no un gasto.

¡Gracias por la respuesta! Sé que debería usar un parámetro para especificar la duración de la duración, pero solo estaba tratando de entender cómo funciona todo el AVR, así que trato de mantenerlo al mínimo. Me las arreglé para resolver usando interrupciones al final :) Además, me preguntaba cómo hiciste ese análisis digital tan bonito al final. :)