找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 7104|回复: 1
打印 上一主题 下一主题
收起左侧

单片机定时器延迟时间计算

[复制链接]
跳转到指定楼层
楼主
ID:104835 发表于 2016-2-2 03:29 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
关于时间单位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


分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:390416 发表于 2021-3-27 09:21 | 只看该作者
1、假设在同一个硬件上做测试,单片机CPU指令周期是一致的。那么 变量i、K,存放在data跟存放在XDATA,读写速度能一样?精确计算有意义吗?
2、假设都存放在data,延迟1ms只需要char类型的变量即可完成,但是,延迟100ms必须16位变量,那么执行时间还能照着公式去套算?
3、假设上述条件都一样,计算好的延迟时间是1ms并且误差1%,打开中断之后,延迟时间变成了5毫秒了。误差500%了,精确计算有意义吗?
4、假设上述条件不影响延迟时间,那么,编译器呢?谁敢说编译器不同的优化等级不影响delay的延迟时间?
5、还有硬件不同的情况,就需要重新计算了。比如晶振频率不同,CPU内核速度不同,STC8H单片机就比STC15快了很多了比89系列快了十几倍了。

所以,不要去精确的计算delay 延迟了多少时间,毕竟单片机的运行情况有很多变数。学会提高CPU的代码执行效率,是很有必要的!
“什么是单片机?咱玩的就是时间!”
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表