搜索
bottom↓
回复: 22

winavr中使用_delay_ms(float x)函数的小疑问

[复制链接]

出0入0汤圆

发表于 2009-5-13 17:33:03 | 显示全部楼层 |阅读模式
在winavr的AVR/INCLUDE/UTIL/中有一个现成的delay.h文件用它可以在程序中方便地实现延时函数:_delay_ms(float x)和_delay_us(float x)可是在编程时包含了这个文件,实际上运行起来会发现延时误差可能很大,按说x取1000也是可以的,实际上运行结果明显小很多,程序中已经正确设置了cpu频率。winavr是20070525版。

阿莫论坛20周年了!感谢大家的支持与爱护!!

曾经有一段真挚的爱情摆在我的面前,我没有珍惜,现在想起来,还好我没有珍惜……

出0入0汤圆

发表于 2009-5-13 17:49:38 | 显示全部楼层
楼主看来没理解GCC _delay_ms用法。

出0入0汤圆

发表于 2009-5-13 17:52:03 | 显示全部楼层
-_-
F_CPU又不是不能直接改...
何苦复制文件...

出0入0汤圆

发表于 2009-5-13 17:53:30 | 显示全部楼层
多此一举,根本不用去改什么。认真看看吧,多试试也可以。

出0入0汤圆

发表于 2009-5-13 18:04:11 | 显示全部楼层
我用ICC,只是从LZ提到的随便说说,WINAVR没用过...

出0入0汤圆

发表于 2009-5-13 18:09:25 | 显示全部楼层
/** \file */
/** \defgroup util_delay <util/delay.h>: Convenience functions for busy-wait delay loops
    \code
    #define F_CPU 1000000UL  // 1 MHz
    //#define F_CPU 14.7456E6
    #include <util/delay.h>
    \endcode


    \note As an alternative method, it is possible to pass the
    F_CPU macro down to the compiler from the Makefile.
    Obviously, in that case, no \c \#define statement should be
    used.


    The functions in this header file are wrappers around the basic
    busy-wait functions from <util/delay_basic.h>.  They are meant as
    convenience functions where actual time values can be specified
    rather than a number of cycles to wait for.  The idea behind is
    that compile-time constant expressions will be eliminated by
    compiler optimization so floating-point expressions can be used
    to calculate the number of delay cycles needed based on the CPU
    frequency passed by the macro F_CPU.

    \note In order for these functions to work as intended, compiler
    optimizations <em>must</em> be enabled, and the delay time
    <em>must</em> be an expression that is a known constant at
    compile-time.  If these requirements are not met, the resulting
    delay will be much longer (and basically unpredictable), and
    applications that otherwise do not use floating-point calculations
    will experience severe code bloat by the floating-point library
    routines linked into the application.

    The functions available allow the specification of microsecond, and
    millisecond delays directly, using the application-supplied macro
    F_CPU as the CPU clock frequency (in Hertz).

*/

它的意思是说,在包含头文件的语句前加上F_CPU的定义或直接在Makefile中定义
_delay_ms(double __ms)
居然用到了浮点运算...

出0入0汤圆

发表于 2009-5-13 18:15:56 | 显示全部楼层
看delay.h中的内容:
#ifndef F_CPU
/* prevent compiler error by supplying a default */
# warning "F_CPU not defined for <util/delay.h>"
# define F_CPU 1000000UL
#endif


也就是说,如果你没有定义F_CPU 那么他就默认定义为1000000UL并给出提示!

所以你可以在程序中:
#define F_CPU  8000000UL
#include <util/delay.h>
_delay_ms(5);
..................


不过我们一般不这么做..因同一个项目的F_CPU都是一样的.而且可能这个程序以后用在别的项目中会有变化
于是我们一般直接在Makefile中就定义了
编译的时候会使用命令行:avr-gcc *** -DF_CPU=8000000UL -c main.c ***
这样就相当于你的程序(main.c)已经定义了:
#define F_CPU  8000000UL

关于楼上说的"居然用到了浮点运算..."请自行查阅本坛相关贴子

出0入0汤圆

发表于 2009-5-13 18:25:30 | 显示全部楼层
居然用到了浮点运算...
——————————————————————
好像“浮点”是洪水猛兽。


IAR,GCC “浮点”延时一个简单测试:

WinAVR 20090313,OS优化,8m时钟:


#define F_CPU 8000000UL
#include <util/delay.h>

    int main(void)
    {
      
          asm volatile("nop");
          _delay_ms(1.2345);   //9877个周期,误差一个周期(1.2345ms准确延时是9876个周期)
          asm volatile("nop");
          
            while(1);
    }


IAR EWAVR 5.20 High speed优化,8m时钟:
#define F_CPU 8000000UL
#include <intrinsics.h>
#define _delay_ms(A)\
  __delay_cycles( (unsigned long) ( (double)(F_CPU)*((A)/1000.0) + 0.5))


    int main(void)
    {
      
           asm("nop");
           _delay_ms(1.2345); //9876个周期,误差0
           asm("nop");
          
          while(1);
    }


————————————————————————————————
【8楼】 cpcgdut

要占用多少程序空间和数据空间先不说,红色部分恐怕已经1ms了吧。
——————————————————————————————

看楼下回复,只能说楼下太小看GCC了。



WinAVR 20090313,OS优化,8m时钟:

#define F_CPU 8000000UL
#include <util/delay.h>

    int main(void)
    {
      
          asm volatile("nop");
          _delay_ms(0.001);   //9个周期,误差一个周期(0.001ms准确延时是8个周期)
          asm volatile("nop");
          
            while(1);
    }


IAR EWAVR 5.20 High speed优化,8m时钟:
#define F_CPU 8000000UL
#include <intrinsics.h>
#define _delay_ms(A)\
  __delay_cycles( (unsigned long) ( (double)(F_CPU)*((A)/1000.0) + 0.5))


    int main(void)
    {
      
           asm("nop");
           _delay_ms(0.001); //8个周期,误差0
           asm("nop");
          
          while(1);
    }

出0入0汤圆

发表于 2009-5-13 18:32:20 | 显示全部楼层
楼上,看看头文件的代码能不能实现1us的延时:

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);
}

要占用多少程序空间和数据空间先不说,红色部分恐怕已经1ms了吧。

出0入0汤圆

发表于 2009-5-13 18:33:46 | 显示全部楼层
保护压栈+参数传递+函数调用
早就超过1us了...

出0入0汤圆

发表于 2009-5-13 18:55:19 | 显示全部楼层
于是我们一般直接在Makefile中就定义了
编译的时候会使用命令行:avr-gcc *** -DF_CPU=8000000UL -c main.c ***
这样就相当于你的程序(main.c)已经定义了:
#define F_CPU  8000000UL  
——————————————————————————————————————————————
使用AVRStudio + WinGCC时,不用自己写makefile,只需要如下图中设置就可以了么?

(原文件名:QQ截图未命名7.png)

出0入0汤圆

发表于 2009-5-13 19:46:02 | 显示全部楼层
8楼和9楼显然不知道为什么delay的头文件要求开启优化的原因,建议开启优化后,读一下gcc生成的汇编代码。

出0入0汤圆

 楼主| 发表于 2009-5-13 19:55:24 | 显示全部楼层
以上各位大虾都有道理,小可受教了,现在的问题是,如楼上所示,已经在项目设置中指定了频率,例如400000,就用的原始文件include/util/delay.h  程序中_delay_ms(1000);实际运行起来明显比1秒短很多,改了delay.h就正常了,因为以前一直用出厂默认设置1000000,所以没有问题,建议大家先实际试一下看看?

出0入0汤圆

发表于 2009-5-13 20:31:38 | 显示全部楼层
【11楼】 yyccaa

呵呵,没往下看,还要求参数必须是常量的,优化后外面那层全没了:
000001ae <DelayMS>:
1ae:        00 97               sbiw        r24, 0x00        ; 0
1b0:        39 f0               breq        .+14             ; 0x1c0 <DelayMS+0x12>
1b2:        3f ef               ldi        r19, 0xFF        ; 255
1b4:        23 2f               mov        r18, r19
1b6:        00 00               nop
1b8:        21 50               subi        r18, 0x01        ; 1
1ba:        e9 f7               brne        .-6              ; 0x1b6 <DelayMS+0x8>
1bc:        01 97               sbiw        r24, 0x01        ; 1
1be:        d1 f7               brne        .-12             ; 0x1b4 <DelayMS+0x6>
1c0:        08 95               ret

000001c2 <DelayUS>:
1c2:        88 23               and        r24, r24
1c4:        19 f0               breq        .+6              ; 0x1cc <DelayUS+0xa>
1c6:        00 00               nop
1c8:        81 50               subi        r24, 0x01        ; 1
1ca:        e9 f7               brne        .-6              ; 0x1c6 <DelayUS+0x4>
1cc:        08 95               ret

000001ce <main>:
DelayMS(500);
1ce:        84 ef               ldi        r24, 0xF4        ; 244
1d0:        91 e0               ldi        r25, 0x01        ; 1
1d2:        0e 94 d7 00         call        0x1ae        ; 0x1ae <DelayMS>
_delay_ms(1);
1d6:        80 ed               ldi        r24, 0xD0        ; 208
1d8:        97 e0               ldi        r25, 0x07        ; 7
1da:        01 97               sbiw        r24, 0x01        ; 1
1dc:        f1 f7               brne        .-4              ; 0x1da <main+0xc>

出0入0汤圆

发表于 2009-5-13 20:38:44 | 显示全部楼层
【12楼】 AAVVRR
程序中_delay_ms(1000);实际运行起来明显比1秒短很多,
______________________________________________________________

旧版WinAVR,_delay_ms()最大延时是 262.14ms/(F_CPU/1000000),
_delay_ms(1000)超出延时范围。

新版WinAVR,_delay_ms()有最大延时是 6553.5ms,误差在1%以内。

出0入0汤圆

 楼主| 发表于 2009-5-14 10:16:45 | 显示全部楼层
上官先生正解!昨天去掉了20070525改装20090313最新版,又发现新的问题:用老板编一个bootload文件很正常,换新版后,提示在形成elf文件过程中程序范围超出,没办法只有换回原来的,看来延时延长不了那么多,(老板并无说明)

出0入0汤圆

发表于 2010-4-7 23:20:20 | 显示全部楼层
那不禁想到,要是在AVRStudio在直接设置晶振频率,同时也在程序中加入#define F_CPU  8000000UL  
如果二者的频率了一样,那编译时会默认选择哪个?

出0入0汤圆

发表于 2010-4-13 23:27:03 | 显示全部楼层
回复【16楼】sophy.lin  
那不禁想到,要是在AVRStudio在直接设置晶振频率,同时也在程序中加入#define F_CPU  8000000UL  
如果二者的频率了一样,那编译时会默认选择哪个?
-----------------------------------------------------------------------
#define F_CPU  8000000UL
......
#define F_CPU  4000000UL
......
F_CPU == ?

出0入0汤圆

发表于 2010-4-14 00:22:38 | 显示全部楼层
楼上的,麻烦解释清楚下,
就算是重复定义F_CPU,
那是不是以最近的一个为准
若是以最近的一个为准,那怎么知道到底是菜单中设置的还是代码中定义的哪个最近?

出0入0汤圆

发表于 2010-4-14 09:09:37 | 显示全部楼层
回复【18楼】sophy.lin  
楼上的,麻烦解释清楚下,
就算是重复定义F_CPU,
那是不是以最近的一个为准
若是以最近的一个为准,那怎么知道到底是菜单中设置的还是代码中定义的哪个最近?
-----------------------------------------------------------------------

大哥,delay.h里面那个定义是需要你没有定义F_CPU才会定义的呢
#ifndef
#define
宏早就防止你这种情况出现了

出0入0汤圆

发表于 2010-4-14 10:23:13 | 显示全部楼层
mark。我用延迟都是在不重要的场合,要准的话用定时器,要短的话加空指令自己数数

出0入0汤圆

发表于 2010-11-11 15:31:57 | 显示全部楼层
先MARK了
平时我比较少用AVR的,学习一下~~

出0入0汤圆

发表于 2013-8-8 22:13:07 | 显示全部楼层
先Mark了,这论坛的好东西真多.学习学习
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-8-26 20:49

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表