• 51单片机延时计算

    2019-01-28 09:34:13
    51单片机延时计算前言正文首先是时钟周期的算法:时钟周期(T)=1(秒)/晶振频率。(比如:上面代码的时钟周期为1/12M(秒))。其次是机器周期:机器周期是由时钟周期组成的,机器周期是单片机完成一个基本操作...

    前言

    我使用51,STC这一类的单片机做控制好几年,一直是使用现成的程序,在其上修修改改,以达到需求动作目的即可。从来都是不求甚解。想法既是如此,会用即可,了解那么多做什么。
    此次又在做一项目,里面用到I2C通讯。本来是直接复制粘贴了事,却没想对里面的一个小小的延时函数起了兴趣,由于本人是基础功底只有5战斗力的渣渣,写写画画了一天才搞了个大体明白。
    以前总是在看其他博主的文章,默默潜水。然而此次,突然就忍不住想写篇文章发表一下费尽心思的微不足道的心得体会。

    正文

    void Delay10us()		//@12.000MHz
    {
    	unsigned char i;
    
    	_nop_();
    	_nop_();
    	i = 27;
    	while (--i);
    }
    

    上面这段代码是用STC-ISP软件中的软件延时计算器给出的,选用的是8051指令集STC-Y5,延时10us。
    以前都是直接这么拿来用的,今天却突然想搞个明白,为什么代码要这么写。

    于是查了各方资料。
    从单片机计时的源头找起,它由下面几部分依次组成。

    首先是时钟周期的算法:时钟周期(T)=1(秒)/晶振频率。

    (比如:上面代码的时钟周期为1/12M(秒))。
    这是单片机的基本时间单位。是由晶振震荡出来的,也叫震荡周期。

    其次是机器周期:机器周期是由时钟周期组成的,机器周期是单片机完成一个基本操作所需要的时间。

    关于机器周期,每种单片机可能都不太一样,我也只用过传统51和STC这两款,就拿此来对比下

    1 传统的8051单片机:

    它的1个机器周期是由12个时钟周期组成的。
    以12M晶振举例,它的一个机器周期就是:12(个时钟周期)*1(秒)/12MHz = 1(us)

    2 STC单片机:

    拿我常用的STC12C5A60S2这款单片机来讲,它可以有两个模式选择,
    一个是1T模式,在这个模式下STC单片机1个时钟周期就是1个机器周期;
    另一个是12T模式,这个模式下STC单片就和传统的8051单片机一样,12个时钟周期组成1个机器周期。
    由此可见1T模式的速度就是12T模式的12倍。
    以12M晶振为例,1T模式下就可以算得机器周期是:
    1(个时钟周期)*1(秒)/12Mhz = 1/12(us)

    最后是指令周期:这个是单片机执行一条指令所需要的时间,它是由机器周期组成的。

    现在可以回到正文开头的代码中了。这个10us的函数是怎么得出来的呢?
    这个我之前查过很多资料,比如执行while语句需要多少个机器周期。赋值需要多少个周期。也就是查这个占用了我很大一部分时间。直到最后将上面的延时函数直接调到main函数中debug调试,才明白,问题其实很简单啊。
    无论是执行什么语句,最终都会回到汇编上来,debug里单步调试,所有的指令周期就会明明白白了。
    我用main函数直接调用延时函数,如下:

    void Delay10us()		//@12.000MHz
    {
    	unsigned char i;
    
    	_nop_();
    	_nop_();
    	i = 27;
    	while (--i);
    }
    main
    {
        Delay10us();
    }
    

    我用的keil软件,将上述build之后,点击debug,开始调试
    .在这里插入图片描述
    看图片上,开始debug,程序的起始就在C:0x0183 020171 LJMP Delay10us(C:0171),
    这里有个长转移指令LJMP,它要转移到C:0171行去执行Delay10us这个函数。
    那执行LJMP这个指令需要多长时间呢,查找STC数据手册,在1T模式下,此条指令在单片机上运行需要4个时钟周期。
    接下来,按单步调试F11键,如下图:
    在这里插入图片描述
    程序成功转移到C:0171行,跳转到Delay10us函数中,此行程序执行NOP指令,空操作。查STC数据手册,NOP指令占用1个时钟周期。
    接下来C:0172行,依然是NOP指令,1个时钟周期。
    接下来C:0173行,此行执行 MOV R7,#0x1B,将立即数送入寄存器。是将27赋值给i。依然查手册,此条指令2个时钟周期。
    继续:
    在这里插入图片描述
    此时执行到while语句了,这里执行的指令时 DJNZ R7,C:0175,寄存器减1非0转移。此条指令执行1次4个时钟周期。
    上面已经将寄存器填入27了,因此这条指令将执行27次。
    继续:
    在这里插入图片描述
    循环了27次,终于到0了,程序继续向下执行,此行指令RET,子程序返回。此条指令4个时钟周期。
    继续:
    在这里插入图片描述
    程序又回到了起点。
    好了,可以计算一下此次延时的时间了。1个LJMP,4时钟;2个NOP,2时钟;1个MOV,2时钟;27个DJNZ,108时钟;1个RET,4时钟。
    4+2+2+108+4=120。
    单片机的时钟周期是:1(S)/12MHz = 1/12(us)
    此次延时的时间是:120 × 1/12(us)= 10(us)

    总结

    其实并没有绝对的准确延时,上面只是理想化的状态,单片机的中断或者其他事件都可能影响到延时的。
    另外,同样的STC单片机,同样的延时10us,同样的1T,官方给出的STC12系列和STC15系列的延时函数就不一样,STC12系列在延时函数内部要少两个NOP指令。debug对比,也是少量NOP,其他都一样。按照12系列和15系列的手册描述,他们的指令周期是相同的。那么他们的差别在哪?单片机内部结构的问题还是官方错误造成的误差?
    各位大神若有知晓的望请告知。不胜感激。

    展开全文
  • 1.代码 #include void delay(int t){ for( ;t!=0; t--); } void main() { unsigned int i; unsigned int istay=9; int step[4]; step[0]=3; //0011 step[1]=6; //0110 step[2]=12;... /

    1.代码

    #include<reg52.h>
    
    void delay(int t){
    	for( ;t!=0; t--);
    }
    
    void main()
    {
    unsigned int i;
    	unsigned int istay=9;
    	int step[4];
    	step[0]=3;  //0011
    	step[1]=6;  //0110
    	step[2]=12; //1100
    	step[3]=9;  //1001
     
    while(1)
    	{  
    		for(i=0;i<4;i++)
    		{
    	    	P2=step[i];
    			delay(istay);
    		}
    	
    
    }
    }


    2. 编译后的混合模式(mixed mode)





    3.撇开main函数的主体部分,先直接找到delay函数主体,其汇编代码为

        22:                         delay(istay); 
    C:0x0829    AF05     MOV      R7,0x05
    C:0x082B    AE04     MOV      R6,0x04
    C:0x082D    12083D   LCALL    delay(C:083D)

    上面将0x05送到R7,0X04送到R6.



         3: void delay(int t){ 
         4:         for( ;t!=0; t--); 
    C:0x083D    EF       MOV      A,R7
    C:0x083E    4E       ORL      A,R6
    C:0x083F    6007     JZ       C:0848
    C:0x0841    EF       MOV      A,R7
    C:0x0842    1F       DEC      R7
    C:0x0843    70F8     JNZ      delay(C:083D)
    C:0x0845    1E       DEC      R6
    C:0x0846    80F5     SJMP     delay(C:083D)
         5: } 
    C:0x0848    22       RET         


    .

    待完成。。。


    展开全文
  • 设51系列单片机晶振频率Fosc为12MHz,则每个机器周期 =12/Fosc =1μs, 每条MOV Rn,#data指令耗用1个机器周期,每条DJNZ Rn,rel指令耗用2个机器周期,每条NOP指令执行耗用1个机器周期
  • 先贴上程序#include #define uchar unsigned char void Delay(uchar); //主程序 void main() { while(1) { Delay(10);//调用延时 ...//延时子程序 ...}这个延时程序由来已久,它的延时可以被精确计算。先来

    先贴上程序

    #include<reg52.h>
    #define uchar unsigned char
    void Delay(uchar);
    //主程序
    void main()
    {
      while(1)
      {
        Delay(10);//调用延时
      }
    
    }
    //延时子程序
    void Delay(uchar t)
    {
      while(--t);
    }

    这个延时程序由来已久,它的延时可以被精确计算。先来看看这段程序的反汇编代码,延时程序的调用就是按图中顺序来执行的。
    解读:
    C:0x000F 指令地址
    7F0A 指令的二进制编码(参考单片机指令系统)
    MOV R7, #0x0A 指令内容

    这里写图片描述

    1.参数传递(MOV,1机器周期,相关内容参考指令系统)
    2.长调用(LCALL,2机器周期)
    3.函数体(循环执行 DJNZ t次,每次2机器周期)
    4.子程序返回(RET,2机器周期)

    执行一条指令的时间,定义为指令周期。每条指令可能分若干步骤完成,每个步骤定义为一个基本操作,一个基本操作的时间定义为机器周期。
    一个机器周期占用6个状态周期(参考《微机原理与接口技术》),每个状态周期占用2个时钟周期。
    一个时钟周期=1/晶振频率。以12M晶振为例,一个时钟周期Tc=1/12 微秒。
    总延时T=(1+2+2*t+2)*12*Tc=12*Tc*(2*t+5) us.

    以上计算都是基于传统8051单片机系统。
    现在的8051单片机在汇编指令执行效率方面有很大改进,取消了机器周期的概念,指令执行均以时钟周期来计量。
    比如下图,截取的是STC15系列单片机与传统8051单片机指令耗时的对比数据。以MOV Rn,#data 为例,传统8051耗时12时钟,而STC只用2个时钟周期就完成了指令。
    因此,对于延时的计算,不同的单片机会有不同的结果。

    另外,while(t--)while(--t)的延时是完全不同的,同一单片机,前者的延时大于后者。

    这里写图片描述

    展开全文
  • 单片机\51系列单片机延时程序运行时间计算方法.发到网上供单片机爱好者学习用
  • 51单片机延时计算

    2018-04-04 00:09:32
    51单片机延时计算 51单片机延时计算 时钟周期 机器周期 延时计算 时钟周期 若时钟晶振的振荡频率为fosc,则振荡周期 Tosc=(1/fosc)。 如:晶振频率为12MHZ,则振荡周期 Tosc=(1/12us)。 ...

    51单片机延时计算


    时钟周期

    若时钟晶振的振荡频率为fosc,则振荡周期 Tosc=(1/fosc)。
    
    如:晶振频率为12MHZ,则振荡周期 Tosc=(1/12us)。
    

    机器周期

    对于不同的芯片采用的机器周期各不相同,主要分为:12T、6T、4T、1T等等。
    
    如51系列单片机常见的12T机器周期,每个机器周期占用时间为(12 * 时钟周期)。
    
    依此类推,6T占用的时间为(6 * 时钟周期)。
    

    延时计算

    对于语句:
    
        for(a=n;a>0;a--); 
    其延时的大小计算如下:
    
         delay_time = [(a*2)+3] * 机器周期
    
    但准确的说要加上延时程序调用时间:
    
        delay_time = ([(a*2)+3] + 5) * 机器周期
    

    例如 :晶振为12MHz、时钟周期为12T的单片机,下面for循环语句:
    
           for(a=50;a>0;a--)
               for(b=10;b>0;b--);
    其延时为:
    
        delay_time = [(10*2 +3)*50+3]*(1/12)*12 us = 1153us
    
    最后 再加上 5us * 12/12us 程序调用延时的时间
    
    其中 1/12 为晶振决定的机器周期,最后面的 12 是指时钟周期为 12T。
    
    // 部分常用的延时程序
    #define u8 unsigned char
    /*
        小于4us的延时直接使用_nop_();实现
    */
    
    void delay_1ms()
    {
        u8 a,b;
        for(a=142;a>0;a--)
            for(b=2;b>0;b--);
        _nop_();
    
    }
    
    void delay_10us()
    {
        u8 a,b;
        for(a=1;a>0;a--)
            for(b=1;b>0;b--);
    
    }
    
    
    void delay_1s()
    {
       u8 a,b,c;
       for(c=46;c>0;c--)
        for(b=152;b>0;b--)
          for(a=70;a>0;a--);
       _nop_(); 
    
    }

    展开全文
  • 单片机提供时钟脉冲信号的振荡源的周期 T=1/f 状态 振荡周期经二分频后得到的 2T 机器 在一个机器周期内,CPU可以完成一个独立的操作 12T 指令 指CPU完成一条操作所需的全部时间 12-12nT 指令: 1、MUL、...

    几种周期介绍




    周期名称 描述 时间
    振荡(时钟) 单片机提供时钟脉冲信号的振荡源的周期 T=1/f
    状态 振荡周期经二分频后得到的 2T
    机器 在一个机器周期内,CPU可以完成一个独立的 操作 12T
    指令 指CPU完成一条操作所需的全部时间 12-12nT

    指令:

    1、MUL、DIV:仅有的4周期指令

    2、包含DPTR和PC的指令均为2周期指令

    3、所有的绝对跳转和条件转移指令,均为2周期指令

    4、所有包括A寄存器的指令,均为单周期指令

    5、位操作指令中,ANL和ORL是2周期指令

    6、所有包含立即地址的指令,除INC direct及DEC direct外,均为2周期指令

    7、剩下的均为单周期指令。



    STC-ISP软件查看各操作用时以及延时函数




    _nop_函数可以在keil软件的C51->HLP->C51lib.chm文档中查阅  (授人以鱼不如授人以渔)




    延时函数计算


    示例:

    void delay(uint z)
    
    {
    
    	uint i,j;
    
    	for(i=z;i>0;i--)
    
    		for(j=0;j<921;j++);
    
    }

    分析:

    1.先计算你单片机的振荡(时钟)周期 T= 1/晶振(11.0592MHZ)

    2.一次i--操作为12T

    3.忽略变量定义,上述延时函数共需时间:921*z*12T

    4.带入T:921*12*T*z 约为 z ms



    计算出现误差的原因


    1.软件仿真时,函数调用的时候入栈出栈操作的耗时。

    2.指令周期随指令的不同而不同导致的误差。

    3.中断的影响。

    4.变量的范围超过,从而与预计时间不一样。


    所以实际上我们应该只能算出估计值,根据最开始周期的信息来计算延时函数中延时的时长。

    展开全文
  • 1、如果单片机采用delay函数来进行...2、可以采用定时器来记录延时时间,在定时器来计算时间的期间,单片机可以处理其他事情,等计时时间到了之后,再来处理延时之后的事情。如果程序中有多个地方需要用到延时,单...
  • 单片机的基本时序 单片机的基本时序与《汇编语言》中讲的一致,分为振荡周期,时钟周期(状态周期),机器周期,指令周期...单片机延时的实现方式 软件实现 软件实现是指单片机连续多次执行同一条空语句。C语言中通...
  • 51单片机延时程序

    2013-03-28 19:31:13
    延时程序在单片机编程中使用非常广泛,但一些读者在学习中不知道延时程序怎么编程,不知道机器 周期和指令周期的区别,不知道延时程序指令的用法, ,本文就此问题从延时程序的基本概念、机器周期和指 令周期的区别...
  • 选取12M晶振时,时钟周期为(1 / 12) us,且假如单片机工作在12T模式下,则一个机器周期为12 * (1 / 12) = 1 us。 为表述方便,下文均用T_M表示机器周期,观察KEIL仿真运行时间具体如下: 进入Delay函数前运行时间...
  • 51单片机延时函数

    2017-10-16 17:02:51
    #include "reg52.h" //此文件中定义了单片机的一些特殊功能寄存器 typedef unsigned long u32; typedef unsigned int u16; //对数据类型进行声明定义 typedef unsigned char u8; /*定义变量及数组*/ u16 j=0;u...
  • 目前在单片机中有不少延时的方法: 1、使用循环函数延时: void delay1ms(void) //误差 0us,延时1ms {  unsigned char a,b;  for(b=199;b>0;b--)  for(a=1;a>0;a--); } 可以用单片机精灵来获取更多...
  • 延时与中断出错,是单片机新手在单片机开发应用过程中,经常会遇到的问题,本文汇总整理了包含了MCS-51系列单片机、MSP430单片机、C51单片机、8051F...1、单片机延时程序的延时时间怎么的? 答:如果用循环语句实现
  • 51单片机的定时器延时计算
  • 晶振频率:12M  (一)原程序: delay: mov r7,#200 ① d1: mov r6,#125 ② d2: djnz r6,d2 ③ djnz r7,d1 ④ ret ⑤ 分析过程: delay: mov r7,#200 r7=200
  • 单片机延时C语言程序

    2015-07-31 22:15:41
    (晶振12MHz,一个机器周期1us.)... 500ms延时子程序 程序:  void delay500ms(void){  unsigned char i,j,k;  for(i=15;i>0;i--)  for(j=202;j>0;j--)  for(k=81;k>0;k--); } 产生的汇编: C:0x0800 7F0F 
  • 在我们使用单片机的时候,很多情况下需要用到精确的延时。比如在跟DS18B20进行通讯的时候需要遵循严格的时序,这就需要我们严格把控程序执行的时间。 一般我们都是通过执行空语句的方式来使程序延时。这种方法是用...
  • 以下为使用汇编代码产生的0.2s延时。关于汇编与C语言的延时更详细的问题推荐彭老师的文章“51系列单片机延时程序运行时间计算”。
  • 实现延时通常有两种方法:一种是硬件延时,要用到定时器/计数器,这种方法可以提高CPU的工作效率,也能做到精确延时;另一种是软件延时,这种方法主要采用循环体进行。 1 使用定时器/计数器实现精确...
1 2 3 4 5 ... 20
收藏数 4,846
精华内容 1,938