这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 高校专区 » 坤创E-Geek/天科大新电社 » 延时函数的精确计算

共4条 1/1 1 跳转至

延时函数的精确计算

菜鸟
2015-01-26 18:24:15     打赏
 

延时函数的精确计算

利用for语句的延时特性,编写一个让一个发光二级管以间隔1S亮灭闪动的程序。

#include<reg52.h>

#define uint unsigned int

sbit led1=P1^0;

uint i,j;

void main()

 {

  while(1)

   {

      led1=0;

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

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

      led1=1;

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

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

   }

 }

简单的分析一下整个程序:点亮灯延时一会儿→关闭灯→延时一会儿点亮灯延时一会儿→关闭灯→延时一会儿……

下面来介绍如何用keil4来模拟出这个延时语句究竟是多长时间。打开keil4编辑界面,单击→【Target】→【XtalMHz)】

24.0改成12.0我的开发板是12.000MHZ),如图1所示。

 

                  1

Keil编译器在编译程序时,计算代码执行时间与晶振频率值有关,既然要模拟真实时间,那么软件模拟速度要与硬件一一对应。根据自己的实际情况来调整晶振值。

单击OK】后,再单击窗口上的调试快捷图标,进入软件模拟调试模式,如图2所示。

 

 

2

    在软件调试模式下,可以设置断点 、单步、全速、进入某个函数内部运行程序,同时还可以查看变换过程、模拟硬件I/O口电平变化、查看代码执行时间等。调整状态下多了图3所示的几个调试按钮。

                             

                                              3

 

1.(从左向右第1个按钮,下同)将程序复位到主函数的最开始处,准备重新运行程序。

2.全速运行,运行程序时中间不停止。

3.停止全速运行,全速运行时激活该按钮,用来停止正全速运行的程序。

4.进入子函数内部。

5.单步执行代码,它不会进入子函数内部,可直接跳过函数。

6.跳出当前进入的函数,只有进入子函数内部该按钮才被激活。

7.程序直接运行至当前所在行。

在单步执行代码时,可以查看I/O口电平变化和变量值的变化。现将。先将硬件I/O口模拟器打开,在图4单击Port 1】项,弹出图5所示对话框。

                  图4 

                  图5

 

5显示的是软件模拟出的单片机P18位口线的状态,单片机上电后I/O口全为1,即十六进制的0xFF.

单击图2中右下角变量观察窗口Watch#1】标签,窗口如图6所示,可以看到上面显示“<double-click or F2 to add>”的字样,然后分别按两次F2,输入程序中的两个变量ij。在右面显示出变量的值0X0000,如图6所示。因为ij在最开始定义的时候并没有给它们赋初值,编译器默认给它们的初值为0,而当进入for语句后,才给ij分别赋了1000110.

                      图6

 

    在图7中我们最关心的数据只有一个,也是核心部分“sec,它后面显示的数据就是程序执行所用的时间,单位是秒,可以看到

                    图7

 

上面显示的是389us,这是程序启动执行到穆青停止位置所花的时间(注意:这个时间是累计时间。

     回到代码编辑框,在图2中可以看到主函数“led1=0;”,前面有一个黄色的小箭头。这个小箭头指向的代码是下一部将要执行的代码,单击单步运行图标,这时看到黄色小箭头向下移动了一行,在P1口软件模拟窗口中,P1的最低位的对号没有了,这说明“led1=0;”这条语句执行完了,在实际硬件中也就点亮了P1^0对应的二极管。同时sec后面变为390uS,因此可以算出执行这条指令实际花了390-389=1uS的时间,这个时间恰好就是51单片机在12.000M晶振下一个机器周期所花费的时间。

     接着再单击单步运行按钮,这时右下角变量查看窗口中的i值变成0x3E8,在这个值上右击选择Number BaseDecimal】项,将数值显示方式改成十进制显示,可以看到i的值为1000,实际上就是刚才上一步运行第一个for语句时给i赋的值。继续单步运行可以看到i的值从1000开始往下递减,同时左侧的sec在一次次增加,但j的值始终为0,这是因为每执行一条外层for语句,内层for语句执行110次,即j已经从110递减到0了,所以看上去j始终为0。那如果要看这个for嵌套语句到底执行了多长时间的话是不是就要单击1000次呢?其实不用那么麻烦,可以通过设置断点来解决这个问题。

     设置断点有很多好处,在软件模拟调试状态下,当程序全速运行时,每遇到断点,程序会自动停止在断点处,即下一步将要执行断点处所在的这条指令。这样,在延时语句的两端各设置一个断点,然后通过全速运行,便可以计算出所求严时代码所执行的时间。

     设置方法如下:单击复位钮,然后在第一个for所在行前面空白处双击鼠标,前面出现一个红色方框,表示本行设置了一个断点,然后在下面“led1=1;”所在的行以同样的方式插入另一个断点,这两个断点之间的断码就是这个两级for嵌套语句,如图8所示。

                  图8

 

    单击全速运行按钮,程序会自动停止在第一个for语句所在行,查看时间为390uS,在单击一次全速按钮,程序停止在第二个for语句下面一行处,查看时间显示为892.397mS。两者相减为892.007mS。误差太大进行调整。当:

 

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

                 for(j=123;j>0;j--);显示时间为1.000381s。两者相减为0.999991S,误差为9s,如果忽略uS级误差,此时间为1S。到此延时函数就计算出来了。

补充:

      1. 可以改变for语句中两个变量来重新测试时间,for语句中两个变量类型都为unsigned int型时(注意,若变量为其他类型则时间不遵循以下规律,因为变量类型不同,单片机运行所需的时间就不同),内层for语句变量恒为123时,内层for语句变量为x*1004,这个for嵌套语句就延时xS。大家可以自己验证,测试出更精确的延时语句。

      2.单片机的几个周期介绍

      <1.>时钟周期。也称震荡周期,定义为时钟频率的倒数,他是单片机中最基本,最小的时间的单位。

      <2.>状态周期。它是时钟周期的两倍。

      <3.>机器周期。单片机的基本操作周期,在一个机器周期内,单片机完成一项基本操作,如取指令、存储器读/写等。它由12个时钟周期(6个状态周期)组成。

      <4.>指令周期。它是指CPU执行一条指令所需要的时间。一般一个指令周期含有14个机器周期。

 




关键词: keil     精确     计算    

菜鸟
2015-01-27 07:11:39     打赏
2楼
      在“补充”上面一段“两者相减为0.999991S,误差为9s,如果忽略uS级误差,此时间为1S”应改为“两者相减为0.999991S,误差为,如果忽略uS级误差,此时间为1S

高工
2015-01-27 10:40:47     打赏
3楼
非常好的贴子,收下了。

高工
2015-01-27 15:35:40     打赏
4楼
还真没用keil仿真过,收了

共4条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]