-2

Essentially, the aim of the piece of test code is to: *Start a timer (hardware timer) - turn on two LEDs - wait until the timer finishes - turn off both LEDs - delay for 0.9s - start again.

    for (;;) //forever
    {
        PORTB &= ~_BV(PINB7); //Turn OFF GREEN LED

        _delay_ms(900); //RED LED stay off for 0.9s

        timer_two(); // start 5 second timer

        while(!(TIFR1 & _BV(OCF1A))) //WHILE 5 second timer flag is not set
        {
            PORTB |= _BV(PINB7); //Turn on GREEN LED
            PORTA |= _BV(PINA6); //Turn on RED LED
        } //leave while loop when five second timer flag is set

        PORTA &= ~_BV(PINA6); //Turn off RED LED  #THIS DOESN'T HAPPEN#

    }

However, with the code written as it is, both LEDs turn on, but only the Green LED turns off. The Green LED continues to turn on and off as I expected.

Although it clearly exits the while loop (as it turns the Green LED off), it doesn't seem to execute anything after it.

Am I missing a basic trick here?

(Code is compiled for an AVR, atmega644p via avr-gcc, on Windows)

Mike Roberts
  • 11
  • 1
  • 4
  • Did you check if the watchdog is enabled? – ouah Mar 15 '15 at 22:23
  • I've made sure it is turned off - it has made no difference though. – Mike Roberts Mar 15 '15 at 23:08
  • 3
    `while(~(TIFR1 & _BV(OCF1A)))` looks suspicious to me. Should you not write: `while(!(TIFR1 & _BV(OCF1A)))` ? – chqrlie Mar 15 '15 at 23:11
  • 1
    `TIFR1 && _BV(OCF1A)` is almost certainly a bug , this loop will run only if *no* flags are set. – M.M Mar 15 '15 at 23:18
  • @MattMcNabb Yes you're right, it should be a bitwise AND in order to make the `_BV(OCF1A)` bit mask work correctly. However, both `&` and `&&` seem to give the same result here. – Mike Roberts Mar 16 '15 at 00:44
  • @chqrlie `~` is a bitwise NOT and `!` is a logical NOT, in this case would this not give the same result? (as `_BV(OCF1A)` is a bit mask leaving only one bit) – Mike Roberts Mar 16 '15 at 00:45
  • @MikeRoberts `!(00001000)` is `0`, but `~(00001000)` is `11110111` – M.M Mar 16 '15 at 00:56
  • `while(~(TIFR1 & _BV(OCF1A)))` is the same as `while(1)` – M.M Mar 16 '15 at 00:57

4 Answers4

1

Resolved it now.

The LED appeared to flash according to the timer due to the timer creating an Interrupt. The program would then restart, as no interrupt handler was given. This would reset the LED that was set before the timer was started.

Disabling all interrupts allows the code to function correctly.cli(); //disable interrupts

Mike Roberts
  • 11
  • 1
  • 4
0
       for (;;) //forever 
       {
        PORTB &= ~_BV(PINB7); //Turn OFF GREEN LED 
         _delay_ms(900); //RED LED stay off for 0.9s 
         timer_two(); // start 5 second timer and executes all lines till the end

         while(!(TIFR1 & _BV(OCF1A))) //WHILE 5 second timer flag is not set 
         {
           PORTB |= _BV(PINB7); //Turn on GREEN LED
           PORTA |= _BV(PINA6); //Turn on RED LED
          } //leave while loop when five second timer flag is set
           _delay_ms(4000); // delays the while
//OR while will be executed for 4sec
          PORTA &= ~_BV(PINA6); //Turn off RED LED for 1sec
       }
user388229
  • 109
  • 5
  • The timer gives a hardware to run for 5sec. But the execution in the m/c will be like queue.. – user388229 Mar 16 '15 at 01:47
  • When the queue ends and time is still remaining, it will execute the last line for rest of the time – user388229 Mar 16 '15 at 01:48
  • If you are unable to get what I'm explaining then your should implement it, and try to increase and decrease delays.. You'll definitely get what you wanted.. – user388229 Mar 16 '15 at 01:53
  • I tried implementing it, and absolutely nothing changed at all. I've now worked it out, essentially the timer was generating an interrupt. As I didn't create an interrupt handler, the program restarted every time when it couldn't find it (hence it doing nothing with your extra delay either). – Mike Roberts Mar 16 '15 at 02:07
  • :-) Well, I was not having any idea about the timer function. I'm better in C language only. So, I explained that. :-D If you would have executed program without timer then my explanation would have been Appropriete.. :-D – user388229 Mar 16 '15 at 04:34
0

If You Didn't got anything what I Said then coming to the Execution..

Your while is being executed only once..

Or you can say that You don't have a while loop running..

Your runnung code is:

for (;;)
{ 
  PORTB &= ~_BV(PINB7);
  _delay_ms(900);
  timer_two();

  PORTB |= _BV(PINB7); 
  PORTA |= _BV(PINA6);
  PORTA &= ~_BV(PINA6);
}
user388229
  • 109
  • 5
  • This is the last thing what I can explain.. Be Practical, the timer only allotted 5sec time but there was no compulsion that while will be executed for 5sec.. Its only that the last code will be executed for 5sec.. – user388229 Mar 16 '15 at 02:08
  • Well, I gave you the simplest way to understand.. You're taking it in a very hard way.. Simply put your last line after the _delay_ms(900); – user388229 Mar 16 '15 at 02:11
-1

Your RED would be always OFF at the execution..?

You set hardware timer to execute

  • While
  • RED OFF

Now, it executes the while at it's crystal speed (i.e., must be in less than 5ms) and executes the last line for rest of the 4995ms..

Got the Execution..?

user388229
  • 109
  • 5
  • The program execution should go: `PORTA &= ~_BV(PINA6); //Turn off RED LED` Then back to the beginning of the for(;;) loop where there is a `_delay_ms(900);` before the red LED is turned back on again. – Mike Roberts Mar 16 '15 at 01:01
  • Now, In this case, you have to give a delay of 4000ms just after the whlie loop to observe the RED as ON.. – user388229 Mar 16 '15 at 01:18
  • The `timer_two()` function starts a timer that lasts 5s. This is a hardware timer, that runs concurrently in the background, so the while loop executes while this timer is running. It only leaves the while loop when the timer finishes, and sets the OCF1A flag. – Mike Roberts Mar 16 '15 at 01:25
  • The `timer_two()` function also resets this flag. – Mike Roberts Mar 16 '15 at 01:25
  • And there is while and RED off.. Both have to be executed in 5sec only.. Its not that the m/c will understand what to execute for 5sec.. So, you will need a delay just after while – user388229 Mar 16 '15 at 01:29
  • If you're not getting it, run the following program.. I made minor changes in yours.. – user388229 Mar 16 '15 at 01:32
  • for (;;) //forever { PORTB &= ~_BV(PINB7); //Turn OFF GREEN LED _delay_ms(900); //RED LED stay off for 0.9s timer_two(); // start 5 second timer and executes all lines till the end while(!(TIFR1 & _BV(OCF1A))) //WHILE 5 second timer flag is not set { PORTB |= _BV(PINB7); //Turn on GREEN LED PORTA |= _BV(PINA6); //Turn on RED LED } //leave while loop when five second timer flag is set _delay_ms(4000); // delays the while //OR while will be executed for 4sec PORTA &= ~_BV(PINA – user388229 Mar 16 '15 at 01:43
  • Nope, it actually makes no difference whatsoever.. it doesn't even leave an extra 4s delay, which I don't understand – Mike Roberts Mar 16 '15 at 01:48