【总结】延时程序

1. 概要

延时在嵌入式系统中,无处不在。延时的作用是等待固定的时间后,执行某个操作。
如,控制LED闪烁,如果延时很小或者没有延时,人眼无法看到闪烁的效果。

2. 原理

CPU在延时处理中,执行指定的时间。在时间未到之前,不能返回或被打断。

3. 实现方式

实现方法有两种:硬件延时,软件延时。

3.1. 软件延时

许多情况下,系统的定时器资源有限,或者用作其他用途,这时可以选择使用软件延时的方法。软件延时,通常使用循环体实现。

3.1.1. 汇编延时

汇编语言延时特点是准确,当是不灵活。

在软件中,每执行一条指令都是要消耗时间的。那么,一条指令的执行时间是确定的吗?对于时钟固定的系统,答案是肯定的。时钟是嵌入式系统的“小心脏”。以51单片机12MHz晶振为例,12MHz的意思是单片机1s内可以执行(12M/12)=1M个机器周期,51单片机规定每个机器周期需要12个时钟震荡周期。换句话说,每个机器周期的时间=1/1M=1um。不同的汇编指令,消耗的时间是机器周期的整数倍。

指令 功能 机器周期数 时间(um)

MOV     数据传送    1   1
NOP     空操作 1   1
DJNZ    循环移位    2   2
LCALL   调用      2   2
RET     返回  2   2

因此,使用汇编语句可以实现很精确的延时。汇编实例分析,50ms延时子程序

DEL :    MOV R7, #200    ①
DEL1:    MOV R6, #125    ②
DEL2:    DJNZ R6, DEL2   ③
         DJNZ R7, DEL1   ④
         RET             ⑤

①:MOV R7, #200 ,单周期指令,执行一次,时间1us
②:MOV R6, #125,单周期指令,由于④,循环执行200次,时间200us
③:DJNZ R6, DEL2,双周期指令,由于②和④,循环执行125*200次,时间2*125*200us
④:DJNZ R7, DEL1,双周期指令,由于①,循环执行200次,时间2*200us
⑤:RET,双周期指令,只执行一次,时间2us

总时间=①+②+③+④+⑤=1+200+2*125*200+2*200+2=50603≈50ms

3.1.2. C 语言延时

C 语言实现的延时程序就相对灵活一些。
C 语言最终编译为汇编语言,就可以知道程序的执行时间了。

可以在C文件中使用NOP()语句实现。(假设:晶振12MHz,一个机器周期1us.)
例1:

void delay_10us(void)
{
    _NOP_();
    _NOP_();
    _NOP_();
    _NOP_();
    _NOP_();
    _NOP_();
}

分析:上面函数中使用了6个NOP()语句,每句执行时间为1us;调用delay_10us函数时,执行LCALL指令(2个机器周期,2us),函数退出时执行RET指令(2个机器周期,2us),执行该函数共消耗10us时间。

例2:

void delay(unsigned char n)
{
    while(--n);
}

如果调用delay(1),keil C对应的汇编代码为

C:0x0005 7F01 MOV R7,#0x01
C:0x0007 111D ACALL delay1(C:001D)
C:0x001D DFFE DJNZ R7,delay1(C:001D)
C:0x001F 22 RET

分析:传递参数1,函数调用2,函数返回2,此三个为固定开销,还有DJNZ的2个
实际延时= 1+2+2+n*2

例3:

void delay_500_ms(void)
{
    unsigned char i, j, k;
    for(i =  15; i > 0; i--)
        for(j = 202; j > 0; j--)
            for(k = 81; k > 0; k--);
}

对应的汇编代码

DEL:  MOV R7, #15
DEL1: MOV R6, #202
DEL2: MOV R5, #81①
      DJNZ R5, $①
      DJNZ R6, DEL2
      DJNZ R7, DEL1
      RET

分析:
一层循环n:R5*2 = 81*2 = 162us DJNZ 2us
二层循环m:R6*(n+3) = 202*165 = 33330us DJNZ 2us + R5赋值 1us = 3us
三层循环: R7*(m+3) = 15*33333 = 499995us DJNZ 2us + R6赋值 1us = 3us
循环外: 5us 子程序调用 2us + 子程序返回 2us + R7赋值 1us = 5us
延时总时间 = 三层循环 + 循环外 = 499995+5 = 500000us =500ms
计算公式:延时时间=[(2*R5+3)*R6+3]*R7+5

3.1.3. 软件延时步骤

  1. 确定系统时钟
  2. 计算指令周期
  3. C语言,分析对应的汇编代码
  4. 根据指令消耗的机器周期数,计算延时时间

3.2. 硬件延时

硬件延时就是使用定时器了。

对于晶振12MHz,一个机器周期1us的51单片机而言,最长的延时时间为216=65536us,若定时器采用工作方式2,可以实现精确延时。步骤,配置定时器工作方式,设置计数值,启动定时器,等待溢出,停止计数器。

void delay_1ms(void)
{
    TMOD = 0x01;      /*定时器0工作在模式1下(16位计数器)*/
    TH0 = 0xfd;       /*(65536-1000)/256*/
    TL0 = 0x65;       /*(65536-1000)%256*/

    TR0 = 1;          /*启动定时器*/
    while(TF0 == 0);  /*计数器溢出后TF0由0变1*/
    TR0 = 0;          /*停止定时器*/
}

65.536ms内的延时程序

void delay_us(int n)
{
    TMOD = 0x01;
    TH0 = (65536-n)/0xff;
    TL0 = (65536-n)%0xff;
    TR0 = 1;
    while(TF0 == 0);
    TR0 = 0;
}

3.2.1 硬件延时步骤

  1. 选择定时器
  2. 配置定时器工作方式
  3. 计算计数值,设置相关寄存器
  4. 启动定时器
  5. 等待溢出
  6. 停止定时器

参考

单片机延时方法总结
51单片机Keil C延时程序的简单研究

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值