1. 基于proteus的51单片机开发实例(2)--闪烁的灯光

1.1. 实验目的

通过本实例了解和熟悉以下知识:

1、51单片机P0端口的结构和工作原理;

2、发光二极管的常用驱动方式和驱动电路;

3、延时程序的编写。

1.2. 设计思路

电路设计思路:使用51单片机P0口的某一位P0.x,通过拉电流的方式驱动发光二极管(LED)循环点亮和熄灭。

程序设计思路:通过编写程序,实现先使P0.x输出1(高电平),点亮LED,延时一段时间后,再使P0.x输出0(低电平),熄灭LED。然后使这些步骤反复执行,从而实现LED的点亮-熄灭-点亮-熄灭......

1.3. 基础知识

1.3.1. 51单片机P0端口的结构

51单片机的P0口既可以作为通用的I/O端口使用,也可以与P2口一起作为数据地址端口。(P0口和P2口组合起来构成16位地址总结,P0口还可以作为8位数据总线。早期单片机因为程序空间ROM和数据空间RAM有限,所以可以通过P0口和P2口扩展外部程序空间和外部数据空间,不过现在随着集成电路工艺的极大提升,单片机的程序空间和数据空间容量已经得到了极大提升。所以外部程序空间和外部数据空间已经极少使用了。在这里我们只做一个了解就行了。)

51单片机P0口的某一位内部结构如图1所示。

proteus仿真课程的51单片机代码(基于proteus的51单片机开发实例)(1)

图1 51单片机P0口的位结构图

从图中可以看出,P0口中一位的内部结构中包括一个输出锁存器,两个三态输入缓冲器、输出驱动电路和控制电路。

其中输出驱动电路有两个场效应晶体管构成,它的工作状态受到由一个与门、一个反向器和一个模拟开关构成的输出控制电路的控制。

当P0口用作通用I/O口时,控制信号=0,则与门输出0,于是输出上拉场效应管T1截止;同时控制多路开关MUX,将锁存器的Q端与输出驱动场效应管T2的栅极接通,此时,输入与输出的工作原理如下。

当P0用作输出口时,写脉冲加在CL上,由于输出驱动电路是漏极开路电路(也就是常说的“开漏电路”,即当写脉冲是高电平时,T2导通,但是T2导通后,P0.x端口接被直接拉到GND了,所以输出不了高电平),如果要驱动N MOS或拉电流负载,则必须在P0.x外接上拉电阻(上拉电阻的阻值一般选择5~10K欧姆之间。)

当P0用作输入口时,分为读端口(读锁存器)和读引脚两种输入方式,因此,端口中设有2个三态缓冲器(B1和B2)用于读操作。读引脚时,需要先向对应的锁存器写“1”,以使T2截止,同时打开三态缓冲器B2,则端口引脚上的电平状态(或数据)经过缓冲器读出。

读端口(读锁存器)时,需要对端口执行“读-修改-写”的步骤,首先通过缓冲器B1读出锁存器Q端的数据,读入后进行运算修改,再写入锁存器,阿然后通过缓冲器B1进入内部总线。这种方法可避免因引脚外部电路的原因而使引脚状态变化,导致出现误读。

试想我们现在要读P0引脚,按理说P0与外部电路相连,外部电路的是什么状态,就应该读到什么,但如果P0口的场效应管T2一端接地的话,它会把P0口电位拉低,你读到的总是低电平0,所以要先给P0写FFH,把P0的场效应管T2和地断开,再读数时就是真实状态了。当外部电路断开,再读时读到的就是P0端口(锁存器)的真实状态了。

1.3.2. 发光二极管常用驱动方式

在上一个实例中,我们点亮发光二极管的方式是将发光二极管的正极通过一个限流电阻接到电源正极,而把发光二极管的负极接到单片机的P1.0口,这样的话,当P1.0输出0(低电平)时,发光二极管导通,相当于电流从电源正极通过发光二极管“灌入”单片机的P1.0口,所以这种方式称为“灌电流”驱动方式。

而如果把发光二极管的正负极颠倒一下:正极接单片机端口,负极接地,当单片机端口输出1(高电平),则发光二极管导通,相当于电流被从单片机端口拉到发光二极管,然后流到地,这就是所谓的“拉电流”驱动方式。

发光二极管“灌电流”和“拉电流”驱动方式如图2所示。

proteus仿真课程的51单片机代码(基于proteus的51单片机开发实例)(2)

图2 发光二极管的“灌电流”和“拉电流”驱动方式

1.3.3. 延时程序的实现

本实例的目的是让发光二极管闪烁,具体流程是,先点亮发光二极管,一段时间后,再熄灭发光二极管,然后再过一段时间,再点亮发光二极管,如此循环往复,从而实现发光二极管的点亮-熄灭-点亮的循环过程。

这里就要用到延时函数,这个延时函数的目的就是让发光二极管点亮(或熄灭)后,持续一定的时间。说白了,就是让程序在一段时间内“停止”。这个怎样实现呢,很简单,让程序一直循环执行一个无用的语句,就相当于是让程序“停止”了一定的时间。

下面这段代码就是一个典型的延时程序

//典型的延时程序,通过两个具有嵌套关系的for循环语句, //使程序在一段时间内不 向下继续执行,从而达到延时的目的 for(DelayMS=0;DelayMS<500;DelayMS ) { for(i=0;i<1141;i ); }

1.4. 电路设计

图3所示是本实例用到的电路图,大家可能会注意到,这个电路图少了复位电路、晶振电路、电源电路。这是为什么呢?

proteus仿真课程的51单片机代码(基于proteus的51单片机开发实例)(3)

图3 -闪烁的灯光电路

原因很简单,在proteus中,自动的就隐藏了单片机的最小系统电路。

还有一点需要说明,这个电路中P0.0有一个上拉电阻,原因就是我们在上面讲的,P0口是开漏输出,必须要外加上拉电阻。

1.5. 程序设计

本实例的程序代码如下。这段程序牵涉到了延时程序和端口电平的变化,需要说明的是,这段程序是演示性质的,写的不是很规范,不过没关系,我们一步一步来,先学会基本原理,再让程序规范化。

#include <AT89X52.h> // int main(void) { unsigned int DelayMS=0,i; while(1) { P0=0x01; //使P0.0输出高电平,点亮LED //延时一段时间,使LED保持点亮状态 for(DelayMS=0;DelayMS<500;DelayMS ) { for(i=0;i<1141;i ); } P0=0x00; //使P0.0输出低电平,熄灭LED //延时一段时间,使LED保持熄灭状态 for(DelayMS=0;DelayMS<500;DelayMS ) { for(i=0;i<1141;i ); } } }

1.6. 实例仿真

编写完程序,编译后生成HEX文件,将该文件装载到proteus仿真电路的单片机里面,然后点击开始仿真。我们就可以看到电路中的发光二极管显示发光,过一会后熄灭,再过一会就又会发光了,如此循环往复。

proteus仿真课程的51单片机代码(基于proteus的51单片机开发实例)(4)

图4 仿真结果

如果大家按照本实例中的程序和电路来做,可能会发现发光二极管并不会闪烁,这时候,可以试着把发光二极管的驱动电流改小,然后就能看到正常的实验现象了。原因是什么呢?单片机端口的驱动能力是有限的。

1.7. 总结

本实例不但介绍了发光二极管的拉电流驱动方式,还了解了简单的延时程序的实现方法。另外还有一个很重要的知识点就是,51单片机的P0口作为输出口时,是开漏输出的,必须外加上拉电阻才能正确输出高电平。

,