winavr中使用_delay_ms(float x)函数的小疑问
在winavr的AVR/INCLUDE/UTIL/中有一个现成的delay.h文件用它可以在程序中方便地实现延时函数:_delay_ms(float x)和_delay_us(float x)可是在编程时包含了这个文件,实际上运行起来会发现延时误差可能很大,按说x取1000也是可以的,实际上运行结果明显小很多,程序中已经正确设置了cpu频率。winavr是20070525版。 楼主看来没理解GCC _delay_ms用法。 -_-F_CPU又不是不能直接改...
何苦复制文件... 多此一举,根本不用去改什么。认真看看吧,多试试也可以。 我用ICC,只是从LZ提到的随便说说,WINAVR没用过... /** \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)
居然用到了浮点运算... 看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_CPU8000000UL
#include <util/delay.h>
_delay_ms(5);
..................
不过我们一般不这么做..因同一个项目的F_CPU都是一样的.而且可能这个程序以后用在别的项目中会有变化
于是我们一般直接在Makefile中就定义了
编译的时候会使用命令行:avr-gcc *** -DF_CPU=8000000UL -c main.c ***
这样就相当于你的程序(main.c)已经定义了:
#define F_CPU8000000UL
关于楼上说的"居然用到了浮点运算..."请自行查阅本坛相关贴子 居然用到了浮点运算...
——————————————————————
好像“浮点”是洪水猛兽。
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);
} 楼上,看看头文件的代码能不能实现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了吧。 保护压栈+参数传递+函数调用
早就超过1us了... 于是我们一般直接在Makefile中就定义了
编译的时候会使用命令行:avr-gcc *** -DF_CPU=8000000UL -c main.c ***
这样就相当于你的程序(main.c)已经定义了:
#define F_CPU8000000UL
——————————————————————————————————————————————
使用AVRStudio + WinGCC时,不用自己写makefile,只需要如下图中设置就可以了么?
http://cache.amobbs.com/bbs_upload782111/files_15/ourdev_444627.png
(原文件名:QQ截图未命名7.png) 8楼和9楼显然不知道为什么delay的头文件要求开启优化的原因,建议开启优化后,读一下gcc生成的汇编代码。 以上各位大虾都有道理,小可受教了,现在的问题是,如楼上所示,已经在项目设置中指定了频率,例如400000,就用的原始文件include/util/delay.h程序中_delay_ms(1000);实际运行起来明显比1秒短很多,改了delay.h就正常了,因为以前一直用出厂默认设置1000000,所以没有问题,建议大家先实际试一下看看? 【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> 【12楼】 AAVVRR
程序中_delay_ms(1000);实际运行起来明显比1秒短很多,
______________________________________________________________
旧版WinAVR,_delay_ms()最大延时是 262.14ms/(F_CPU/1000000),
_delay_ms(1000)超出延时范围。
新版WinAVR,_delay_ms()有最大延时是 6553.5ms,误差在1%以内。 上官先生正解!昨天去掉了20070525改装20090313最新版,又发现新的问题:用老板编一个bootload文件很正常,换新版后,提示在形成elf文件过程中程序范围超出,没办法只有换回原来的,看来延时延长不了那么多,(老板并无说明) 那不禁想到,要是在AVRStudio在直接设置晶振频率,同时也在程序中加入#define F_CPU8000000UL
如果二者的频率了一样,那编译时会默认选择哪个? 回复【16楼】sophy.lin
那不禁想到,要是在AVRStudio在直接设置晶振频率,同时也在程序中加入#define F_CPU8000000UL
如果二者的频率了一样,那编译时会默认选择哪个?
-----------------------------------------------------------------------
#define F_CPU8000000UL
......
#define F_CPU4000000UL
......
F_CPU == ? 楼上的,麻烦解释清楚下,
就算是重复定义F_CPU,
那是不是以最近的一个为准
若是以最近的一个为准,那怎么知道到底是菜单中设置的还是代码中定义的哪个最近? 回复【18楼】sophy.lin
楼上的,麻烦解释清楚下,
就算是重复定义F_CPU,
那是不是以最近的一个为准
若是以最近的一个为准,那怎么知道到底是菜单中设置的还是代码中定义的哪个最近?
-----------------------------------------------------------------------
大哥,delay.h里面那个定义是需要你没有定义F_CPU才会定义的呢
#ifndef
#define
宏早就防止你这种情况出现了 mark。我用延迟都是在不重要的场合,要准的话用定时器,要短的话加空指令自己数数 先MARK了
平时我比较少用AVR的,学习一下~~ 先Mark了,这论坛的好东西真多.学习学习
页:
[1]