- 芝华塔尼欧的少年
-
跟51的一样,具体可以根据软件调试修改时间。
WinAVR20081205 延时函数 :
void
_delay_loop_1(uint8_t __count)
{
__asm__ volatile (
"1: dec %0" " "
"brne 1b"
: "=r" (__count)
: "0" (__count)
);
}
准确延时是3*__count个时钟周期 (0<__count<256)
void
_delay_loop_2(uint16_t __count)
{
__asm__ volatile (
"1: sbiw %0,1" " "
"brne 1b"
: "=w" (__count)
: "0" (__count)
);
}
准确延时是4*__count+1个时钟周期 (0<__count<256*256-1)
_delay_loop_1() 最小延时是3个时钟周期,最大延时是256*3个时钟周期
_delay_loop_2() 最小延时是4+1个时钟周期,最大延时是256*256*4+1个时钟周期
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);
}
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);
}
_dealy_us()最小延时 与 _delay_loop_1()相同,是3个时钟周期,
_delay_us(0)就是最小延时,相当于_delay_loop_1(1),
在8M时钟下,_delay_us(0.375)也是最小延时(0.375us是3个时钟周期)
_delay_us(0.7499999)仍然是最小延时,相当于_delay_loop_1(1),
而_delay_us(0.74999999)则相当于_delay_loop_1(2)了。
_dealy_ms() 最小延时与 _delay_loop_2()相同,是4+1个时钟周期。
_delay_ms(0)就是最小延时,相当于_delay_loop_2(1),
在8M时钟下,_delay_ms(0.0005)也是最小延时(0.0005ms相当于是4个时钟周期)
_delay_ms(0.0009999999)仍然是最小延时,相当于_delay_loop_2(1),
而_delay_ms(0.00099999999)则相当于_delay_loop_2(2)了。
_dealy_us(__us)延时精度范围:
(0 , 3个时钟周期),误差(0,3)个时钟周期
(3个时钟周期 , 768us/(F_CPU/1000000)),误差(-2,0)个时钟周期
(768us/(F_CPU/1000000) , 262.14ms/(F_CPU/1000000)),误差(-2,+1)个时钟周期,
(262.14ms/(F_CPU/1000000)) , 6553.5ms),误差8M时钟下(约+0.18ms,约+57ms)
_dealy_ms(__ms)延时精度范围:
(0 , 4个时钟周期),误差(1,5)个时钟周期
(4个时钟周期 , 262.14ms/(F_CPU/1000000)),误差(-2,+1)个时钟周期,
(262.14ms/(F_CPU/1000000)) , 6553.5ms),误差8M时钟下(约+0.18ms,约+57ms)
_dealy_us(__us)最大延时6553.5ms,即_delay_us(6553500);
_delay_ms(__ms)最大延时6553.5ms,即_delay_ms(6553.5);
本人水平有限,如果错漏之处,多谢指正。
补充:
1.WinAVR延时库函数看起来,又是double,又是if、else,难道不耗时间?
不耗时间。WinAVR延时库函数,double都可以优化成常量,而整型常量,浮点常量运算,结果仍然仍然是常量。
编译器只要开优化,不会编译出额外的代码出来。if,else也一样。if判断条件是一个常量,也就是说某个分支一定为真,
另外的分支一定为假,编译器优化时,不会编译出额外代码。需要注意,如果要调用WinAVR延时库函数,则必须要开优化。
2.怎么没有计算函数调用,返回时间?
WinAVR延时库函数全部都是内联函数,没有函数调用和返回开销。当然,这也有一个副作用,每处延时函数都会编译出一段代码,
占据更多的代码空间。
3.旧版WinAVR _delay_us()最大延时768us/(F_CPU/1000000),delay_ms()最大延时是262.14ms/(F_CPU/1000000)。
新版WinAVR_delay_us()和_delay_ms()最大延时都是6553.5ms,不过误差也相对较大,每0.1ms多7个时钟周期,8M时钟下,误差约为+0.88%。
----------------------------------
附IARAVR延时函数:
#ifndef __IAR_DELAY_H__
#define __IAR_DELAY_H__
#include <intrinsics.h>
#include "hal_type.h"
#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)/1000000.0) + 0.5))
#define _delay_ms(A)
__delay_cycles( (uint32) ( (double)(F_CPU)*((A)/1000.0) + 0.5))
#define _delay_s(A)
__delay_cycles( (uint32) ( (double)(F_CPU)*((A)/1.0) + 0.5))
#endif
- 一自萧关起战尘
-
#ifndef DS18B20__H__
#define DS18B20__H__
/************************************************
DS18B20温度采集头文件
说明:仅仅只调用带返回值函数Get_Temp()
MCU主频20MHz,调用时请注意修改延时
*************************************************/
#define DS18B20_DDR DDRF
#define DS18B20_PORT PORTF
#define DS18B20_PIN PINF
#define DQ PF2
/**********以上I/O口的设置,请注意修改***********/
#define DQ_OUT DS18B20_DDR|=BIT(DQ)
#define DQ_IN DS18B20_DDR&=~BIT(DQ)
#define DQ_ON DS18B20_PORT|=BIT(DQ)
#define DQ_OFF DS18B20_PORT&=~BIT(DQ)
#define DQ_PIN DS18B20_PIN&BIT(DQ)
void DS18B20_us(unsigned int j)
{
unsigned char i;
do
{
for(i=0;i<2;i++);
j--;
asm("nop");
}
while(j);
}
void DS18B20_ms(unsigned int j)
{
unsigned int i;
do
{
for(i=0;i<2880;i++);
j--;
}
while(j);
}
void DS18B20_Init(void)
{
DQ_OUT;
DQ_ON;
DS18B20_us(1);
DQ_OFF;
DS18B20_us(480);
DQ_ON;
DQ_IN;
//DS18B20_us(1);
while(!(DQ_PIN));
DQ_OUT;
DQ_ON;
DS18B20_us(150);
}
void DS18B20_Write(unsigned char dat)
{
unsigned char i;
for(i=0;i<8;i++)
{
DQ_OUT;
DQ_OFF;
//DS18B20_us(15);
if(dat&0x01)
{
DQ_ON;
}
else
{
DQ_OFF;
}
DS18B20_us(30);
DQ_ON;
dat>>=1;
}
DQ_ON;
}
unsigned char DS18B20_Read(void)
{
unsigned char i,dat=0;
for(i=0;i<8;i++)
{
DQ_OUT;
dat>>=1;
DQ_ON;
//DS18B20_us(1);
DQ_OFF;
DS18B20_us(1);
DQ_ON;
DQ_IN;
if(DQ_PIN)
{
dat|=BIT(7);
}
else
{
dat&=~BIT(7);
}
DS18B20_us(30);
}
DQ_OUT;
return dat;
}
unsigned int Get_Temp(void)
{
unsigned char a=0,b=0;
unsigned int temp;
float t=0;
DS18B20_Init();
DS18B20_Write(0xcc);
DS18B20_Write(0x44);
DS18B20_ms(90);
DS18B20_Init();
DS18B20_Write(0xcc);
DS18B20_Write(0xbe);
a=DS18B20_Read();
b=DS18B20_Read();
temp=b;
temp<<=8;
temp=temp|a;
t=temp*0.0625;
temp=t*10+0.5;
return temp;
}
#endif
以上是DS18B20.h文件,这是在20MHz下的。你要的是8MHz,以下是8MHz下的延时函数头文件“delay.h”
#ifndef delay__H__
#define delay__H__
/************************************************
8M延时函数
说明:此延时函数用AVR Studio仿真得出
*************************************************/
void delay_us(unsigned int us) //延时us级
{
unsigned char i;
us=us*5/4;
for( i=0;i<us;i++);
}
void delay_ms(unsigned int ms) //延时ms级
{
unsigned int i,j;
for( i=0;i<ms;i++)
for(j=0;j<1141;j++);
}
//////////////////////延时函数结束////////////////////
#endif
这个DS18B20程序是调试通过的: http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=3999139&bbs_page_no=1&search_mode=3&search_text=xzf962&bbs_id=9999
- gitcloud
-
STUDIO 里自带延时程序,我就是使用,基本很准的。
DS18B20我也是那么做的,效果很好