4472|1

1379

帖子

0

TA的资源

裸片初长成(中级)

楼主
 

闪烁灯 [复制链接]

在给大家一个闪烁灯的实验程序

如下图所示:在P1.0端口上接一个发光二极管L1,使L1在不停地一亮一灭.

2.  电路原理图

4.1.1

3.  系统板上硬件连线

   

在我们的《编程试验 一体板》已经接好8个发光二极管,不需要任何改动,就可以做这个试验。

4.  程序设计内容

怎样才能让灯不断地闪烁呢?实际上就是要灯亮一段时间,再灭一段时间,也就是说要P1.0不断地输出高和低电平。怎样实现这个要求呢?请考虑用下面的指令是否可行:

SETB P10

CLR P10

……

这是不行的,有两个问题,第一,计算机执行指令的时间很快,执行完SETB P10后,灯是灭了,但在极短时间(微秒级)后,计算机又执行了CLR P10指令,灯又亮了,所以根本分辨不出灯曾灭过。第二,在执行完CLR P10后,不会再去执行SETB P10指令,所以以后再也没有机会让灭了。

  为了解决这两个问题,我们可以做如下设想,第一,在执行完SETB P10后,延时一段时间(几秒或零点几秒)再执行第二条指令,就可以分辨出灯曾灭过了。第二在执行完第二条指令后,让计算机再去执行第一条指令,不断地在原地兜圈,我们称之为"循环",这样就可以完成任务了。

以下先给出程序(后面括号中的数字是为了便于讲解而写的,实际不用输入):

;主程序:

LOOP: SETB P10     ;(1)

    LCALL DELAY   ;(2)

    CLR P10     ;(3)

    LCALL DELAY   ;(4)

    LJMP LOOP    ;(5)

;以下子程序

DELAY: MOV R7,#250  ;(6)

D1: MOV R6,#250    ;(7)

D2: DJNZ R6,D2    ;(8)

  DJNZ R7,D1     ;(9)

  RET         ;(10)

  END         ;(11)

按上面的设想分析一下前面的五条指令。

  第一条是让灯灭,第二条应当是延时,第三条是让灯亮,第四条和第二条一模一样,也是延时,第五条应当是转去执行第一条指令。第二和第四条实现的原理稍后谈,先看第五条,LJMP是一条指令,意思是转移,往什么地方转移呢?后面跟的是LOOP,看一下,什么地方还有LOOP,对了,在第一条指令的前面有一个LOOP,所以很直观地,我们可以认识到,它要转到第一条指令处。这个第一条指令前面的LOOP被称之为标号,它的用途就是给这一行起一个名字,便于使用。是否一定要给它起名叫LOOP呢?当然不是,起什么名字,完全由编程序的人决定,可以称它为A,X等等,当然,这时,第五条指令LJMP后面的名字也得跟着改了。

  第二条和第四条指令的用途是延时,它是怎样实现的呢?指令的形式是LCALL,这条指令称为调用子程序指令,看一下指令后面跟的是什么,DELAY,找一下DELAY,在第六条指令的前面,显然,这也是一个标号。这条指令的作用是这样的:当执行LCALL指令时,程序就转到LCALL后面的标号所标定的程序处执行,如果在执行指令的过程中遇到RET指令,则程序就返回到LCALL指令的下面的一条指令继续执行,从第六行开始的指令中,可以看到确实有RET指令。在执行第二条指令后,将转去执行第6条指令,而在执行完6,7,8,9条指令后将遇到第10条令:RET,执行该条指令后,程序将回来执行第三条指令,即将P10清零,使灯亮,然后又是第四条指令,执行第四条指令就是转去执行第6,7,8,9,10条指令,然后回来执行第5条指令,第5条指令就是让程序回到第1条开始执行,如此周而复始,灯就在不断地亮、灭了。

  在标号DELAY标志的这一行到RET这一行中的所有程序,这是一段延时程序,大概延时零点几秒,至于具体的时间,以后我们再学习如何计算。 程序的最后一行是END,这不是一条指令,它只是告诉我们程序到此结束,它被称为"伪指令"。

 

    延时程序的设计方法

下面我们再来看一下其它符号的含义。

DELAY: MOV R7,#250   ;(6)
D1: MOV R6,#250   ;(7)

D2: DJNZ R6,D2    ;(8)

DJNZ R7,D1   ;(9)    

RET        ;(10)


MOV:这是一条指令,意思是传递数据。说到传递,我们都很清楚,传东西要从一个人的手上传到另一个人的手上,也就是说要有一个接受者,一个传递者和一样东西。从指令MOV R7,#250中来分析,R7是一个接受者,250是被传递的数,传递者在这条指令中被省略了(注意:并不是每一条传递指令都会省的,事实上大部份数据传递指令都会有传递者)。它的意义也很明显:将数据250送到R7中去,因此执行完这条指令后,R7单元中的值就应当是250。在250前面有个#号,这又是什么意思呢?这个#就是用来说明250就是一个被传递的东西本身,而不是传递者。那么MOV R6,#250是什么意思,应当不用分析了吧。

DJNZ:这是另一条指令,我们来看一下这条指令后面跟着的两个东西,一个是R6,一个是D2,R6我们当然已知是什么了,查一下D2是什么。D2在本行的前面,我们已学过,这称之为标号。标号的用途是什么呢?就是给本行起一个名字。DJNZ指令的执行过程是这样的,它将其后面的第一个参数中的值减1,然后看一下,这个值是否等于0,如果等于0,就往下执行,如果不等于0,就转移,转到什么地方去呢?可能大家已猜到了,转到第二个参数所指定的地方去(请大家用自已的话讲一下这条语句是怎样执行的)。本条指令的最终执行结果就是,在原地转圈250次。
 

 

执行完了DJNZ R6,D2之后(也就是R6的值等于0之后),就会去执行下面一行,也就是DJNZ R7,D1,请大家自行分析一下这句话执行的结果。(转去执行MOV R6,#250,同时R7中的值减1),最终DJNZ R6,D2这句话将被执行250*250=62500次,执行这么多次同一条指令干吗?就是为了延时。
 


时序分析:

前面我们介绍了延时程序,但这还不完善,因为,我们只知道DJNZ R6,D2这句话会被执行62500次,但是执行这么多次需要多长时间呢?是否满足我们的要求呢?我们还不知道,所以下面要来解决这个问题。

先提一个问题:我们学校里什么是最重要的。(铃声)校长可以出差,老师可以休息,但学校一日无铃声必定大乱。整个学校就是在铃声的统一指挥下,步调一致,统一协调地工作着。这个铃是按一定的时间安排来响的,我们可以称之为“时序 时间的顺序”。一个由人组成的单位尚且要有一定的时序,计算机当然更要有严格的时序。事实上,计算机更象一个大钟,什么时候分针动,什么时候秒针动,什么时候时针动,都有严格的规定,一点也不能乱。计算机要完成的事更复杂,所以它的时序也更复杂。

我们已知,计算机工作时,是一条一条地从ROM中取指令,然后一步一步地执行,我们规定:计算机访问一次存储器的时间,称之为一个机器周期。这是一个时间基准,好象我们人用“秒”作为我们的时间基准一样,为什么不干脆用“秒”,多好,很习惯,学下去我们就会知道用“秒”反而不习惯。

一个机器周期包括12个时钟周期。下面让我们算一下一个机器周期是多长时间吧。设一个单片机工作于12M晶振,它的时钟周期是1/12(微秒)。它的一个机器周期是12*(1/12)也就是1微秒。(请计算一个工作于6M晶振的单片机,它的机器周期是多少)。

 

 

如上图,是我们试验板上自带的3个石英晶体,通过选择开关,可以选择不同频率的石英晶体,而且还预留了外接晶振插座。方便扩展。这里,我们选择12MHz的晶振。因此,1个机器周期为1微秒



MCS-51单片机的所有指令中,有一些完成得比较快,只要一个机器周期就行了,有一些完成得比较慢,得要2个机器周期,还有两条指令要4个机器周期才行。这也不难再解,不是吗?我让你扫地的执行要完成总得比要你完成擦黑板的指令时间要长。为了恒量指令执行时间的长短,又引入一个新的概念:指令周期。所谓指令周期就是指执行一条指令的时间。INTEL对每一条指令都给出了它的指令周期数,这些数据,大部份不需要我们去记忆,但是有一些指令是需要记住的,如DJNZ指令是双周期指令。

下面让我们来计算刚才的延时。首先必须要知道晶振的频率,我们设所用晶振为12M,则一个机器周期就是1微秒。而DJNZ指令是双周期指令,所以执行一次要2个微秒。一共执行62500次,正好125000微秒,也就是125毫秒。

此帖出自单片机论坛

最新回复

//p1   8灯闪烁程序 #include //sbit L1=P1^0; void delay02s(void)                //延时0.2秒子程序 {   unsigned char i,j,k;   for(i=20;i>0;i--)   for(j=20;j>0;j--)   for(k=248;k>0;k--); } void main(void) {   while(1)     {       P1=0;       delay02s();       P1=0xff;       delay02s();     } }  详情 回复 发表于 2009-3-24 14:42
点赞 关注
 

回复
举报

154

帖子

0

TA的资源

纯净的硅(高级)

沙发
 

Re: 闪烁灯

//p1   8灯闪烁程序
#include
//sbit L1=P1^0;

void delay02s(void)                //延时0.2秒子程序
{
  unsigned char i,j,k;
  for(i=20;i>0;i--)
  for(j=20;j>0;j--)
  for(k=248;k>0;k--);
}


void main(void)
{
  while(1)
    {
      P1=0;
      delay02s();
      P1=0xff;
      delay02s();
    }
}
此帖出自单片机论坛

赞赏

1

查看全部赞赏

 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条
艾睿电子& Silicon Labs 有奖直播 | 全新蓝牙信道探测:从技术创新到实际应用
直播时间:3月12日(周三)上午10:00
直播奖励:多功能榨汁机、蓝牙音箱、手机支架

查看 »

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表