关于延迟函数的一些问题

[复制链接]
 楼主| sonjs 发表于 2012-7-31 18:58 | 显示全部楼层 |阅读模式
小生对51单片机刚入门,过程中对延迟函数感到比较困惑,下面附上例说C51一书中的一个小程序

  1. //==声明区=============================
  2. #include        <reg51.h>        //        定义8x51暂存器的标头档,P2-17~19
  3. #define        LED        P1                        //        定义LED接至Port 1
  4. void delay1ms(int);                //        声明延迟函数
  5. void left(int);                        //        声明单灯左移函数
  6. //==主程序===================================
  7. main()                                        //        主程序开始
  8. {        IE=0x81;                        //        准许INT 0中断(6-4页)
  9.         LED=0x00;                        //        初值=0000 0000,灯全亮       
  10.         while(1)                        //        无穷循环,程序一直跑
  11.         {        delay1ms(250);        //        延迟250*1m=0.25s
  12.                 LED=~LED;                //        LED反相
  13.         }                                        //        while循环结束
  14. }                                                //        主程序结束
  15. //==子程序===================================
  16. /* INT 0的中断子程序 - 单灯左移3圈 */
  17. void my_int0(void) interrupt 0        //        INT0 中断子程序开始
  18. {        unsigned saveLED=LED;        //        储存中断前LED状态
  19.         left(3);                        //        单灯左移3圈
  20.         LED=saveLED;                //        写回中断前LED状态
  21. }                                                //        结束INT0 中断子程序
  22. /* 延迟函数,延迟约x 1ms */
  23. void delay1ms(int x)        //        延迟函数开始
  24. {        int i,j;                        //        声明整数变数i,j
  25.         for (i=0;i<x;i++)        //        计数x次,延迟x 1ms
  26.                 for (j=0;j<120;j++);        //        计数120次,延迟1ms
  27. }                                                //        延迟函数结束
  28. /* 单灯左移函数,执行x圈 */
  29. void left(int x)                 //        单灯左移函数开始
  30. {        int i, j;                        //        声明变数i,j
  31.         for(i=0;i<x;i++)        //        i循环,执行x圈
  32.         {        LED=0xfe;                //        初始状态=1111 1110,最右灯亮
  33.                 for(j=0;j<7;j++)//        j循环,左移7次
  34.                 {        delay1ms(250);        //        延迟250*1m=0.25s
  35.                         LED=(LED<<1)|0x01;         //        左移1位後,LSB设为1
  36.                 }                                //        j循环结束
  37.                 delay1ms(250);        //        延迟250*1m=0.25s
  38.         }                                        //        i循环结束*/
  39. }                                         //        单灯左移函数结束
不明白的是for (j=0;j<120;j++)这句为什么 计数120次就延迟1ms?感觉最中心的问题在于这个时间单位,即for (j=0;j<120;j++)计数一次是多少时间?
实在困惑,望高手给予指点
 楼主| sonjs 发表于 2012-7-31 19:11 | 显示全部楼层
有关延迟函数的另一个困惑是这样的
  1. #include<reg51.h>
  2. #define uint unsigned int
  3. sbit D1=P1^0;
  4. void delay(int);
  5. void main()
  6. {
  7.         D1=0;
  8.         delay(10);
  9.         D1=1;
  10.         delay(10);
  11. }
  12. void delay(int z)
  13. {       
  14.         unsigned int x,y;
  15.         for(x=z;x>0;x--)
  16.         for(y=120;y>0;y--);
  17. }
这段代码实现的功能大致是这样的,一个LED灯间隔一定的时间闪烁。如果对程序进行如下修改能否实现同样的功能?
  1. #include<reg51.h>
  2. #define uint unsigned int
  3. sbit D1=P1^0;
  4. void delay(int);
  5. void main()
  6. {
  7. D1=0;
  8. delay(120);
  9. D1=1;
  10. delay(120);
  11. }
  12. void delay(int z)
  13. {       
  14. unsigned int x,y;
  15. for(x=10;x>0;x--)
  16. for(y=120;y>0;y--);
  17. }
就是这两段代码的延迟时间是一致的吗?为什么?求救…
sinonion 发表于 2012-7-31 19:17 | 显示全部楼层
翻IO,示波器卡波形!
原野之狼 发表于 2012-7-31 19:42 | 显示全部楼层
能够能软仿真 那么仿真一下就知道多少个周期了
或者拿示波器来看
或者看汇编代码后估算
NE5532 发表于 2012-7-31 20:31 | 显示全部楼层
因为指令运行消耗了时间,所以起到延时的目的,C语言因为有编译器在,很难说清翻译成了多少句汇编,示波器直接看运行时间是王道。
shell.albert 发表于 2012-7-31 20:34 | 显示全部楼层
CPU执行指令是需要时间的,叫做指令周期。
如SUB减法可能是2个指令周期,JMP跳转可能是3个指令周期,(可能噢,具体得查手册)
你写的C程序会被翻译成汇编语言,你看一下汇编语言。
再计算一下汇编语言中使用的助记符,每一个助记符的指令周期,加起来就行了。

书上的也不是很准,LED这种程序,并不多能闪闪,看到结果就行。
wukunshan 发表于 2012-7-31 21:28 | 显示全部楼层
这个问题也来问?楼主是不是没有学过C语言?买一本C语言的书来看,就很明白了。
qiujiahongde 发表于 2012-8-1 08:32 | 显示全部楼层
这个问题也来问?楼主是不是没有学过C语言?买一本C语言的书来看,就很明白了。
wukunshan 发表于 2012-7-31 21:28

在批评人家之前请考虑好,别误导人家,延迟多少时间最终是看编译器汇编之后的代码。
ayb_ice 发表于 2012-8-1 09:08 | 显示全部楼层
利用指令延时的函数,核心还是用汇编写有保证些
frlop 发表于 2012-8-1 09:18 | 显示全部楼层
在批评人家之前请考虑好,别误导人家,延迟多少时间最终是看编译器汇编之后的代码。
qiujiahongde 发表于 2012-8-1 08:32

正解。
misra 发表于 2012-8-1 10:08 | 显示全部楼层
楼主大侠  莫愁。我也是搞了很久太晓得 这个软件延时是个咋回事。
软件延时一般是不咋准确的,都是自己凑出来的。 另外 在不同的单片机下,相同的函数 延时的时间是不一样的。一定要注意。
另外 不同的优化级别也是不一样的。  所以可以通过伪指令 把优化级别把延时函数给限制住。

延时函数有时候还是用的上的,不过像楼主觉得例子里面那种过于随便的用延时,不值得提倡。当然练习用  令当别论。

另外  还是用定时器来模拟软件延时比较好一点。
弄个一秒的定时器

在定时器终端服务程序里面写上

        if (TimingDelay != 0x00) {
                TimingDelay--;
        }


然后再写个函数
void Delay(__IO INT16U nTime)
{
  TimingDelay = nTime;

  while(TimingDelay != 0);
}

然后就可以调用这个函数了。
我见过还ST  ATMEL  不少官方代码 都这样写的  可以考虑

希望楼主基础打好 。。。。。。。。
有意思 发表于 2012-8-1 10:42 | 显示全部楼层
要比较精确的延时
void delay()
{
  //初始化定时器
//等待定时器计数器完成
}
这样的思想应该比较精确
 楼主| sonjs 发表于 2012-8-1 15:47 | 显示全部楼层
确实基础不好,我会努力的,谢谢 7# wukunshan
 楼主| sonjs 发表于 2012-8-1 15:48 | 显示全部楼层
看到大家这么热心的对待一个初学者,我很感动,谢谢大家
您需要登录后才可以回帖 登录 | 注册

本版积分规则

0

主题

44

帖子

0

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