2
\$\begingroup\$

This question already has an answer here:

I am having some trouble wrapping my head around this, and it might just be some small error somewhere, that I keep missing .. but as it stands, I am trying to create a hardware "delay" that can run at the same time some code executes.

For practise purposes, I am simply trying to blink an LED at PD4 at an interval of 1 second.

I have used the following formula to determine the prescaler, and the value of the Output Compare Register A (OCR1A):

Formula for calculation

Using a prescaler of 256, I get a value for OCR1A of 62499:

Result of calculation

Looking at the registers TCCR1A and TCCR1B in the datasheet, I set the Waveform Generation Mode bits (WGM) to use CTC and the Clock Select bits to use the 256 prescaler.

Now, in my main function, I am starting of by turning on the LED, then calling my function that should start the timer. I am then checking to see if the overflow flag has been set in TIFR1, and if it has, I am turning of the LED and writing a logic 1 to TOV1 to reset the overflow flag.

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;
}

In my function I start off by setting OCR1A to the value that I calculated earlier. I then set the bits in the TCCR1B register that needs to be set for using the specific prescaler and CTC mode, and I then create a loop while waiting for the overflow event to happen; which I envision should take one second.

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: Now the problem is that no matter what I can dream up, the LED is just constantly turned on, and I am not sure if I am setting the the wrong values in the registers, or if I am just having some brain farts?

\$\endgroup\$

marked as duplicate by Bence Kaulics, ThreePhaseEel, Community Mar 27 '17 at 19:49

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • 2
    \$\begingroup\$ You turn OFF the led after one second but then widout any "delay" you turn ON the led again. \$\endgroup\$ – G36 Mar 26 '17 at 10:07
  • \$\begingroup\$ Check this: 12 hours delay with ATmega16A. \$\endgroup\$ – Bence Kaulics Mar 26 '17 at 10:26
  • 1
    \$\begingroup\$ Thank you so much @BenceKaulics ! Using the interrupt what something that I hadn't found, so this was a huge help and I finally thing that I understand it :) \$\endgroup\$ – Michael Nissen Mar 26 '17 at 11:31
  • \$\begingroup\$ G36 already gave a hint and I suggest you use an ISR for timer1 (ISR(TIMER1_COMPA_vect)) where you toggle your LED with PORTD ^= 1 << PD4; \$\endgroup\$ – Andy Mar 26 '17 at 11:32
  • 1
    \$\begingroup\$ I tried doing what G36 talked about, but that didn't do it for me, however using the ISR did the trick.. I simply didn't know about the ISR before @BenceKaulics mentioned it ! :) But thank you for the answer! \$\endgroup\$ – Michael Nissen Mar 26 '17 at 11:34
0
\$\begingroup\$
void oneSecondDelay() {

that function's construct isn't terribly optimal. you could have easily made it take a parameter to determine the length of the delay, not to mention other issues.

A quick fix would be something like this - it still has issues but at least workable.

//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

}

that piece of code in action when fed TMR1_PS100ms as a parameter:

enter image description here

the goal of writing any piece of code is so that you don't have to write it again. That way, anything you write is an investment, not an expense.

\$\endgroup\$
  • \$\begingroup\$ Thanks for the answer! I know that I should use a parameter to specify the length of the duration, but I was just trying to wrap my head around how the whole AVR thing works, so trying to keep it at bare minimum. I managed to solve by using interrupts in the end :) Also, was wondering how you made that nice looking digital analysis at the end? :) \$\endgroup\$ – Michael Nissen Mar 26 '17 at 19:39

Not the answer you're looking for? Browse other questions tagged or ask your own question.