您的位置 首页 元件

AVR 中 delay 函数的调用注意事项!delay_ns delay_ms

早就知道AVR的编译器有自带的延时子函数(或者说是头文件),但一直没时间一探究竟,今天终于揭开了其内幕。AVR编译器众多,可谓是百家齐鸣

早就知道AVR的编译器有自带的延时子函数(或许说是头文件),但一向没时刻一探终究,今日总算揭开了其内情。

AVR编译器很多,可谓是百家齐鸣,自己独尊WinAVR.
阐明:编译器版别WinAVR-20080610
先说winAVR的_Delay.h_肯定是在Include文件夹下了,进去一看果然有,可翻开一看,其曰:“This file has been moved to delay.h>.”
在util文件夹中找到delay头文件如下:
——————————————————————————————————————————————–
void
_delay_us(double __us)
{
uint8_t __ticks;
double __tmp = ((F_CPU) / 3e6) * __us; //3e6=3000000
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_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);
}
1、剖析程序发现上面两个子函数,别离using _delay_loop_1() and using_delay_loop2()
2、还有一点,用此头文件时,有必要设置主频和优化项,否则会呈现如下提示:
#ifndef F_CPU
/* prevent compiler error by supplying a default */
# warning “F_CPU not defined for
# define F_CPU 1000000UL
#endif

#ifndef __OPTIMIZE__
# warning “Compiler optimizations disabled; functions from wont work as designed”
#endif
3、经过查找发现_Delay_loop1()和_Delay_loop2()在文件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 passedas 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” “”
“brne 1b” a a
: “=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” “”
“brne 1b”
: “=w” (__count)
: “0” (__count)
);
}
4、有了上面的根底就不难得出
#include // 头文件

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

#include // 头文件

_delay_loop_1(uint8_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
…………
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

// _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;idelay_1ms();
}
/*------------------------------------ -*/

原文见:http://hi.baidu.com/xtuyvzkkkllstue/item/9654ea2f29450bc7ef10f1e2

个人的一些了解,欢迎拍砖:

(1)_delay_us(double __us)调用了子函数void _delay_loop_1(uint8_t _count),uint8_t约束了_us的取值规模不能超过255,而_us又决议了_delay_us()能延时多久的问题,详细能延时多久就依据时钟频率了,如上文所说(如同原文有误_delay_loop_1(uint8_t __count)这个当地搞成了_delay_loop_2(uint16_t __count),本篇已改正):

_delay_loop_1(uint8_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_ms(double _ms)也相同,调用了子函数void _delay_loop_2(uint16_t _count),uint16_t约束了_ms的取值规模不能超过65535,而_ms又决议了_delay_ms()能延时多久

_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
…………
F_CPU MAX_DELAY_TIME = (1/F_CPU)*4*65535

(2)AVR自带delay函数延时1us、1ms跟晶振频率没有关系,晶振频率仅仅决议了参数取值规模,在计数延时时分F_CPU这个值抵消掉了。

(3)上文中的解决方法是自己写了个延时1ms的函数,其实跟自带的是相同,自带的如下:

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

绿色部分暂时不看,赤色部分便是_ticks的值,假如晶振是8M带入(F_CPU) / 4e3既得2000,跟上文是相同。便是自带的函数里边不用考虑时钟频率,由于它终究被约分。所以这个1ms延时不用自己写了,咱们只需要引证_delay_ms(1);让它延时1ms,然后再设循环延时nms,这样就摆脱了_delay_ms(double _ms)中_ms的规模约束。

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/xinpin/yuanjian/261472.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部