精确延时.docx

上传人:b****1 文档编号:2922549 上传时间:2023-05-05 格式:DOCX 页数:13 大小:19.73KB
下载 相关 举报
精确延时.docx_第1页
第1页 / 共13页
精确延时.docx_第2页
第2页 / 共13页
精确延时.docx_第3页
第3页 / 共13页
精确延时.docx_第4页
第4页 / 共13页
精确延时.docx_第5页
第5页 / 共13页
精确延时.docx_第6页
第6页 / 共13页
精确延时.docx_第7页
第7页 / 共13页
精确延时.docx_第8页
第8页 / 共13页
精确延时.docx_第9页
第9页 / 共13页
精确延时.docx_第10页
第10页 / 共13页
精确延时.docx_第11页
第11页 / 共13页
精确延时.docx_第12页
第12页 / 共13页
精确延时.docx_第13页
第13页 / 共13页
亲,该文档总共13页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

精确延时.docx

《精确延时.docx》由会员分享,可在线阅读,更多相关《精确延时.docx(13页珍藏版)》请在冰点文库上搜索。

精确延时.docx

精确延时

KEIL单片机C语言精确延时值的计算

2011-11-2020:

54|发布者:

pcb_dz|查看:

111|评论:

0|来自:

 关于单片机C语言的精确延时,网上很多都是大约给出延时值没有准确那值是多少,也就没有达到精确高的要求,而51hei给出的本函数克服了以上缺点,能够精确计数出要延时值且精确达到1us,本举例所用CPU为STC12C5412系列12倍速的单片机,只要修改一下参数值其它系例单片机也通用,适用范围宽。

 

共有三条延时函数说明如下:

函数调用分两级:

一级是小于10US的延时,二级是大于10US的延时

//====================小于10US的【用1US级延时】====================

//----------微秒级延时---------

for(i=X;i>X;i--)延时时间=(3+5*X)/12  提示(单位us, X不能大于255)

 

//================大于10US<小于21.9955Ms的可用【10US级延时函数】===========

voidDelay10us(ucharMs)

{

   uchardatai;

   for(;Ms>0;Ms--)                       

for(i=26;i>0;i--);

}

i=[(延时值-1.75)*12/Ms-15]/4

如想延时60US则 i=[(60-1.75)*12/6-15]/4=25.375≈26;修改i的值=26,再调用上面的【10US级延时函数】Delay10us(6);则就精确延时60US;

如果想延时64US可以用这二种函数组合来用:

Delay10us(6);for(i=9;i>X;i--) 共延时64US

 

//==============对于大于20Ms的可用中断来实现程序运行比较好===============

中断用定时器0,1Ms中断:

voidtimer0(void)interrupt1                                 

{                                                             

   TL0=(0xffff-1000+2)%0x100;TH0=(0xffff-1000+2)/0x100;//每毫秒执行一次

   if(DelayMs_1>0)DelayMs_1--;//大于20Ms延时程序 

}

函数调用

voidDelayMs(uinta)//延时a×1(ms)的时间。

{

   DelayMs_1=a;

   while(DelayMs_1);

}

如果延时50Ms则函数值为 DelayMs(50)

//+++++++++++++++++++++++++公式推算来由++++++++++++++++++++++++++++

二级延时C语言反汇编见上传图1:

//=======================STC单片机延时指令时间====================

 指今              时间(1us)              指今              时间(1us)

MOV  A  Rn      1                       SETB C            1

MOV  Rn #data    2                       SUBB A  #data    2 

DJNZ Rn rel      4

Dec  Rn           3                        SJMP rel           3

JC   rel           3                        MOV  Rndirect     4      

Lcalladdr16         6                        RET                4  

//--------------

JNZ                3                        XRL                2

SUBB              3  

 

使用Delay10us(ucharMs)最多能延时21995.5us;

其中循环外函数调用与返回用的时间=(6+4)进入+退出(1+1+2+3+,4)=10+11=21/12=1.75us;

循环内函数时间MS=Ms*(1+1+2+3,+2+4*I+3+3)/12=Ms*(15+4*I)/12;

所以如果延时60us时用【10US级延时函数】I的值为:

60=循环外时间+循环内时间=1.75us+Ms*(15+4*I)/12;

则i=[(60-1.75)*12/6-15]/4=25.375≈26即如果Ms=6,i=26;

本算法中的12是STC12单片机与普通标准速率比。

C语言写程序时,初学者遇到的一个难题时精确延时程序的设计。

我刚开始用C语言写程序时同样遇到了这个问题,后来参考了一些文章和实际设计后才知道了精确延时程序的设计。

   我现在就用两种方法来实现,一种是while()语句,另一种是for()语句,这两种语句均可产生汇编语句中的DJNZ语句,以12MHZ晶振为例(说明:

在编写C程序时,变量尽量使用unsignedchar,如满足不了才使用unsignedint):

   1.delay=99;while(--delay);

产生的汇编代码为:

000FH   MOV   08H,#63H

0012H   DJNZ   08H,0012H

这样产生的延时时间为:

(99+1)×2us。

最小延时时间为2us,若加上对delay赋值语句,则最小为4us。

 

   2.for(i=delay;i>0;i--);

产生的汇编代码同while()语句。

 

   下面来举例几个延时函数:

   一.500ms延时子程序

voiddelay500ms(void)

{

   unsignedchari,j,k;

    for(i=15;i>0;i--)

    for(j=202;j>0;j--)

    for(k=81;k>0;k--);

}

产生的汇编代码:

C:

0x0800   7F0F    MOV     R7,#0x0F

C:

0x0802   7ECA    MOV     R6,#0xCA

C:

0x0804   7D51    MOV     R5,#0x51

C:

0x0806   DDFE    DJNZ    R5,C:

0806

C:

0x0808   DEFA    DJNZ    R6,C:

0804

C:

0x080A   DFF6    DJNZ    R7,C:

0802

C:

0x080C   22      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

 

   二.200ms延时子程序

voiddelay200ms(void)

{

   unsignedchari,j,k;

   for(i=5;i>0;i--)

   for(j=132;j>0;j--)

   for(k=150;k>0;k--);

}

 

   三.10ms延时子程序

voiddelay10ms(void)

{

   unsignedchari,j,k;

   for(i=5;i>0;i--)

   for(j=4;j>0;j--)

   for(k=248;k>0;k--);

}

 

   四.1s延时子程序

voiddelay1s(void)

{

   unsignedcharh,i,j,k;

   for(h=5;h>0;h--)

   for(i=4;i>0;i--)

   for(j=116;j>0;j--)

   for(k=214;k>0;k--);

}

以上的这先希望对大家有帮组,如有不足之处请指出,如有更好的方法也可以告诉我,大家一起分享

C语言最大的缺点就是实时性差,我在网上到看了一些关于延时的讨论,其中有篇文章51单片机KeilC延时程序的简单研究,作者:

InfiniteSpaceStudio/isjfk

 写得不错,他是用while(--i);产生DJNZ来实现精确延时,后来有人说如果while里面不能放其它语句,否则也不行,用do-while就可以,具体怎样我没有去试.所有这些都没有给出具体的实例程序来.还看到一些延时的例子多多少少总有点延时差.为此我用for循环写了几个延时的子程序贴上来,希望能对初学者有所帮助.(晶振12MHz,一个机器周期1us.)

voidDelay(uchari)

{

 while(--i);

}

   21:

voidDelay(uchari)

   22:

{

   23:

        while(--i);

C:

0x001F   DFFE    DJNZ    R7,Delay(C:

001F)

   24:

}

 

    一.500ms延时子程序

程序:

    voiddelay500ms(void)

      {

      unsignedchari,j,k;

        for(i=15;i>0;i--)

        for(j=202;j>0;j--)

        for(k=81;k>0;k--);

      }

产生的汇编:

    C:

0x0800    7F0F    MOV      R7,#0x0F

    C:

0x0802    7ECA    MOV      R6,#0xCA

    C:

0x0804    7D51    MOV      R5,#0x51

    C:

0x0806    DDFE    DJNZ    R5,C:

0806

    C:

0x0808    DEFA    DJNZ    R6,C:

0804

    C:

0x080A    DFF6    DJNZ    R7,C:

0802

    C:

0x080C    22      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

    二.200ms延时子程序

程序:

voiddelay200ms(void)

{

      unsignedchari,j,k;

        for(i=5;i>0;i--)

        for(j=132;j>0;j--)

        for(k=150;k>0;k--);

}

产生的汇编

C:

0x0800    7F05    MOV      R7,#0x05

C:

0x0802    7E84    MOV      R6,#0x84

C:

0x0804    7D96    MOV      R5,#0x96

C:

0x0806    DDFE    DJNZ    R5,C:

0806

C:

0x0808    DEFA    DJNZ    R6,C:

0804

C:

0x080A    DFF6    DJNZ    R7,C:

0802

C:

0x080C    22      RET

    三.10ms延时子程序

程序:

voiddelay10ms(void)

{

      unsignedchari,j,k;

        for(i=5;i>0;i--)

        for(j=4;j>0;j--)

        for(k=248;k>0;k--);

}

产生的汇编

C:

0x0800    7F05    MOV      R7,#0x05

C:

0x0802    7E04    MOV      R6,#0x04

C:

0x0804    7DF8    MOV      R5,#0xF8

C:

0x0806    DDFE    DJNZ    R5,C:

0806

C:

0x0808    DEFA    DJNZ    R6,C:

0804

C:

0x080A    DFF6    DJNZ    R7,C:

0802

C:

0x080C    22      RET      

    四.1s延时子程序

程序:

voiddelay1s(void)

{

      unsignedcharh,i,j,k;

        for(h=5;h>0;h--)

        for(i=4;i>0;i--)

        for(j=116;j>0;j--)

        for(k=214;k>0;k--);

}

产生的汇编

C:

0x0800    7F05    MOV      R7,#0x05

C:

0x0802    7E04    MOV      R6,#0x04

C:

0x0804    7D74    MOV      R5,#0x74

C:

0x0806    7CD6    MOV      R4,#0xD6

C:

0x0808    DCFE    DJNZ    R4,C:

0808

C:

0x080A    DDFA    DJNZ    R5,C:

0806

C:

0x080C    DEF6    DJNZ    R6,C:

0804

C:

0x080E    DFF2    DJNZ    R7,C:

0802

C:

0x0810    22      RET

在精确延时的计算当中,最容易让人忽略的是计算循环外的那部分延时,在对时间要求不高的场合,这部分对程序不会造成影响.

设晶振频率为12M,单片机为AT89C51。

则知一个机器周期为1us。

现有延时函数如下:

    3:

voiddelay(void)

    4:

{

    5:

        unsignedchari,j,k;

    6:

        for(i=15;i>0;i--)

    7:

        for(j=202;j>0;j--)

    8:

        for(k=81;k>0;k--);

    9:

}

        以上就是利用C51语言编写的一个延时函数,下面这段代码则是利用keil软件翻译的一段汇编语言程序段,大家可以对照着看。

  

                                                                        机器周期数

C:

0x0800    7F0F      MOV      R7,#0x0F                1

C:

0x0802    7ECA    MOV      R6,#0xCA                1

C:

0x0804    7D51      MOV      R5,#0x51                1

C:

0x0806    DDFE    DJNZ    R5,C:

0806                2

C:

0x0808    DEFA    DJNZ    R6,C:

0804                2

C:

0x080A    DFF6    DJNZ    R7,C:

0802                2

C:

0x080C    22          RET                                          2

        通过上面的汇编语言程序段(0x0F=15,0xCA=202,0x51=81),我们可以计算出该延时子程序的具体延时时间:

Td=[(2×81+1)×202+202×2+1]×15+15×2+1+2

    =(163×202+405)×15+35

    =33331×15+33

    =499978us=499.978ms

        通过与C语言相比较,我们可以得出一个公式(对于C51,这个公式中的格式就跟上面的一样,数据类型必须是unsignedchar,而且是三重循环,延时函数不带任何形参):

    Td=[2×j×k+3×j+3]×i+3.....................①

        下面是调用了上面的延时函数的C51主函数,紧跟其后的汇编语言是利用keil软件翻译的一段汇编语言程序段。

    11:

voidmain(void)

    12:

{

    13:

        p10=1;

    14:

        while

(1)

    15:

        {

    16:

                p10=~p10;

    17:

                delay();

    18:

        }    

                                                                                  机器周期数

C:

0x0819    D290        SETB      p10(0x90.0)                    1

C:

0x081B    B290        CPL        p10(0x90.0)                    1

C:

0x081D    120800    LCALL    delay(C:

0800)                  2

C:

0x0820    80F9        SJMP      C:

081B                            2

        倘若我们需要一个带有形参的延时函数,方便在程序中根据不同的情形调用,延时时间不一致,我们的延时时间又如何计算呢?

下面我们来看看这个延时函数,跟上面的一样,只是把延时函数加了个形参,我们用同样的方法来计算它的延时时间。

    3:

voiddelay(unsignedchari)

    4:

{

    5:

        unsignedcharj,k;

    6:

        for(;i>0;i--)

    7:

        for(j=202;j>0;j--)

    8:

        for(k=81;k>0;k--);

    9:

}

                                                                          机器周期数

C:

0x800      EF          MOV      A,R7

C:

0x0801    D3          SETB      C

C:

0x0802    9400      SUBB      A,#0x00

C:

0x0804    400B      JC          C:

0811

C:

0x0806    7ECA      MOV      R6,#0xCA

C:

0x0808    7D51      MOV      R5,#0x51

C:

0x080A    DDFE    DJNZ      R5,C:

080A

C:

0x080C    DEFA    DJNZ      R6,C:

0808

C:

0x080E    1F          DEC        R7

C:

0x080F    80EF      SJMP      delay(C:

0800)

C:

0x0811    22          RET

        我们看看,R7的值是多少呢?

在下面,主函数里面,赋值为0x0F,就是15。

通过上面这段汇编程序段,我们用同样的方法来计算一下它的延时时间为(机器周期数请自己查阅书籍):

Td=[2×202×81+3×202+8]×15+3

    =[32724+614]×15+3

    =33338×15+3

    =500073us=500.073ms

由此,我们可以得出一个公式为:

    Td=[2×j×k+3×j+8]×i+3.....................②

下面是调用了voiddelay(unsignedchari)延时函数的main()函数机器汇编代码。

    11:

voidmain(void)

    12:

{

    13:

        p10=1;

    14:

        while

(1)

    15:

        {

    16:

       

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 法律文书 > 调解书

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2