您的位置:首页 > 其它

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

2014-07-17 11:55 337 查看
分析程序发现上面两个子函数,分别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 如下图:



要正确使用它们是有如下条件的:
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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: