Avr-Gcc中关于delay函数的应用

分析程序发现上面两个子函数,分别using _delay_loop_1() and using_delay_loop2()
整理一下单片机的相关的资料,我用的编译器是atmel的AVR studio+gcc
先整理下关于avr-gcc中关于delay函数的应用

#include <util/delay.h> 
就可以使用了。这个头文件定义了两个级别的延时函数分别是:
void  _delay_us (double __us) ;      //微秒级
void  _delay_ms (double __ms);    //毫秒级


这个参数和 Makefile 中的 F_CPU 值有关,Makefile 所定义的的F_CPU 变量的值会传递给编译器。你如果用AVR_studio 4来编辑和调试,用内嵌AVR-GCC的进行编译,并且让AVR_studio 帮你自动生成Makefile 的话,那你可以在:
 Project -> Configuration Options -> Gerneral -> Frequency   如下图:
AVR单片机LED点亮 - Hydeogen - Hydrogen的博客


要正确使用它们是有如下条件的:

1. 首先,你要正确定义你的 F_CPU的值,也就是你的AVR单片机实际的频率。否则延时不准,这个就是Frequency的值。  

写下你的F_CPU的值,F_CPU这个值表示你的AVR单片机的工作频率。单位是 Hz ,不是 MHZ,不要写错。
比如说:16MHZ,要写成16000000,不要写成16

2. 你在编译时一定要打开优化,Makefile中OPT 不要选 0 ,如果AVR_studio不要选O0 。要不然就会出现# warning"Compiler optimizations disabled; functions from <util/delay.h>won't work as designed"编译警告,且延时失准。

====================================================================================================

-00 无优化。
-01 减少代码尺寸和执行时间,不进行需要大量编译时间的优化。
-O2 几乎执行所有优化,而不考虑代码尺寸和执行时间。
-O3 执行-O2所有的优化,以及内联函数,重命名寄存器的优化。
-OS 针对尺寸的优化。执行所有-O2优化而不增加代码尺寸。

====================================================================================================
复选框:
1. 所有char认为是unsined char
2.所有bitfields 认为是unsigned
3.定义结构体时,连续存储
4.定义枚举类型时,使用最大需要的存储空间 (3,4两项真是多余,不选中肯定出错)

一般选-OS优化,复选框全选。

在util文件夹中找到delay头文件如下:
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);
}
/****************************************************************************************/
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);
}
分析程序发现上面两个子函数,分别使用了 _delay_loop_1();和using_delay_loop2()
还是在util文件夹下打开delay_basic.h文件
/** \ingroup util_delay_basic

    Delay loop using an 8-bit counter \c __count, so up to 256
    iterations are possible.  (The value 256 would have to be passed
    as 0.)  The loop executes three CPU cycles per iteration, not
    including the overhead the compiler needs to setup the counter
    register.

    Thus, at a CPU speed of 1 MHz, delays of up to 768 microseconds
    can be achieved.
*/

翻译过来就是:
    循环变量为8位,所以可达256(其值256和0等同),每次循环好执行3个CPU时钟,不包括程序调用和退出该函数所花费的时间。
    如此,当CPU为1MHZ时,最大延时为768us。( 3us*256)void
_delay_loop_1(uint8_t __count)
{
    __asm__ volatile (
        "1: dec %0" "\n\t"
        "brne 1b"
        : "=r" (__count)
        : "0" (__count)
    );
}

/******************************************************/
/** \ingroup util_delay_basic

    Delay loop using a 16-bit counter \c __count, so up to 65536
    iterations are possible.  (The value 65536 would have to be
    passed as 0.)  The loop executes four CPU cycles per iteration,
    not including the overhead the compiler requires to setup the
    counter register pair.

    Thus, at a CPU speed of 1 MHz, delays of up to about 262.1
    milliseconds can be achieved.
 */

翻译:
        循环变量为16位,所以可达65536(其值65536和0等同),每次循环好执行4个CPU时钟,不包括程序调用和退出该函数所花费的时间。
    如此,当CPU为1MHZ时,最大延时大约为262.1us。( 4us*65536)void
_delay_loop_2(uint16_t __count)
{
    __asm__ volatile (
        "1: sbiw %0,1" "\n\t"
        "brne 1b"
        : "=w" (__count)
        : "0" (__count)
    );
}
/*************************************************************/

有了上面的基础就不难得出
   #include <util/delay_basic.h>    // 头文件
  
   // _delay_loop_1(XX);        //    8-bit count, 3 cycles/loop
   // _delay_loop_2(XXXX);      //   16-bit count, 4 cycles/loop

   #include <util/delay.h>    // 头文件
  
   _delay_loop_1(uint16_t __count)
   1MHz时: MAX_DELAY_TIME = (1/1000000)*3*256 = 0.000768 S = 768 uS
   8MHz时: MAX_DELAY_TIME = (1/8000000)*3*256 = 0.000096 S = 96 uS
   ............
   F_CPU     MAX_DELAY_TIME = (1/F_CPU)*3*256
   依此类推。

    _delay_loop_2(uint16_t __count)
    1MHz时: MAX_DELAY_TIME = (1/1000000)*4*65535 = 0.26214 S = 262.1 mS
    8MHz时: MAX_DELAY_TIME = (1/8000000)*4*65535 = 0.03277 S = 32.8 mS
   ............

    16MHZ时:MAX_DELAY_TIME = (1/16000000)*4*65535 = 0.03277 S = 16.4 mS

   F_CPU     MAX_DELAY_TIME = (1/F_CPU)*4*65535
   依此类推。


重要提示:_delay_loop_1(0)、_delay_loop_1(256)延时是一样的!!
同理,    _delay_loop_2(0)、_delay_loop_2(65536)延时也是一样的!!这些函数的延时都是最长的延时。

重量级函数出场>>>>>>>>>>>>>_delay_us() and    _delay_ms() !!!<<<<<<<<<<<<<<<<<

    先说_delay_us(double __us),不要以为该函数的形参是double形就为所欲为,随便付值都不会溢出了,其实这个函数的调用是有限制的,不然就会出现延时不对的情况。函数的注释里说明如下:

   The maximal possible delay is 768 us / F_CPU in MHz.
   在1MHz时最大延时768us!!!!

     也就是说double __us这个值在1M系统时钟时最大只能是768。如果大于768,比如这样调用延时函数_delay_us(780)会怎么样呢??那就会和调用_delay_loop_1(0)一样的效   果了!能延迟多少各位可以算出来。具体在各种系统时钟之下这个值是多少可以通过一个公式算出来:

   MAX_VALUE = 256*3000000/F_CPU

   同理,分析程序,可以知道_delay_ms(double __ms)函数,在1MHz系统时钟下其最大延时是262.14 ms!在这里也给出该函数的形参的最大值,调用此函数时的实参都不要大于     这个值,大于这个限制值的话就和调用_delay_loop_2(0)同样的延时效果!

   MAX_VALUE = 65536*4000/F_CPU (1MHZ时,能输入的最大值为262)

   从上面可以看出来,当用延时函数时,若不加注意会出错的(毕竟人们很难经常记住这两个最大值),那还有什么补偿的办法呢?
   #include <util/delay_basic.h>

    // _delay_loop_2(XXXX); // 16-bit count, 4 cycles/loop
    // _delay_loop_1(XX);      //   8-bit count, 3 cycles/loop

/*------------------------------------*/
void delay_1ms(void)        //1ms延时函数 主频为8MHz
{  
    _delay_loop_2(2000); // 16-bit count,4 cycles/loop

   }                                    // 2000*4/FREQ

                                        //使用不同的晶振,可以自己来计算出()里的值

/*-------------------------------------*/
  
void delay_nms(unsigned int n)       //N ms延时函数
   {
      unsigned int i=0;
      for (i=0;i<n;i++)
      delay_1ms();
     }
/*------------------------------------ -*/

参考地址:http://hi.baidu.com/xtuyvzkkkllstue/item/9654ea2f29450bc7ef10f1e2

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值