跟51的一样,具体可以根据软件调试修改时间。
WinAVR20081205 延时函数 :
void
_delay_loop_1(uint8_t __count)
{
__asm__ volatile (
"1: dec %0" "\n\t"
"brne 1b"
: "=r" (__count)
: "0" (__count)
);
}
准确延时是3__count个时钟周期 (0<__count<256)
void
_delay_loop_2(uint16_t __count)
{
__asm__ volatile (
"1: sbiw %0,1" "\n\t"
"brne 1b"
: "=w" (__count)
: "0" (__count)
);
}
准确延时是4__count+1个时钟周期 (0<__count<256256-1)
_delay_loop_1() 最小延时是3个时钟周期,最大延时是2563个时钟周期
_delay_loop_2() 最小延时是4+1个时钟周期,最大延时是2562564+1个时钟周期
void
_delay_us(double __us)
{
uint8_t __ticks;
double __tmp = ((F_CPU) / 3e6) __us;
if (__tmp < 10)
__ticks = 1;
else if (__tmp > 255)
{
_delay_ms(__us / 10000);
return;
}
else
__ticks = (uint8_t)__tmp;
_delay_loop_1(__ticks);
}
void
_delay_ms(double __ms)
{
uint16_t __ticks;
double __tmp = ((F_CPU) / 4e3) __ms;
if (__tmp < 10)
__ticks = 1;
else if (__tmp > 65535)
{
// __ticks = requested delay in 1/10 ms
__ticks = (uint16_t) (__ms 100);
while(__ticks)
{
// wait 1/10 ms
_delay_loop_2(((F_CPU) / 4e3) / 10);
__ticks --;
}
return;
}
else
__ticks = (uint16_t)__tmp;
_delay_loop_2(__ticks);
}
_dealy_us()最小延时 与 _delay_loop_1()相同,是3个时钟周期,
_delay_us(0)就是最小延时,相当于_delay_loop_1(1),
在8M时钟下,_delay_us(0375)也是最小延时(0375us是3个时钟周期)
_delay_us(07499999)仍然是最小延时,相当于_delay_loop_1(1),
而_delay_us(074999999)则相当于_delay_loop_1(2)了。
_dealy_ms() 最小延时与 _delay_loop_2()相同,是4+1个时钟周期。
_delay_ms(0)就是最小延时,相当于_delay_loop_2(1),
在8M时钟下,_delay_ms(00005)也是最小延时(00005ms相当于是4个时钟周期)
_delay_ms(00009999999)仍然是最小延时,相当于_delay_loop_2(1),
而_delay_ms(000099999999)则相当于_delay_loop_2(2)了。
_dealy_us(__us)延时精度范围:
(0 , 3个时钟周期),误差(0,3)个时钟周期
(3个时钟周期 , 768us/(F_CPU/1000000)),误差(-2,0)个时钟周期
(768us/(F_CPU/1000000) , 26214ms/(F_CPU/1000000)),误差(-2,+1)个时钟周期,
(26214ms/(F_CPU/1000000)) , 65535ms),误差8M时钟下(约+018ms,约+57ms)
_dealy_ms(__ms)延时精度范围:
(0 , 4个时钟周期),误差(1,5)个时钟周期
(4个时钟周期 , 26214ms/(F_CPU/1000000)),误差(-2,+1)个时钟周期,
(26214ms/(F_CPU/1000000)) , 65535ms),误差8M时钟下(约+018ms,约+57ms)
_dealy_us(__us)最大延时65535ms,即_delay_us(6553500);
_delay_ms(__ms)最大延时65535ms,即_delay_ms(65535);
本人水平有限,如果错漏之处,多谢指正。
补充:
1WinAVR延时库函数看起来,又是double,又是if、else,难道不耗时间?
不耗时间。WinAVR延时库函数,double都可以优化成常量,而整型常量,浮点常量运算,结果仍然仍然是常量。
编译器只要开优化,不会编译出额外的代码出来。if,else也一样。if判断条件是一个常量,也就是说某个分支一定为真,
另外的分支一定为假,编译器优化时,不会编译出额外代码。需要注意,如果要调用WinAVR延时库函数,则必须要开优化。
2怎么没有计算函数调用,返回时间?
WinAVR延时库函数全部都是内联函数,没有函数调用和返回开销。当然,这也有一个副作用,每处延时函数都会编译出一段代码,
占据更多的代码空间。
3旧版WinAVR _delay_us()最大延时768us/(F_CPU/1000000),delay_ms()最大延时是26214ms/(F_CPU/1000000)。
新版WinAVR_delay_us()和_delay_ms()最大延时都是65535ms,不过误差也相对较大,每01ms多7个时钟周期,8M时钟下,误差约为+088%。
----------------------------------
附IARAVR延时函数:
#ifndef __IAR_DELAY_H__
#define __IAR_DELAY_H__
#include <intrinsicsh>
#include "hal_typeh"
#define _delay_loop_1(A) __delay_cycles(3(A))
#define _delay_loop_2(A) __delay_cycles(4(A)+1)
#define _delay_us(A)\
__delay_cycles( (uint32) ( (double)(F_CPU) ((A)/10000000) + 05))
#define _delay_ms(A)\
__delay_cycles( (uint32) ( (double)(F_CPU)((A)/10000) + 05))
#define _delay_s(A)\
__delay_cycles( (uint32) ( (double)(F_CPU)((A)/10) + 05))
#endif
看C程序段执行的时间可以通过IAR的resister cyclecounter来查看,计算两短点之间的程序执行时间的方法是:记录下两断点的 cyclecounter的值,然后做差,用差值乘以机器周期即可(比如使用的是8M晶振,那差值就是乘以10^-8)
具体看什么要求,一般一个中断执行时间计时毫秒,估计是你写程序写的太多,造成PLC扫描中断周期过长。
建议你把中断程序优化下,写到其他位置,和中断分离,这样扫描的周期会短点,另外,你可以考虑用定时中断啊,这样避免了中断程序没扫描完,中断就被复位,程序一般控制毫秒控制肯定能达到工业使用要求的,你也可以把定时时间加长点。
优化举个简单例子:int
i;i=1;i=2;i=3;i=4;i=5;i=6;i=7;i=8;i=9;i=10;这段代码会被直接优化成
i=10;连续10次给i赋值,只有最后一次才有意义。前面的赋值没有意义,会被直接优化掉。如果后面i也没有被使用,则变量i本身没有意义,直接优化掉。最后编译出来的代码就是空。进一步,把上面的赋值换成循环int
i;for(i=1;i<10;i++);这段代码也会被优化成i=10;循环相当于连续给i赋值9次,循环里面i的值是多少,是没有意义的,最后循环退出时的i值才有意义,相当于最后一次的赋值i=10;如果后面的程序没有用到i,则变量i本身没有意义,直接优化掉。最后编译出来的代码就是空。谨记:空循环是没有意义的,有点优化能力的编译器,都会将空循完全环优化掉。如果需要延时,请加上volatile,或者调用编译器的延时函数,或者用编译参数禁止优化,或者使用内嵌汇编。总之,不要使用没有volatile的空循环带实现延时,这是不规范的。
#include<msp430x14xh>
#define uint unsigned int
delay(uint);
void main()
{
WDTCTL = 0x5A80;
uint ch[8] = {0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};
uint i,j;
P2DIR = 0xff;
P2OUT = 0xff; //低电平点亮
while(1)
{
for(i=0;i<8;i++)
{
P2OUT = ch[i];
delay(50000);
}
for(j=6;j>0;j--)
{
P2OUT = ch[j];
delay(50000);
}
}
}
void delay(uint z)
{
uint a;
for(a=0;a<z;a++);
}
1这是较为简单的流水灯程序,没有使用定时器,只是简单的延时;
若要精确延时,需要设置定时器A或B
2也可以通过移位 *** 作来实现流水灯,移位 *** 作放入中断内最好
以上就是关于AVR单片机(atmega16)的us级延时程序,用于DS18B20全部的内容,包括:AVR单片机(atmega16)的us级延时程序,用于DS18B20、如何在IAR里面查看一段程序的运行时间、iar定时器中断程序两秒等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)