关于时间单位1s=1000ms毫秒=10-3秒
1ms=1000us微秒=10-6秒
1us=1000ns纳秒=10-9秒
1ns=1000ps皮秒=10-12秒
1ps=1000fs飞秒=10-15秒
目前51单片机只能精确到微秒级,若对时间精度要求较高,需达到微秒级,则一般需用汇编语言编程,若只需达到秒或毫秒级,则用C语言编程就可满足要求。
==》作为预备知识,建议先了解下机器周期、数据类型和存储器类型,可以参照
机器周期:http://www.51hei.com/bbs/dpj-43300-1.html
数据类型:http://www.51hei.com/bbs/dpj-43301-1.html
存储器类型:http://www.51hei.com/bbs/dpj-43302-1.html
==》下面先介绍汇编语言编程
根据定时时间长度可以编制不同循环重数的程序。
===》单循环延迟程序
MOV R7,#TIME
LOOP:NOP 1机器周期
NOP 1机器周期
DJNZ R7,LOOP 2机器周期
延迟时间=4 X T X TIME
以常见的12M晶振为例,则一个机器周期T=1us
因为R7是8位寄存器,所以TIME只能为char型,其值域为0~255
则定时范围为 4us~1020us
===》双循环延时程序
MOV R7,#TIME1 1机器周期
LOOP1:MOV R6,#TIME2 1机器周期
LOOP2:NOP 1机器周期
NOP 1机器周期
DJNZ R6,LOOP2 2机器周期
DJNZ R7,LOOP1 2机器周期
延时时间=(TIME2 X 4 +2+1) X TIME1 X T+T
定时范围为 8us~260 866us
===》三重循环延时程序
MOV R7,#TIME1 1机器周期
LOOP1:MOV R6,#TIME2 1机器周期
LOOP2:MOV R5,#TIME3 1机器周期
LOOP3:NOP 1机器周期
NOP 1机器周期
DJNZ R5,LOOP3 2机器周期
DJNZ R6,LOOP2 2机器周期
DJNZ R7,LOOP1 2机器周期
延迟时间=((TIME3 X 4 +2+1) X TIME2 +2+1) X TIME1 X T +T
定时范围为 11us~66 521 341us
根据需要还可以编写4重5重或更多重程序,满足不同延时需要。
==》C语言编程
C语言中通过循环结构的程序达到延时的目的,还可以通过循环嵌套满足不同的定时要求,常用循环语句有以下三种:
while(表达式){语句;}
do{语句;}while(表达式)
for(表达式1;表达式2;表达式3){语句;}
我是通过keil仿真时数汇编指令的数目来确定循环语句执行时间的(我不知道是不是还有更好的方法),结果如下:
====》while语句
下面的例子可以不看,后面跟着结果。
例子:int i; while(i<1000); {i++;}
keil编译成的汇编代码循环执行段为:
循环代码 消耗的机器周期
C:0x0003 C3 CLR C 1
C:0x0004 E509 MOV A,0x09 1
C:0x0006 94E8 SUBB A,#0xE8 1
C:0x0008 E508 MOV A,0x08 1
C:0x000A 6480 XRL A,#P0(0x80) 1
C:0x000C 9483 SUBB A,#DPH(0x83) 1
C:0x000E 500A JNC C:001A 2
5: {i++;}
C:0x0010 0509 INC 0x09 1
C:0x0012 E509 MOV A,0x09 1
C:0x0014 70ED JNZ main(C:0003) 2
根据每条指令的机器周期可以确定,循环一次消耗的机器周期数为:12个
依然以12M晶振为例,每个机器周期为1us,则循环一次耗时12us,循环一千次耗时12 000us
(signed int)i 能取到的最大值为32767,所以此循环语句的定时范围为10us~393 204us
====》do while 语句
同样例子后面有结果,可以不看例子。
例子: int i=10; do{i--;} while(i>0);
keil编译的汇编程序循环段代码:
循环段代码 消耗的机器周期
C:0x0007 EF MOV A,R7 1
C:0x0008 1F DEC R7 1
C:0x0009 7001 JNZ C:000C 2
C:0x000B 1E DEC R6
5: while(i>0);
C:0x000C D3 SETB C 1
C:0x000D EF MOV A,R7 1
C:0x000E 9400 SUBB A,#0x00 1
C:0x0010 EE MOV A,R6 1
C:0x0011 6480 XRL A,#P0(0x80) 1
C:0x0013 9480 SUBB A,#P0(0x80) 1
C:0x0015 50F0 JNC C:0007 2
循环一次消耗的机器周期数:12个
晶振12M,i 最大值32767,定时范围:10us~393 204us
====》for语句
例子: int i; for(i=1000;i>0;i--);
循环段代码 消耗的机器周期
C:0x0007 EF MOV A,R7 1
C:0x0008 1F DEC R7 1
C:0x0009 7001 JNZ C:000C 2
C:0x000B 1E DEC R6
C:0x000C EF MOV A,R7 1
C:0x000D 4E ORL A,R6 1
C:0x000E 70F7 JNZ C:0007 2
循环一次消耗的机器周期数:8个
依然以12M晶振为例,则定时范围:6us~262 136us
for语句中,若 i 定义为 unsigned int ,则 i 的最大值可取65535,则定时范围:6us~524 280us