Global Variable Scope Issue

27 Feb 2011

I'm having an issue with the scoping of a global variable. In this demo code I wrote, LED1 flashes at 100ms on then 100ms off and that is handled in the function TimerFunction() with is called with an attach. However, LED is supposed to be flashing at 1000ms on and then 1000ms off but it does not. It flashes at a rate of 0.3us on then 0.3us off. That is micro seconds!

See attached scope plot of the LED2 pin and code below. The scope is setup for 0.2us per division

Maybe someone can try this code on their mbed and see if it does the same thing. Is there something obviously wrong with this code?

The issue seems to be with the global variable TimerValue. I tried defining it as int, unsigned int, long, unsigned long, volatile, extern,etc and not luck.

For what it's worth, I have the same basic program structure running on an LPC2129 and GNU compiler with no issues. In that code I have TimverValue defines as a long volatile and it works.

Any help would be appreciated.

Thanks.

/media/uploads/numerical7/_scaled_p1020288.jpg

#include "mbed.h"

DigitalOut led1(LED1);
DigitalOut led2(LED2);

Ticker SchedulerTimer;

long volatile TimerValue;

void TimerFunction()
{
    led1 = !led1;  //every 100ms
    TimerValue = TimerValue + 1;
}
   
int main()
{
    SchedulerTimer.attach(&TimerFunction,0.1);
    
    while(1)
    {
        if(TimerValue%10 == 0)  //every 1000ms
        {
            led2 = !led2;
        }
    }
}
27 Feb 2011

Here's what I think happens.

  1. TimerValue is initialized to 0 by the compiler (BTW you're lucky here, you should always init your variables explicitly)
  2. Ticker is set up to call TimerFunction every 100ms
  3. For the first 100ms TimerValue is not changed, so led2 starts toggling as fast as the code allows...
  4. after 100ms TimerFunction is called and TimerValue is changed to 1
  5. for the next 900ms led2 stays as is
  6. once TimerValue reaches 10, led2 again starts toggling like mad
  7. and so on...
27 Feb 2011

if(TimerValue%10 == 0)

You get closer to your expected behaviour with

if(int i = TimerValue%10 == 0)

However, it's as Igor says. The equation will evaluate true for quite a vast number of the while(1) iterations. A better way to do this would be to move the == test into the ticker callback and set a flag there every ten counts. Like this:-

#include "mbed.h"

DigitalOut led1(LED1);
DigitalOut led2(LED2);

Ticker SchedulerTimer;

volatile bool oneSecFlag = false;

volatile long TimerValue = 0;

void TimerFunction()
{
    led1 = !led1;  //every 100ms
    TimerValue++; // = TimerValue + 1;
    if (TimerValue == 10) {
        oneSecFlag = true;
        TimerValue = 0;
    }
}
   
int main()
{
    SchedulerTimer.attach(&TimerFunction,0.1);
    
    while(1)
    {
        if(oneSecFlag)  //every 1000ms
        {
            oneSecFlag = false; 
            led2 = !led2;
        }
    }
}

I think this gives you the result you are expecting.

27 Feb 2011

Igor and Andy,

Thanks so much for looking at this. What you you guys are saying makes perfect sense now that I've had some dinner and a break. Sometimes its better to just "STEP AWAY FROM THE CODE" and take a break!

Andy's modifications make it work exactly as I need.

Thanks!

28 Feb 2011

So this is my working code. I implemented it a little bit differently because of the application. I'm basically putting together a little mini "Scheduler" of sorts.

#include "mbed.h"

DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);
DigitalOut led4(LED4);

DigitalOut InTask10ms(p18);
DigitalOut InTask50ms(p19);
DigitalOut InTask100ms(p20);

Ticker SchedulerTimer;

long volatile TimerValue = 1;

void TimerFunction()
{
    led4 = !led4;
    TimerValue = TimerValue + 1;
}
   
int main()
{
    long CurrentTimeVal;
    long LastUsedTimeVal;

    SchedulerTimer.attach(&TimerFunction,0.001);
    
    LastUsedTimeVal = -1;
        
    while(1)
    {
        CurrentTimeVal = TimerValue;
        
        if( CurrentTimeVal != LastUsedTimeVal)
        {
            if( CurrentTimeVal%10 == 0x00)  //10ms task
            {       
                // Insert 10ms tasks here
                led1 = !led1; 
                InTask10ms = !InTask10ms;

                LastUsedTimeVal = CurrentTimeVal;
            }

            if( CurrentTimeVal%50 == 0x00  ) //50ms task
            {
                // Insert 50ms tasks here      
                led2 = !led2;
                InTask50ms = !InTask50ms;

                LastUsedTimeVal = CurrentTimeVal;
            }

            if( CurrentTimeVal%100 == 0x00  ) //100ms task
            {       
                // Insert 100ms tasks here
                led3 = !led3;
                InTask100ms = !InTask100ms;

                LastUsedTimeVal = CurrentTimeVal;
            }
        } // end if
    } // end while(1)
} // end main