avr-gcc-list
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [avr-gcc-list] Problem with delay loop


From: David Kelly
Subject: Re: [avr-gcc-list] Problem with delay loop
Date: Fri, 28 Sep 2007 09:05:40 -0500
User-agent: Mutt/1.4.2.3i

On Fri, Sep 28, 2007 at 01:29:19PM +0530, Royce Pereira wrote:
> Hi all,
> 
> In the latest WinAVR (avr-gcc (GCC) 4.1.2 (WinAVR 20070525) I found this.
> 
> Check this out:
> //======================
> void delay(unsigned del_cnt)
>     {
>        while(del_cnt--);
> 
>        return;
>     }
> //=======================

I agree with what others have said, no matter the old compiler did what
you intended with the above code, the code is less that fully correct.
Is legal for the compiler to burn cycles in the loop, is legal for the
compiler to recognize a do-nothing loop and remove it. You are not the
first to discover this that is why the volatile modifier exists.

Why are you not using hardware timers? First thing I do on a new project
is set up a hardware timer to tick away at 60 or 100 Hz or something
close. Then in the interrupt routine I commonly create "software timers"
something like this:

        if( timer_serial_cmd )
                timer_serial_cmd--;

Elsewhere in my code I might start receiving a serial command string
where no two characters should arrive more than 100 ms apart. At 60 Hz
that would be 6 ticks, 10 at 100 Hz. So I put 6 or 10 in
timer_serial_cmd and if ever I find timer_serial_cmd to be zero I know
too much time has passed.

Notice timer_serial_cmd needs to be volatile but you might get away
without. I use uint8_t more than anything else as my variable type. If
your timer_serial_cmd is 16 bits then if it is not zero interrupts need
to be locked out while it is initialized. Or a quick and dirty way is to
write the value twice knowing the 60 Hz interrupt isn't going to fire
twice in 2 lines of code:

        volatile uint16_t timer_serial_cmd;

        timer_serial_cmd = 1000;
        timer_serial_cmd = 1000;

or
        cli();
        timer_serial_cmd = 1000;
        sei();

For finer delays don't forget the OCR functions on the timers. Is pretty
easy to write and create very accurate delays with:

void delay( uint8_t delay );
{
        OCR2A = TCNT2 + delay;
        TIFR2 = (1<<OCF2A);             //  clear possible pending

        //  wait until TCNT2 matches OCR2A
        while( ( TIFR2 && (1<<OCF2A) ) == 0 )
                ;
}

If you are not already using timers then you need to set a clock source
to start the timer running. See TCCR2B for the above.

With small variations all of the above works for timers 0, 1, and 2.

-- 
David Kelly N4HHE, address@hidden
========================================================================
Whom computers would destroy, they must first drive mad.




reply via email to

[Prev in Thread] Current Thread [Next in Thread]