打印
[AVR单片机]

WinAVR延时函数理解[转]

[复制链接]
3180|6
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
huamunv|  楼主 | 2010-2-20 10:04 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
WinAVR20081205 延时函数 :

void
_delay_loop_1(uint8_t __count)
{
        __asm__ volatile (
                "1: dec %0" "\n\t"
                "brne 1b"
                : "=r" (__count)
                : "0" (__count)
        );
}

准确延时是3*__count个时钟周期         (0<__count<256)

void
_delay_loop_2(uint16_t __count)
{
        __asm__ volatile (
                "1: sbiw %0,1" "\n\t"
                "brne 1b"
                : "=w" (__count)
                : "0" (__count)
        );
}

准确延时是4*__count+1个时钟周期        (0<__count<256*256-1)


_delay_loop_1() 最小延时是3个时钟周期,最大延时是256*3个时钟周期

_delay_loop_2() 最小延时是4+1个时钟周期,最大延时是256*256*4+1个时钟周期


void
_delay_us(double __us)
{
        uint8_t __ticks;
        double __tmp = ((F_CPU) / 3e6) * __us;
        if (__tmp < 1.0)
                __ticks = 1;
        else if (__tmp > 255)
        {
                _delay_ms(__us / 1000.0);
                return;
        }
        else
                __ticks = (uint8_t)__tmp;
        _delay_loop_1(__ticks);
}

void
_delay_ms(double __ms)
{
        uint16_t __ticks;
        double __tmp = ((F_CPU) / 4e3) * __ms;
        if (__tmp < 1.0)
                __ticks = 1;
        else if (__tmp > 65535)
        {
                //        __ticks = requested delay in 1/10 ms
                __ticks = (uint16_t) (__ms * 10.0);
                while(__ticks)
                {
                        // wait 1/10 ms
                        _delay_loop_2(((F_CPU) / 4e3) / 10);
                        __ticks --;
                }
                return;
        }
        else
                __ticks = (uint16_t)__tmp;
        _delay_loop_2(__ticks);
}

_dealy_us()最小延时 与 _delay_loop_1()相同,是3个时钟周期,
_delay_us(0)就是最小延时,相当于_delay_loop_1(1),
在8M时钟下,_delay_us(0.375)也是最小延时(0.375us是3个时钟周期)
_delay_us(0.7499999)仍然是最小延时,相当于_delay_loop_1(1),
而_delay_us(0.74999999)则相当于_delay_loop_1(2)了。


_dealy_ms() 最小延时与 _delay_loop_2()相同,是4+1个时钟周期。
_delay_ms(0)就是最小延时,相当于_delay_loop_2(1),
在8M时钟下,_delay_ms(0.0005)也是最小延时(0.0005ms相当于是4个时钟周期)
_delay_ms(0.0009999999)仍然是最小延时,相当于_delay_loop_2(1),
而_delay_ms(0.00099999999)则相当于_delay_loop_2(2)了。


_dealy_us(__us)延时精度范围:
(0 , 3个时钟周期),误差(0,3)个时钟周期
(3个时钟周期 , 768us/(F_CPU/1000000)),误差(-2,0)个时钟周期
(768us/(F_CPU/1000000) , 262.14ms/(F_CPU/1000000)),误差(-2,+1)个时钟周期,
(262.14ms/(F_CPU/1000000)) , 6553.5ms),误差8M时钟下(约+0.18ms,约+57ms)


_dealy_ms(__ms)延时精度范围:
(0 , 4个时钟周期),误差(1,5)个时钟周期
(4个时钟周期 , 262.14ms/(F_CPU/1000000)),误差(-2,+1)个时钟周期,
(262.14ms/(F_CPU/1000000)) , 6553.5ms),误差8M时钟下(约+0.18ms,约+57ms)


_dealy_us(__us)最大延时6553.5ms,即_delay_us(6553500);
_delay_ms(__ms)最大延时6553.5ms,即_delay_ms(6553.5);


本人水平有限,如果错漏之处,多谢指正。

补充:
1.WinAVR延时库函数看起来,又是double,又是if、else,难道不耗时间?
不耗时间。WinAVR延时库函数,double都可以优化成常量,而整型常量,浮点常量运算,结果仍然仍然是常量。
编译器只要开优化,不会编译出额外的代码出来。if,else也一样。if判断条件是一个常量,也就是说某个分支一定为真,
另外的分支一定为假,编译器优化时,不会编译出额外代码。需要注意,如果要调用WinAVR延时库函数,则必须要开优化。

2.怎么没有计算函数调用,返回时间?
WinAVR延时库函数全部都是内联函数,没有函数调用和返回开销。当然,这也有一个副作用,每处延时函数都会编译出一段代码,
占据更多的代码空间。

3.旧版WinAVR  _delay_us()最大延时768us/(F_CPU/1000000),delay_ms()最大延时是262.14ms/(F_CPU/1000000)。
新版WinAVR_delay_us()和_delay_ms()最大延时都是6553.5ms,不过误差也相对较大,每0.1ms多7个时钟周期,8M时钟下,误差约为+0.88%。


----------------------------------
附IARAVR延时函数:

#ifndef __IAR_DELAY_H__
#define __IAR_DELAY_H__

#include <intrinsics.h>
#include "hal_type.h"

#define _delay_loop_1(A) __delay_cycles(3*(A))
#define _delay_loop_2(A) __delay_cycles(4*(A)+1)

#define _delay_us(A)\
  __delay_cycles( (uint32) ( (double)(F_CPU) *((A)/1000000.0) + 0.5))

#define _delay_ms(A)\
  __delay_cycles( (uint32) ( (double)(F_CPU)*((A)/1000.0) + 0.5))

#define _delay_s(A)\
  __delay_cycles( (uint32) ( (double)(F_CPU)*((A)/1.0) + 0.5))

#endif

相关帖子

沙发
Karlshen| | 2010-2-20 21:53 | 只看该作者
赞一个

使用特权

评论回复
板凳
laslison| | 2010-2-21 16:19 | 只看该作者
进来学习

使用特权

评论回复
地板
xiaoxin1986| | 2010-2-21 19:00 | 只看该作者
解释的还可以

使用特权

评论回复
5
love_life| | 2010-2-21 19:10 | 只看该作者
嘿嘿,普通的延时函数也能说这么多

使用特权

评论回复
6
lovelyegle| | 2010-2-22 19:43 | 只看该作者
牛,研究得很深入

使用特权

评论回复
7
wangwo| | 2010-2-23 12:40 | 只看该作者
:kiss:顶了

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

88

主题

730

帖子

1

粉丝