搜索
bottom↓
回复: 9

WinAVR中delay函数的研究

[复制链接]

出0入0汤圆

发表于 2009-5-18 23:24:44 | 显示全部楼层 |阅读模式
在WinAVR中,有一个delay.h文件,里面包含了_delay_us和_delay_ms两个函数,分别可以延时微秒和毫秒时间。看下面一个例子:


#include <avr/io.h>
#include <util/delay.h>

unsigned char t = 10;

int main()
{
  while(1)
  {
    _delay_ms(10);
  }

  return 0;
}

编译后,程序空间占用为:

AVR Memory Usage
----------------
Device: atmega168

Program: 180 bytes (1.1% Full)
(.text + .data + .bootloader)

Data: 2 bytes (0.2% Full)
(.data + .bss + .noinit)


Build succeeded with 0 Warnings...


如果将上面程序稍作修改:


#include <avr/io.h>
#include <util/delay.h>

unsigned char t = 10;

int main()
{
  while(1)
  {
    _delay_ms(t);
  }

  return 0;
}


Device: atmega168

Program: 3844 bytes (23.5% Full)
(.text + .data + .bootloader)

Data: 266 bytes (26.0% Full)
(.data + .bss + .noinit)

Build succeeded with 0 Warnings...

发现RAM和ROM的占用突然就急剧增加了。这是为什么呢?从程序直接看,没有什么问题。打开delay.h文件,我们发现有一段说明:

In order for these functions to work as intended, compiler optimizations must be enabled, and the delay time must 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.

上面这段话说明delay函数需要使用常数作为延时的参数,否则延时的结果可能会很长(不可预知),同时会因为链接了浮点库到程序,所以程序大小会急剧膨胀。


参考文献:
http://blog.ednchina.com/shaoziyang/139750/message.aspx

出0入0汤圆

 楼主| 发表于 2009-5-18 23:26:03 | 显示全部楼层
winavr中延时函数有问题?延时不准确!

在WINAVR中,可以自己编写延时程序,也可以直接调用WINAVR自带的delay函数。

在调用WINAVR自带的delay函数时,有时我们想延时1秒钟时,直接写_delay_ms(1000);

可是,最后结果却不对,延时不到1秒,为什么呢?下面就来解释一下这个现象:

delay.h文件位于X:\WinAVR\avr\include\avr中。

delay.h中有两个函数--------_delay_ms(double __ms)和_delay_us(double __us),分别延时__ms*F_CPU毫秒、__us*F_CPU微秒,(单片机晶振是F_CPU MHZ)两函数的原型分别如下:

1、_delay_us(double __us)

static __inline__ void
_delay_us(double __us)
{
uint8_t __ticks;
double __tmp = ((F_CPU) / 3e6) * __us;
if (__tmp < 1.0)
__ticks = 1;
else if (__tmp > 255)
__ticks = 0; /* i.e. 256 */
else
__ticks = (uint8_t)__tmp;
_delay_loop_1(__ticks);
}

其中,该函数延时的最大时间是768/F_CPU微秒。

2、_delay_ms(double __ms)

static __inline__ 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 = 0; /* i.e. 65536 */
else
__ticks = (uint16_t)__tmp;
_delay_loop_2(__ticks);
}

其中,该函数延时的最大时间是262.14/F_CPU毫秒。

现在明白上面为什么不行了吧!

具体函数代码,大家可以直接到delay.h里看看。还有,以后大家在写程序时,用到编译软件自带的函数时,都可以直接到源文件里看看,以后自己也学着写一些供调用的函数或头文件,这对提高编程水平很有帮助的!


参考文献:
http://www.avrtool.com/avr/gccavr/200808/1312.html

出0入0汤圆

 楼主| 发表于 2009-5-18 23:26:32 | 显示全部楼层
delay_ms,delay_us延时函数在不同工作频下的最大值
GCC中delay_ms,delay_us延时函数在不同工作频(常用)下的最大值如下:
_delay_ms(double __ms)
The maximal possible delay is 262.14 ms / F_CPU in MHz.
工作频率 最大延时值(ms)
20M 13ms
16M 16ms
12M 21ms
11.0592M 23ms
8M 32ms
7.3728M 35ms
4M 65ms
2M 131ms
1M 262ms
_delay_us(double __us)
The maximal possible delay is 768 us / F_CPU in MHz.
工作频率 最大延时值(us)
20M 38us
16M 48us
12M 64us
11.0592M 69us
8M 96us
7.3728M 104us
4M 192us
2M 384us
1M 768us

转自OURAVR论坛:

http://www.ouravr.com/bbs/bbs_content.jsp?bbs_sn=936084&bbs_page_no=1&bbs_id=1000

出0入0汤圆

发表于 2009-5-18 23:45:52 | 显示全部楼层
补充几点:

1.
_delay_us(double __us)  
_delay_ms(double __ms)
参数是浮点,并非整型,
_delay_ms(0.001)是可以的,相当于delay_us(1)。(并非完全等同,误差可能会不一样)

2.
_delay_us精确延时误差为(-3,0]个时钟周期,_delay_ms精确延时误差为(-3,+1]个时钟周期,
这里没有考虑_delay_us(0)和_delay_ms(0)

3.
_delay_us(0)相当于_delay_loop_1(1),延时3个周期,误差+3个周期
和_delay_ms(0) 当于_delay_loop_2(1),延时5周,误差+5个周期

4.
新版WinAVR,_delay_us和_delay_ms最大延时都是6553.5ms,不精确延时,约有%0.89的误差。

出0入0汤圆

发表于 2009-5-31 15:23:58 | 显示全部楼层
好贴!65535*4e3/1e6 = 262.14
      255*3e6/1e6 =  765

static __inline__ void 是干么的?

出0入0汤圆

发表于 2010-4-14 00:56:16 | 显示全部楼层
顶一下,查看本模块所有关于delay.h的贴

出0入0汤圆

发表于 2010-4-15 10:11:20 | 显示全部楼层
收藏了

出0入0汤圆

发表于 2012-9-15 20:38:16 | 显示全部楼层
学习了,解决了当前问题

出0入0汤圆

发表于 2012-9-29 16:42:17 | 显示全部楼层
学习中...

出0入0汤圆

发表于 2014-1-20 20:35:21 | 显示全部楼层
现在收藏是不是有点儿挖坟的味道???。。。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2024-4-29 13:16

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

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