您的位置 首页 国产IC

avr-gcc中关于delay延时函数的使用修改版

在51中我们的延时函数都是自己编写的,无论是在汇编中还是在C言语中。虽然有模板,有时还是有点烦。呵呵。不过在应用avr单片机的时候我们

在51中咱们的延时函数都是自己编写的,无论是在汇编中仍是在C言语中。虽然有模板,有时仍是有点烦。呵呵。不过在运用avr 单片机的时分咱们就有福了。由于avr-gcc 供给给咱们很便利的delay 延时函数, 只要在源文件包含:

#i nclude
就能够运用了。这个头文件界说了两个等级的延时函数别离是:
void_delay_us (double __us) ;//微秒级
void_delay_ms (double __ms);//毫秒级

不过不能够快乐的太早,由于要在你的avr-gcc中正确运用它们是有条件的,下面我将渐渐道来。

这个参数和 Makefile 中的 F_CPU 值有关,Makefile 所界说的的F_CPU 变量的值会传递给编译器。你假如用AVR_studio 4.1X来修正和调试,用内嵌AVR-GCC的进行编译,而且让AVR_studio 帮你主动生成Makefile 的话,那你能够在:
Project -> Configuration Options -> Gerneral -> Frequency 如下图:


写下你的F_CPU的值,F_CPU这个值表明你的AVR单片机的作业频率。单位是 Hz ,不是 MHZ,不要写错。如 7.3728M 则 F_CPU = 7372800
你会发现在”delay.h” 头文件中有这个样的一个界说如下:
#ifndef F_CPU
# warning “F_CPU not defined for
# define F_CPU 1000000UL// 1MHz
#endif

这是为了在你没有界说F_CPU这个变量(包含空),或是AVR_studio Frequency没有给值的时分,供给一个默许的 1MHz频率值。让编译器编译时不至于犯错。

下面是这两个函数的实体:
void _delay_us(double __us)//微秒
{
uint8_t __ticks;
double __tmp = ((F_CPU) / 3e6) * __us; // 3e6 是由于调用的_delay_loop_1()是三条指令的
if (__tmp < 1.0)
__ticks = 1;
else if (__tmp > 255)
__ticks = 0;
else
__ticks = (uint8_t)__tmp;
_delay_loop_1(__ticks);
}

void _delay_ms(double __ms) // 毫秒
{
uint16_t __ticks;
double __tmp = ((F_CPU) / 4e3) * __ms;// 4e3 是由于调用的_delay_loop_2()是四条指令的

if (__tmp < 1.0)
__ticks = 1;
else if (__tmp > 65535)
__ticks = 0;
else
__ticks = (uint16_t)__tmp;
_delay_loop_2(__ticks);
}

你会发现他们都别离调用了_delay_loop_1(); 和_delay_loop_2(); 这两个函数
而这两个函数又如下所示:
void_delay_loop_1(uint8_t __count)
{
__asm__ volatile (
“1: dec %0” “”
“brne 1b”
: “=r” (__count)
: “0” (__count)
);
}

从其函数注释里边能够了解到,该函数用来推迟3个晶振时钟周期,不包含程序调用和退出该函数所花费的时刻。该函数的形参__count是一个8位的变量,由此,咱们就能够依据体系选用的晶振频率算出该函数最大的推迟时刻了:
1MHz时:MAX_DELAY_TIME=(1/1000000)*3*256=0.000768S=768uS
8MHz时:MAX_DELAY_TIME=(1/8000000)*3*256=0.000096S=96uS
…………
F_CPUMAX_DELAY_TIME=(1/F_CPU)*3*256
依此类推。
void_delay_loop_2(uint16_t __count)
{
__asm__ volatile (
“1: sbiw %0,1” “”
“brne 1b”
: “=w” (__count)
: “0” (__count)
);
}
该函数延时4个晶振周期,形参是一个16位的变量,相同咱们也能够算出该函数最大的推迟时刻:
1MHz时:MAX_DELAY_TIME=(1/1000000)*4*65535=0.26214S=262.1mS
8MHz时:MAX_DELAY_TIME=(1/8000000)*4*65535=0.03277S=32.8mS
…………
F_CPUMAX_DELAY_TIME=(1/F_CPU)*4*65535
依此类推。
重要提示:_delay_loop_1(0)、_delay_loop_1(256)延时是相同的!!
同理,_delay_loop_2(0)、_delay_loop_2(65536)延时也是相同的!!这些函数的延时都是最长的延时。

这两个函数都是avr-gcc 的 inline汇编格局写的,详细的语法规矩我就不多说了。能够参阅avr-libc。不过这两个函数很简单,很简单理解。一个是字节递减,一个是字递减。假如你仔细看上面几个函数,你就会发现要正确运用它们是有如下条件的:
1. 首要,你要正确界说你的 F_CPU 的值,也便是你的AVR单片机实践的频率。不然延时禁绝。(延时只在数字上禁绝确,详细能够核算)
2. 你在编译时一定要翻开优化,Makefile中OPT 不要选 0 ,假如AVR_studio 不要选O0 。
3. 你在运用这两个delay()时,传递给两个函数的实参要运用常量,不要运用变量。
4. 设置的时刻参数__ms , __us 是有规模的,不要超越规模。__ms:1 – [262.14 ms / (F_CPU/1e6) ],__us:1- [768 us / (F_CPU/1e6)] 。 […]表取整数部分.(此处定论过错?)。

__us的最大值应该是768us(1M频率下)MAX_VALUE=256*3/F_CPU s,最小值3个时钟周期MIN_VALUE=1*3/F_CPU s;
,__ms最大值MAX_VALUE=65536*4/F_CPU s,MIN_VALUE=1*4/F_CPU s;

只要具有了上面的条件你才能够正确运用延时函数 _delay_us () 和 _delay_ms () 。关于第三个条件,为什么要选用常量,还有第二个条件为什么要翻开优化选项。这是为了让编译器在编译的时分就把延时的值核算好,而不是把它编译到程序中,在运行时才进行核算,那样的话,一是会添加代码的长度,还会使你的延时程序的延时时刻加长,或是变得不行意料。发生时序的过错。

在08版别中现已修正,详细函数如下:
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);
}
当__us过大的时分,就会调用_delay_ms();由上面能够知道8M时分_delay_ms最小能够延时4/8000000=0.5us 1M时,最小延时4/1000000=4us,能够连接上。
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);
}
当__ms过大时,只选用__ticks –的方法延时。先延时一个262ms(1M,32ms 8M),然后用递减方法。

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

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

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

微信扫一扫关注我们

返回顶部