12tangyang12 发表于 2012-7-27 21:20:55

求指点---有关延时函数形参的问题

本帖最后由 12tangyang12 于 2012-7-28 11:03 编辑

今天在调试的时候偶然间发现一个问题,延时函数 形参类型不一样 对延时的时间竟然也有影响的,下面先把程序打包上传36903。
下载附件慢的朋友 可以直接看, 我把源码 贴出来吧


#include<reg52.h>
#define uint unsigned int
#define uchar unsigned char

void Delay_char(char del)
{
        while(del--);
}

void Delay_uchar(uchar del)
{
        while(del--);
}

void Delay_int(int del)
{
        while(del--);
}
void Delay_uint(uint del)
{
        while(del--);
}

void main(void)
{
        while(1)
        {
                Delay_char(100);        //需要0。66298ms
                Delay_uchar(100);        //需要0。66298ms
                Delay_int(100);                //需要0。993ms
                Delay_uint(100);        //需要0。993ms

        }
}

12tangyang12 发表于 2012-7-27 21:31:32

程序中 我定义了 四个延时函数,四个函数唯一的区别就是 形参 的类型 不一样 , 分别是 charunchar int 和 uint。 接着 在主函数中调用它们。 为了使 循环的次数一样 , 我们输入的形参 是100 , 这样都能满足 charuncharint uint 数据类型。 在调试前 设置 晶振 11.0592Mhz    通过设置断点 调试后 发现当 延时函数 的 形参类型是 char 和 uchar 时竟然和inuint延时的时间不一样。 怎么会这样呢? 不得其解, 希望 各路大大指点指点

lcw_swust 发表于 2012-7-27 22:34:02

那是因为C转为汇编后,代码都不一样了,建议楼主看看编译后的汇编代码。
函数传递参数时,一个字节的参数和两个字节的参数肯定是不一样的。
做加法时,8位的加法和16位的加法是不一样的。

12tangyang12 发表于 2012-7-28 08:14:10

lcw_swust 发表于 2012-7-27 22:34 static/image/common/back.gif
那是因为C转为汇编后,代码都不一样了,建议楼主看看编译后的汇编代码。
函数传递参数时,一个字节的参数和 ...

thankyou

12tangyang12 发表于 2012-7-28 13:07:45

今天仔细调试了一下,又发现了个新的问题。 先把源程序 贴出来。
#include<reg52.h>
#define uint unsigned int
#define uchar unsigned char

void Delay_char(char del)
{
        while(del--);
}

void Delay_uchar(uchar del)
{
        while(del--);
}

void Delay_int(int del)
{
        while(del--);
}
void Delay_uint(uint del)
{
        while(del--);
}

void main(void)
{
        while(1)
        {

                Delay_char(10);                        //75.954 us
                Delay_char(50);                        //336.37us
                Delay_char(100);                //661.89us

                Delay_uchar(10);                //75.964us
                Delay_uchar(50);                //336.37us
                Delay_uchar(100);                //661.89us

                Delay_int(10);                        //112.85us
                Delay_int(50);                        //503.47us
                Delay_int(100);                        //991.75us

                Delay_uint(10);                        //112.85us
                Delay_uint(50);                        //503.47us               
                Delay_uint(100);                //991.75us

                P0=0x00;
        }
}
在程序中,就拿 Delay_uchar(uchar del);这个函数举例吧,
当形参是 10的时候 整个函数执行的时间是 75.964us
当形参是 50 的时候按照倍数关系 执行的时间 应该是 75.964 X 5 = 379.82us可是通过调试 测出执行的时间是 336.37us -   将近比预计的时间快了 43.45 us   这个误差 在精确延时中不容忽视了已经。
我们再看看 当 100的时候 , 100的时候执行整个函数 需要 661.89us而 我们通过倍数关系应该是 75.964us的10倍 =759.64 , 和实际延时 相差了 97.75us这次 误差更大了。
这个是什么原因造成的呢? 这个难道延时的时间不能通过 执行一次需要的时间乘以执行的次数 算吗??
程序 我也打包上传了。虽然是 us 级别的误差。但是在 DS18B20 这样对时序要求严格的元器件 这样的误差足以导致不能产生正确的时序了。。。。
哪位 大大 能够 指点 指点?鄙人真想不明白了

BXAK 发表于 2012-7-28 13:35:10

从 汇编 过度到 C 就不会这样的疑问。
通过keil编译后看汇编代码,对照51指令表,将下面这个延时函数的延时时间公式推导出来就明白:虽然形参del越大 延时时间就越长,但两者并不是正比关系
void Delay_uchar(uchar del)
{
      while(del--);
}

觉得麻烦的话,建议直接用“单片机小精灵”(论坛有,自己搜搜),输入参数 直接生产 精确的延时函数

614229816 发表于 2012-7-28 20:16:06

第一个问题显然8位加法和16位加法运算速度不一样,
第二个问题你可以看看这个
****************C语*******************/
void delay(uint delaytime)
{
       while(delaytime--);
}

/****************汇编******************/

C:0x0840      EF          MOV             A,R7                                        //1个机器周期
C:0x0841      1F          DEC            R7                                           //1个机器周期
C:0x0842      AC06      MOV             R4,0x06                                 //1个机器周期
C:0x0844      7001      JNZ               C:0847                                    //2个机器周期
C:0x0846      1E          DEC            R6                                          //1个机器周期
C:0x0847      4C          ORL            A,R4                                       //1个机器周期
C:0x0848      70F6       JNZ            delay(C:0x0840)                     //2个机器周期
C:0x084A      22          RET                                                         //2个机器周期
/**************************************/
运行时间(周期):
8*[(R7+1)+256*R6]+1*R6+2
平均时间约为8个机器周期
占用资源:ACC,R4,R6,R7

614229816 发表于 2012-7-28 20:18:31

/****************C语*******************/
void delay(uint delaytime)
{
       while(delaytime--);
}

/****************汇编******************/

C:0x0840      EF          MOV             A,R7                                        //1个机器周期
C:0x0841      1F          DEC            R7                                           //1个机器周期
C:0x0842      AC06      MOV             R4,0x06                                 //1个机器周期
C:0x0844      7001      JNZ               C:0847                                    //2个机器周期
C:0x0846      1E          DEC            R6                                          //1个机器周期
C:0x0847      4C          ORL            A,R4                                       //1个机器周期
C:0x0848      70F6       JNZ            delay(C:0x0840)                     //2个机器周期
C:0x084A      22          RET                                                         //2个机器周期
/**************************************/
运行时间(周期):
8*[(R7+1)+256*R6]+1*R6+2
平均时间约为8个机器周期
占用资源:ACC,R4,R6,R7


/**************************************/



/****************C语*******************/
void delay(uint delaytime)
{
       while(--delaytime);
}

/****************汇编******************/

C:0x0840      EF          MOV             A,R7                                       //1个机器周期
C:0x0841      1F          DEC            R7                                          //1个机器周期
C:0x0842      7001      JNZ               C:0845                                 //2个机器周期
C:0x0844      1E          DEC            R6                                       //1个机器周期
C:0x0845      14          DEC            A                                          //1个机器周期
C:0x0846      4E          ORL            A,R6                                    //1个机器周期
C:0x0847      70F7       JNZ            delay(C:0x0840)                      //2个机器周期
C:0x084A      22          RET                                                          //2个机器周期
/**************************************/
运行时间(周期):
6*(R7+256*R6)+1*R6+2
平均时间约为6个机器周期
占用资源:ACC,R6,R7


/**************************************/




/****************C语*******************/
void delay(uint delaytime)
{
       for(;delaytime==0;--delaytime);
}

/****************汇编******************/

C:0x0840      EF          MOV             A,R7                                        //1个机器周期
C:0x0841      4E          ORL            A,R7                                        //1个机器周期
C:0x0842      7007      JNZ               C:084B                                    //2个机器周期
C:0x0844      EF          MOV             A,R7                                       //1个机器周期
C:0x0845      1F          DEC            R7                                          //1个机器周期
C:0x0846      70F8      JNZ               delay(C:0x0840)                     //2个机器周期
C:0x0848      1E          DEC            R6                                          //1个机器周期
C:0x0849      80F5      SJMP             delay(C:0x0840)                     //2个机器周期
C:0x084B      22          RET                                                         //2个机器周期
/**************************************/
运行时间(周期):
4+8*(R7+256*R6)+3*R6+2
平均时间约为8个机器周期
占用资源:ACC,R6,R7


/**************************************/
void delay(uint delaytime)
{
       for(;delaytime==0;delaytime--);
}
同上一样 for(;delaytime==0;--delaytime);。
/**************************************/
页: [1]
查看完整版本: 求指点---有关延时函数形参的问题