1.这种方法最主要了:定时器的初值,也就是对TH1,TL1(T0也是如此)重装初值,这种方法需要先计算(一定要注意波特率和PCON的初始化)。
2.就是用汇编来实现,我先贴一段汇编的延时子程序大家看看:
;1s的延时程序
delay1s: mov r1,#50
del0:mov r2,#100
del1:mov r3,$
djne r2,del1
djnz r1,del0
ret
抱歉得很,没有注释,因为我也不太明白这种延时是不是很准确,这是我在电子制作这本杂志上看到的,当时如获至宝抄了下来,不过在网上看了很多汇编程序都是这样,不过要是在C语言上使用还是要内嵌这段汇编代码。
所以我想问问各位要用到精确延时时究竟该怎么做?
32 个解决方案
#1
哦对了,上面汇编代码有点问题。具体是这样的:
delay1s: mov r1,#50
del0: mov r2,#100
del1: mov r3,#100
djnz r3,$
djnz r2,del1
djnz r1,del0
ret
delay1s: mov r1,#50
del0: mov r2,#100
del1: mov r3,#100
djnz r3,$
djnz r2,del1
djnz r1,del0
ret
#2
这种方法应该还是比较精确的
它是用每一条语句运行的时间,时钟每跳一次的时间来算的
它是用每一条语句运行的时间,时钟每跳一次的时间来算的
#3
谢谢
#4
用循环还是会受中断干扰,用定时器是较可靠的,但软件复杂些
#5
同意楼上的意见,用软件循环延时在关中断的情况下可以实现精确定时,因为每条指令的执行时间是已知的。用定时器来实现一般较为精确,但是涉及到中断和主程序的协调和同步问题,程序结构较为复杂。
#6
用定时器吧...不过我不懂
#7
你的汇编代码主要是应用了DJNZ的2个时钟周期,靠这2个时钟周期定时.在KEIL下C语言也可以实现,具体代码我没有,你可以一边调试(反汇编),一边测试.KEIL是很强大的,它的优化功能做的很好.在"中山单片机"有人专门写了个贴子是关于用c语言写的延时,精确度较高.
调试是一种很好的方法
调试是一种很好的方法
#8
上述汇编代码其实也是通过循环来延时,只不过汇编指令的时间比较精确。不过不同的晶振频率对应于不同循环计数。用定时器的话,要使用一个定时器,并且禁止定时器中断。如果单片机有多余的定时器的话,可以优先考虑这种方法。
#9
最近看了看书有点明白了上面的汇编延时原理是这样的,一个mov语句是耗时2个周期,例如我经常用的11.0592的晶振,一个单片机周期约1us,那么一个mov语句为2us,djnz r3,$就是在本行不停地作减1,r3为100,那就要在本句做100次执行,明白这两句话的含义上面的延时时间就好算了,具体为:50*(2+2+100*2+(2*100+2)*100)+2=1020200us大约为1s的延时,不知我算得对不对?
#10
精确的话就用定时器啦
我只会C语言的,还没学好汇编的
所以就给个C的吧
void time() interrupt ?(0~4) //中断函数 ?表示中断号,0到4分别为外部中断,定时器中断,串口中断
{TH?=0x??;//重装初值
TL?=0x??;
}
main()
{
TMOD=0x??; //定时器工作模式
TH0=0x??; //装初值
TL0=0x??;
TR0=1; //开定时器 使之工作
EA=1; //开所有中断
ET?=1; //开定时器中断
for(;;){;}//无限循环 等待中断
}
我只会C语言的,还没学好汇编的
所以就给个C的吧
void time() interrupt ?(0~4) //中断函数 ?表示中断号,0到4分别为外部中断,定时器中断,串口中断
{TH?=0x??;//重装初值
TL?=0x??;
}
main()
{
TMOD=0x??; //定时器工作模式
TH0=0x??; //装初值
TL0=0x??;
TR0=1; //开定时器 使之工作
EA=1; //开所有中断
ET?=1; //开定时器中断
for(;;){;}//无限循环 等待中断
}
#11
定时器延时精确
#12
同意定时器
#13
定时器是最佳选择
#14
定时器也不是很准确,也在找更好的方法。
#15
本身晶振也是存在误差的。
#16
写好延时函数后,用定时器测试一下 看看具体是多长时间哈
#17
每条语句执行的时间是一定的 你把 tr1 th1 重新装初始值 delay函数的延迟时间 一般情况还是很精确的在毫秒级内
#18
用定时器还是比较好的
#19
其实红外协议根本不用那么精确的延时,可以在一段延时之后判断i/o口的方法做。
我在3.8M定时器时钟下都能正常解码。
我在3.8M定时器时钟下都能正常解码。
#20
还是用定时器中断形式比较好
#21
还没有开始学习汇编
#22
定时器,软件延时都可以吧,关键看你怎么写
#23
定时器的确是比较准确的,但是如果用到的比较多的中断程序的话要精确的定时是有点复杂的。lz用到的红外协议其实要求的延时直接用for就行啦,我自己本身用过的ds18b20这个单总线传输的温度传感器就是用for的延时的。
#24
红外遥控根本就不用精确定时,只要有效控制好范围就ok了!以nec为例,例如你要解头码的9ms,你可以使用0.14ms的定时中断,在里边计数,只要最后的结果在8-10ms中就ok了!
#25
掐秒表
#26
这要看你是用多少兆晶振的,下面的代码是我写的,晶振是12MHZ的,延时程序如下:
;//////////////延时程序1/////////////////////////////
;//实现的功能:延时1004us
delay1:
mov r6,#3
d0: mov r7,#165
djnz r7,$
djnz r6,d0
ret
;//////////////延时程序1/////////////////////////////
;//实现的功能:延时1004us
delay1:
mov r6,#3
d0: mov r7,#165
djnz r7,$
djnz r6,d0
ret
#27
我这儿有一种方法,来和大家共享一下
C语言的精确延时
以下所有测试若作为子函数,则调用时还要加上调用的2us和返回的2us,再加上赋值的时间。
long 4us(赋值)+2us(清零),int 2us,char 1us,3for 则不用.
即作为子函数调用全部要加的时间为long +10us,int +6us,char +5us,3for +0us.
*/
#include <at89x52.h>
void delay(void)
{
unsigned long i;
i=135;
while(--i);
}
void main(void)
{
/*unsigned long i;
i=113;
while(--i);
//此种形式定时时间为i*480/M us。最大误差不会超过1us,此1us主要是由某些特殊晶振不能被整除引起.
//i最大值为4294967295.M=12MHz下,Tmax=171798691800us约=17万秒
//大概生成代码是74
*/
/*unsigned int i;
i=113;
while(--i);
//此种形式定时时间为i*96/M us。最大误差不会超过1us,此1us主要是由某些特殊晶振不能被整除引起.
//i最大值为65535.M=12MHz下,Tmax=524280us约=0.5秒(500ms)
//大概生成代码是32
*/
/*unsigned char i;
i=150;
while(--i);
//此种形式定时时间为i*24/M us。最大误差不会超过1us,此1us主要是由某些特殊晶振不能被整除引起.
//i最大值为255.M=12MHz下,Tmax=510us约=0.5ms(500us)
//大概生成代码是23
*/
/*unsigned char i,j,k;
for(i=10;i>0;i--)
for(j=10;j>0;j--)
for(k=10;k>0;k--)
;
//此种形式定时时间为(((2*i+3)*j+3)*k+1)*12/M us。最大误差不会超过1us,
//此1us主要是由某些特殊晶振不能被整除引起.
//一层循环n:R5*2 DJNZ 2us
// 二层循环m:R6*(n+3) DJNZ 2us + R5賦值 1us = 3us
// 三层循环: R7*(m+3) DJNZ 2us + R6賦值 1us = 3us
//循环外:R7赋值 1us
//i最大值为255.M=12MHz下,Tmax=33.358591s
//大概生成代码是31。不过计算挺麻烦,要用软件计算,而且不是每1us都能算得到。
*/
delay();//子函数调用才用此行
P1_1=0;
while(1);
}
C语言的精确延时
以下所有测试若作为子函数,则调用时还要加上调用的2us和返回的2us,再加上赋值的时间。
long 4us(赋值)+2us(清零),int 2us,char 1us,3for 则不用.
即作为子函数调用全部要加的时间为long +10us,int +6us,char +5us,3for +0us.
*/
#include <at89x52.h>
void delay(void)
{
unsigned long i;
i=135;
while(--i);
}
void main(void)
{
/*unsigned long i;
i=113;
while(--i);
//此种形式定时时间为i*480/M us。最大误差不会超过1us,此1us主要是由某些特殊晶振不能被整除引起.
//i最大值为4294967295.M=12MHz下,Tmax=171798691800us约=17万秒
//大概生成代码是74
*/
/*unsigned int i;
i=113;
while(--i);
//此种形式定时时间为i*96/M us。最大误差不会超过1us,此1us主要是由某些特殊晶振不能被整除引起.
//i最大值为65535.M=12MHz下,Tmax=524280us约=0.5秒(500ms)
//大概生成代码是32
*/
/*unsigned char i;
i=150;
while(--i);
//此种形式定时时间为i*24/M us。最大误差不会超过1us,此1us主要是由某些特殊晶振不能被整除引起.
//i最大值为255.M=12MHz下,Tmax=510us约=0.5ms(500us)
//大概生成代码是23
*/
/*unsigned char i,j,k;
for(i=10;i>0;i--)
for(j=10;j>0;j--)
for(k=10;k>0;k--)
;
//此种形式定时时间为(((2*i+3)*j+3)*k+1)*12/M us。最大误差不会超过1us,
//此1us主要是由某些特殊晶振不能被整除引起.
//一层循环n:R5*2 DJNZ 2us
// 二层循环m:R6*(n+3) DJNZ 2us + R5賦值 1us = 3us
// 三层循环: R7*(m+3) DJNZ 2us + R6賦值 1us = 3us
//循环外:R7赋值 1us
//i最大值为255.M=12MHz下,Tmax=33.358591s
//大概生成代码是31。不过计算挺麻烦,要用软件计算,而且不是每1us都能算得到。
*/
delay();//子函数调用才用此行
P1_1=0;
while(1);
}
#28
这要看你是用多少兆晶振的,下面的代码是我写的,晶振是12MHZ的,延时程序如下:
;//////////////延时程序1/////////////////////////////
;//实现的功能:延时1004us
delay1:
mov r6,#3
d0: mov r7,#165
djnz r7,$
djnz r6,d0
ret
;//////////////延时程序1/////////////////////////////
;//实现的功能:延时1004us
delay1:
mov r6,#3
d0: mov r7,#165
djnz r7,$
djnz r6,d0
ret
#29
这要看你是用多少兆晶振的,下面的代码是我写的,晶振是12MHZ的,延时程序如下:
;//////////////延时程序1/////////////////////////////
;//实现的功能:延时1004us
delay1:
mov r6,#3
d0: mov r7,#165
djnz r7,$
djnz r6,d0
ret
;//////////////延时程序1/////////////////////////////
;//实现的功能:延时1004us
delay1:
mov r6,#3
d0: mov r7,#165
djnz r7,$
djnz r6,d0
ret
#30
直接用增强型单片机,使用自动重载定时器功能,也可以精确定时
#31
用定时器啊,不用重装初值的那组,很精确
#32
用定时器工作在方式2(不用重装初值)即M1M0=10,定时的时间由你自己设定
采用汇编的循环也可能会有中断的影响
采用汇编的循环也可能会有中断的影响
#1
哦对了,上面汇编代码有点问题。具体是这样的:
delay1s: mov r1,#50
del0: mov r2,#100
del1: mov r3,#100
djnz r3,$
djnz r2,del1
djnz r1,del0
ret
delay1s: mov r1,#50
del0: mov r2,#100
del1: mov r3,#100
djnz r3,$
djnz r2,del1
djnz r1,del0
ret
#2
这种方法应该还是比较精确的
它是用每一条语句运行的时间,时钟每跳一次的时间来算的
它是用每一条语句运行的时间,时钟每跳一次的时间来算的
#3
谢谢
#4
用循环还是会受中断干扰,用定时器是较可靠的,但软件复杂些
#5
同意楼上的意见,用软件循环延时在关中断的情况下可以实现精确定时,因为每条指令的执行时间是已知的。用定时器来实现一般较为精确,但是涉及到中断和主程序的协调和同步问题,程序结构较为复杂。
#6
用定时器吧...不过我不懂
#7
你的汇编代码主要是应用了DJNZ的2个时钟周期,靠这2个时钟周期定时.在KEIL下C语言也可以实现,具体代码我没有,你可以一边调试(反汇编),一边测试.KEIL是很强大的,它的优化功能做的很好.在"中山单片机"有人专门写了个贴子是关于用c语言写的延时,精确度较高.
调试是一种很好的方法
调试是一种很好的方法
#8
上述汇编代码其实也是通过循环来延时,只不过汇编指令的时间比较精确。不过不同的晶振频率对应于不同循环计数。用定时器的话,要使用一个定时器,并且禁止定时器中断。如果单片机有多余的定时器的话,可以优先考虑这种方法。
#9
最近看了看书有点明白了上面的汇编延时原理是这样的,一个mov语句是耗时2个周期,例如我经常用的11.0592的晶振,一个单片机周期约1us,那么一个mov语句为2us,djnz r3,$就是在本行不停地作减1,r3为100,那就要在本句做100次执行,明白这两句话的含义上面的延时时间就好算了,具体为:50*(2+2+100*2+(2*100+2)*100)+2=1020200us大约为1s的延时,不知我算得对不对?
#10
精确的话就用定时器啦
我只会C语言的,还没学好汇编的
所以就给个C的吧
void time() interrupt ?(0~4) //中断函数 ?表示中断号,0到4分别为外部中断,定时器中断,串口中断
{TH?=0x??;//重装初值
TL?=0x??;
}
main()
{
TMOD=0x??; //定时器工作模式
TH0=0x??; //装初值
TL0=0x??;
TR0=1; //开定时器 使之工作
EA=1; //开所有中断
ET?=1; //开定时器中断
for(;;){;}//无限循环 等待中断
}
我只会C语言的,还没学好汇编的
所以就给个C的吧
void time() interrupt ?(0~4) //中断函数 ?表示中断号,0到4分别为外部中断,定时器中断,串口中断
{TH?=0x??;//重装初值
TL?=0x??;
}
main()
{
TMOD=0x??; //定时器工作模式
TH0=0x??; //装初值
TL0=0x??;
TR0=1; //开定时器 使之工作
EA=1; //开所有中断
ET?=1; //开定时器中断
for(;;){;}//无限循环 等待中断
}
#11
定时器延时精确
#12
同意定时器
#13
定时器是最佳选择
#14
定时器也不是很准确,也在找更好的方法。
#15
本身晶振也是存在误差的。
#16
写好延时函数后,用定时器测试一下 看看具体是多长时间哈
#17
每条语句执行的时间是一定的 你把 tr1 th1 重新装初始值 delay函数的延迟时间 一般情况还是很精确的在毫秒级内
#18
用定时器还是比较好的
#19
其实红外协议根本不用那么精确的延时,可以在一段延时之后判断i/o口的方法做。
我在3.8M定时器时钟下都能正常解码。
我在3.8M定时器时钟下都能正常解码。
#20
还是用定时器中断形式比较好
#21
还没有开始学习汇编
#22
定时器,软件延时都可以吧,关键看你怎么写
#23
定时器的确是比较准确的,但是如果用到的比较多的中断程序的话要精确的定时是有点复杂的。lz用到的红外协议其实要求的延时直接用for就行啦,我自己本身用过的ds18b20这个单总线传输的温度传感器就是用for的延时的。
#24
红外遥控根本就不用精确定时,只要有效控制好范围就ok了!以nec为例,例如你要解头码的9ms,你可以使用0.14ms的定时中断,在里边计数,只要最后的结果在8-10ms中就ok了!
#25
掐秒表
#26
这要看你是用多少兆晶振的,下面的代码是我写的,晶振是12MHZ的,延时程序如下:
;//////////////延时程序1/////////////////////////////
;//实现的功能:延时1004us
delay1:
mov r6,#3
d0: mov r7,#165
djnz r7,$
djnz r6,d0
ret
;//////////////延时程序1/////////////////////////////
;//实现的功能:延时1004us
delay1:
mov r6,#3
d0: mov r7,#165
djnz r7,$
djnz r6,d0
ret
#27
我这儿有一种方法,来和大家共享一下
C语言的精确延时
以下所有测试若作为子函数,则调用时还要加上调用的2us和返回的2us,再加上赋值的时间。
long 4us(赋值)+2us(清零),int 2us,char 1us,3for 则不用.
即作为子函数调用全部要加的时间为long +10us,int +6us,char +5us,3for +0us.
*/
#include <at89x52.h>
void delay(void)
{
unsigned long i;
i=135;
while(--i);
}
void main(void)
{
/*unsigned long i;
i=113;
while(--i);
//此种形式定时时间为i*480/M us。最大误差不会超过1us,此1us主要是由某些特殊晶振不能被整除引起.
//i最大值为4294967295.M=12MHz下,Tmax=171798691800us约=17万秒
//大概生成代码是74
*/
/*unsigned int i;
i=113;
while(--i);
//此种形式定时时间为i*96/M us。最大误差不会超过1us,此1us主要是由某些特殊晶振不能被整除引起.
//i最大值为65535.M=12MHz下,Tmax=524280us约=0.5秒(500ms)
//大概生成代码是32
*/
/*unsigned char i;
i=150;
while(--i);
//此种形式定时时间为i*24/M us。最大误差不会超过1us,此1us主要是由某些特殊晶振不能被整除引起.
//i最大值为255.M=12MHz下,Tmax=510us约=0.5ms(500us)
//大概生成代码是23
*/
/*unsigned char i,j,k;
for(i=10;i>0;i--)
for(j=10;j>0;j--)
for(k=10;k>0;k--)
;
//此种形式定时时间为(((2*i+3)*j+3)*k+1)*12/M us。最大误差不会超过1us,
//此1us主要是由某些特殊晶振不能被整除引起.
//一层循环n:R5*2 DJNZ 2us
// 二层循环m:R6*(n+3) DJNZ 2us + R5賦值 1us = 3us
// 三层循环: R7*(m+3) DJNZ 2us + R6賦值 1us = 3us
//循环外:R7赋值 1us
//i最大值为255.M=12MHz下,Tmax=33.358591s
//大概生成代码是31。不过计算挺麻烦,要用软件计算,而且不是每1us都能算得到。
*/
delay();//子函数调用才用此行
P1_1=0;
while(1);
}
C语言的精确延时
以下所有测试若作为子函数,则调用时还要加上调用的2us和返回的2us,再加上赋值的时间。
long 4us(赋值)+2us(清零),int 2us,char 1us,3for 则不用.
即作为子函数调用全部要加的时间为long +10us,int +6us,char +5us,3for +0us.
*/
#include <at89x52.h>
void delay(void)
{
unsigned long i;
i=135;
while(--i);
}
void main(void)
{
/*unsigned long i;
i=113;
while(--i);
//此种形式定时时间为i*480/M us。最大误差不会超过1us,此1us主要是由某些特殊晶振不能被整除引起.
//i最大值为4294967295.M=12MHz下,Tmax=171798691800us约=17万秒
//大概生成代码是74
*/
/*unsigned int i;
i=113;
while(--i);
//此种形式定时时间为i*96/M us。最大误差不会超过1us,此1us主要是由某些特殊晶振不能被整除引起.
//i最大值为65535.M=12MHz下,Tmax=524280us约=0.5秒(500ms)
//大概生成代码是32
*/
/*unsigned char i;
i=150;
while(--i);
//此种形式定时时间为i*24/M us。最大误差不会超过1us,此1us主要是由某些特殊晶振不能被整除引起.
//i最大值为255.M=12MHz下,Tmax=510us约=0.5ms(500us)
//大概生成代码是23
*/
/*unsigned char i,j,k;
for(i=10;i>0;i--)
for(j=10;j>0;j--)
for(k=10;k>0;k--)
;
//此种形式定时时间为(((2*i+3)*j+3)*k+1)*12/M us。最大误差不会超过1us,
//此1us主要是由某些特殊晶振不能被整除引起.
//一层循环n:R5*2 DJNZ 2us
// 二层循环m:R6*(n+3) DJNZ 2us + R5賦值 1us = 3us
// 三层循环: R7*(m+3) DJNZ 2us + R6賦值 1us = 3us
//循环外:R7赋值 1us
//i最大值为255.M=12MHz下,Tmax=33.358591s
//大概生成代码是31。不过计算挺麻烦,要用软件计算,而且不是每1us都能算得到。
*/
delay();//子函数调用才用此行
P1_1=0;
while(1);
}
#28
这要看你是用多少兆晶振的,下面的代码是我写的,晶振是12MHZ的,延时程序如下:
;//////////////延时程序1/////////////////////////////
;//实现的功能:延时1004us
delay1:
mov r6,#3
d0: mov r7,#165
djnz r7,$
djnz r6,d0
ret
;//////////////延时程序1/////////////////////////////
;//实现的功能:延时1004us
delay1:
mov r6,#3
d0: mov r7,#165
djnz r7,$
djnz r6,d0
ret
#29
这要看你是用多少兆晶振的,下面的代码是我写的,晶振是12MHZ的,延时程序如下:
;//////////////延时程序1/////////////////////////////
;//实现的功能:延时1004us
delay1:
mov r6,#3
d0: mov r7,#165
djnz r7,$
djnz r6,d0
ret
;//////////////延时程序1/////////////////////////////
;//实现的功能:延时1004us
delay1:
mov r6,#3
d0: mov r7,#165
djnz r7,$
djnz r6,d0
ret
#30
直接用增强型单片机,使用自动重载定时器功能,也可以精确定时
#31
用定时器啊,不用重装初值的那组,很精确
#32
用定时器工作在方式2(不用重装初值)即M1M0=10,定时的时间由你自己设定
采用汇编的循环也可能会有中断的影响
采用汇编的循环也可能会有中断的影响