延时是怎样计算

[复制链接]
4420|26
 楼主| dingy 发表于 2011-8-2 19:54 | 显示全部楼层 |阅读模式
汇编的延时很理解,以晶振为时间基准算出机器周期然后让机器在那里空转,但是C呢?
 楼主| dingy 发表于 2011-8-2 20:00 | 显示全部楼层
//=================
void delay(uint k)
{
uint i,j;
for (i=0;i<k;i++)
  {
    for (j=0;j<121;j++)
     {;}
  }
}
//上面这个延时书中说是延时1ms

那么如果硬件不变的话下面这个是延时多少呢???

//-------------------------------------------------------------------
void delay_1ms(void)
{
uint k;
for(k=0;k<121;k++);   //很奇怪??为什么这里for语句后面没有了循环体了呢??
}
//难道这个也是1ms
renyaq 发表于 2011-8-2 20:05 | 显示全部楼层
拆看C编译后的汇编代码,算一下就OK了
zwll 发表于 2011-8-2 20:07 | 显示全部楼层
最好直接用硬件定时器,现在的单片机,定时器资源都很多
llljh 发表于 2011-8-2 20:09 | 显示全部楼层
俺有个简单的办法,用Keil的软仿。

一般这样用:
void delay( uint16_t ms ){ // 注意这个参数是ms,也就是毫秒
  uint8_t i;
  while( ms-- ){
    // 注意这个i =100,后面说明这个值怎么确定
    for( i=100; i!=0; --i ){;} // 这行要不要{}都行,但分号不能少
  }
}

用的时候这样用:
  delay(200); // 这就是延时200ms
  delay(20); // 这个延时是20ms
这样定义是不是可读性好一点?!


软件仿真前配置好晶振的数值!!!
主程序这样写
void main( void ){
  low_level_init(); // 低层初始化,最好打开需要的中断,如按键扫描,LED显示刷新等
  delay(1000);   // 在这行前定义一个断点,运行到这清一下软件仿真的计时器,在Keil窗口右下角
  。。。
  while(1);
}

Keil窗口右下角有个软件计时器,再次强调用前一定要设置好晶振的数值
运行delay(1000)前,Reset Watch1, 然后单步运行delay(1000),再看一下Watch1的数值,算一下结果差多少,
修改一下delay程序中的i=100一句,再重新编译一下,重新来过

这个办法的好处是可以把中断的时间影响一起加进去,比单纯的手工算周期更准一些,也不容易出错,但是:

一定要注意CPU的型号,一般只对12分频的标准8051核的好用,比如W79E4051是4分频的,这个办法就不能用了
supernan 发表于 2011-8-2 20:12 | 显示全部楼层
keil软件仿真的吧,不过精度值得商榷
juventus9554 发表于 2011-8-2 20:14 | 显示全部楼层
void delay(uint z)
{
    uint x,y;
    for(x=z;x>0;x--)
        for(y=110;y>0;y--);
pengf 发表于 2011-8-3 09:42 | 显示全部楼层
C的延时,用汇编来算的,写一段C延时,在看看翻译成汇编计算时间
supernan 发表于 2011-8-3 09:46 | 显示全部楼层
一般情况下,我是编译后看汇编代码计算时间。
zwll 发表于 2011-8-3 09:49 | 显示全部楼层
外接个引脚,示波器测下波形就知道了!
司徒老鹰 发表于 2011-8-3 10:02 | 显示全部楼层
嗯,我也是拿示波器
pengf 发表于 2011-8-3 10:12 | 显示全部楼层
这两段显然不一样嘛,第一段是嵌套循环,延时更长点。后面那个没有循环体也没什么,执行判断和自加不就行了~!
chuxh 发表于 2011-8-3 10:17 | 显示全部楼层
实际上,用while(--i)比较好一些,具体原因看反汇编。
llljh 发表于 2011-8-3 10:28 | 显示全部楼层
时序严格的时候建议用for循环进行延时,精确,可控。
for(i=x;i>0;i--);
延时时间为(2*i+1 ) us
ms级的延时建议采用一个带形参的延时函数,然后用keil的软仿真进行调试即可。
当然嵌入汇编语言进行延时是最好的一种形式
栩栩如生 发表于 2011-8-3 10:51 | 显示全部楼层
//=================
void delay(uint k)
{
       uint i,j;
       for (i=0;i<k;i++)
      {
             for (j=0;j<121;j++)
             {;}
      }
}
//上面这个延时书中说是延时1ms

可以简写成这样:
void delay(uint k)                    //这里不是延时1ms,而是毫秒级延时,至于延时多少毫秒,要看K。
{                                             //这个延时可能是根据Keil的软仿真得来的。
       uint i,j;                             //毫秒级别是怎么算来的呢?我猜想这里晶振可能是11.0592MHZ
       for (i=0;i<k;i++)               //根据51的12分频,指令周期大约为0.92us。
             for (j=0;j<121;j++);   //如果k=1,j=1。那么,两个for之间转换成汇编
}                                             //就会有两个INC,两个DNJZ等。所以,两个for可能有9个指令周期。
                               //如果K=1,那么:循环的时间=121*9*0.92=1000us=1ms

void delay_1ms(void)
{
       uint k;
       for(k=0;k<121;k++); //很奇怪??为什么这里for语句后面没有了循环体了呢??
}                                    //不用奇怪,你可以理解成:作者想怎么写就怎么写,你管不了。
                                    //程序是作者思路、思想 的体现。各有各的风格,以后你爱怎么写人家也不管你
              //一个for,大约有4个指令周期。所以循环的时间=121*4*0.92=450us(不是1ms)
supernan 发表于 2011-8-3 10:56 | 显示全部楼层
晶振12M:void delay()
                {
                   unsigned char a,b;
                   for(a=10;a>0;a--)
                     for(b=100;b>0;b--) ;      
                  }
jack_shine 发表于 2011-8-3 11:01 | 显示全部楼层
可以空转,也可以在这段时间干些别的事情
 楼主| dingy 发表于 2011-8-3 11:01 | 显示全部楼层
呵呵,真热闹,先结贴了,多谢大家
rulu 发表于 2011-8-5 13:59 | 显示全部楼层
都拿示波器呀
rulu 发表于 2011-8-5 13:59 | 显示全部楼层
您需要登录后才可以回帖 登录 | 注册

本版积分规则

745

主题

10920

帖子

6

粉丝
快速回复 在线客服 返回列表 返回顶部