AVR: Using ATmega328 Timer1 to create a delay [duplicate]

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):

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

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?

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

• You turn OFF the led after one second but then widout any "delay" you turn ON the led again. – G36 Mar 26 '17 at 10:07
• Check this: 12 hours delay with ATmega16A. – Bence Kaulics Mar 26 '17 at 10:26
• 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 :) – Michael Nissen Mar 26 '17 at 11:31
• 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; – Andy Mar 26 '17 at 11:32
• 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! – Michael Nissen Mar 26 '17 at 11:34

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:

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.

• 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? :) – Michael Nissen Mar 26 '17 at 19:39