典型的8051单片机具有4个8位的并行I/O端口,分别为P0、P1、P2和P3,共32条I/O线。这些I/O端口是双向I/O端口,每个端口均可以用做输入和输出。在程序中,这些I/O端口分别对应4个特殊功能寄存器P0、P1、P2和P3。
对于8051的4组8位I/O口来说,其中P1、P2和P3为准双向口,P0口则为双向三态输入/输出口,下面分别介绍这几个端口的结构。
P0端口是由8个相同结构的引脚组成的,对于某一个引脚结构,如图2-19所示。P0端口内部包含一个输出锁存器、一个输出驱动电路、一个输出控制电路、转换开关MUX和两个三态缓冲器,其中输出驱动电路由一对场效应管(FET)组成,整个端口的工作状态受控于输出控制电路。
P0端口既是一个真正的双向数据总线口,也可以分时复用输出低8位地址总线。
当P0端口作为普通的I/O使用时,对应的控制信号为0。电子模拟开关MUX将锁存器的 Q 端和输出端连接在一起。同时与门输出为0使上拉FET管截止,这时的输出是漏极开路电路,故需要外接上拉电阻(5kΩ~10kΩ)才能正常工作。其工作情况如下:
●当程序中使该输出为0时,锁存器的输出端 Q 为高电平,致使下拉FET管导通,从而输出端输出0;
●当程序中设置输出1时,锁存器的 Q 为低电平,致使下拉FET管截止,由外接的上拉电阻将输出端变为高电平,从而输出1。
对于输入的情况,一般应首先置各个锁存器为1(即输出FFH),才能保证获得正确的输入结果。即作为普通I/O端口时,其不是一个真正的双向I/O端口,而是一个准双向端口。
图2-19 P0口内部结构
当P0口用做低8位地址/数据分时复用时,控制信号为高电平1,控制电子模拟开关MUX与地址/数据线经反相器输出相连,并于下拉FET导通,同时与门开锁,输出地址/数据信号,既通过与门驱动上拉FET管,又通过反相器驱动下拉FET管。其工作情况如下:
●当输出信号1时,上拉FET管导通,而1经过反相器后变为0,使下拉FET管截止,从而在输出引脚上输出高电平1;
●当输出信号0时,上拉FET管截止,而0经过反相器后变为1,使下拉FET管导通,从而使输出引脚上输出低电平0。
由于P0口做地址/数据分时复用方式时,经复位后自动置P0口为0FFH,使下拉FET管截止,控制为0时,上拉FET管也截止,从而保证在高阻抗状态下输入正确的信息。因此,P0口作地址/数据总线时是一个真正的双向口,其能够驱动8个LSTTL负载。
P1口一般用做通用I/O端口,其可以用做位处理,各位都可以单独输出或输入信息。P1口的结构示意图如图2-20所示。
图2-20 P1口内部结构
P1口同样是准双向的I/O端口,当需要某位先输出然后输入的时候,应该在输入操作前,加一条输出1的指令,然后再输入才正确。对于复位后,由于各位锁存器均置为1, Q 端输出为0,下拉FET管截止,因此,各位用做输出或输入都是正确的。
另外,对于AT89S52,P1端口的某些引脚还可以有第二功能。P1.0引脚用于定时/计数器2的外部事件计数输入端口,P1.1引脚用于定时/计数器2的外部控制端口。P1.5~P1.7还用于片内Flash的编程。
P2口可以当做普通I/O口,也可以在系统外部扩展存储器的时候,输出高8位的地址。P2口单个引脚的结构示意图,如图2-21所示,其工作情况如下:
●当P2用做高8位地址时,控制信号用电子模拟开关MUX接通地址端,高8位地址信号便加到输出端口,从而实现8位地址的输出;
图2-21 P2口内部结构
●当P2用做普通I/O口时,控制信号用电子模拟开关MUX接通锁存器的Q端,则进行通用I/O操作。此时,P2口属于准双向I/O口。因此,在复位情况下,直接可以从引脚输入外部数据信息;而在运行中,由输出转为输入方式的时候,则应该加一条输出0FFH指令,再从端口读入才正确。其余操作和P0口类似,P2口可以驱动4个LSTTL负载。
P3端口是一个具有第二变异功能且可位操作的端口。P3口的内部结构如图2-22所示,其用途有以下两种。
●当作为普通I/O端口时,P3口可以进行位操作,是准双向端口,可以驱动4个LSTTL负载。
●当系统需要扩展外部器件时,P3口可以作为第二变异功能使用。其各位的功能如表2-8所示。
图2-22 P3口内部结构
表2-8 P3端口的第二变异功能
单片机4个8位I/O端口的不同结构,决定了各自的应用范围。例如,在一些复杂的应用系统中,只用一个单片机很难达到系统的要求,经常需要外部功能扩展。因此,单片机的P0口和P2口常用于组成16位地址总线。P0口用做8位数据总线,P3口由于其特有的第二变异功能,因此常用于传输和控制等,只有P1口可以真正地用于I/O操作。
另外,在单片机应用时,P0口需要外加上拉电阻,而P1口、P2口和P3口内部设置有上拉电阻,不用外加。这4个I/O端口均为准双向I/O端口,其驱动能力不同,P0口的驱动能力最强,可以驱动8个LSTTL负载,其余三个端口只能驱动4个LSTTL负载。
还有一点需要强调的是,这些端口都有两种读取方式,即读锁存器和读引脚。这是因为在I/O端口中,锁存器内容和引脚上的内容有可能不一致。
例如,当单片机的某个I/O引脚用于驱动三极管的基极时,向该引脚写入1,使三极管导通,此时基极的电压便发生由1到0的跳变,从而使该引脚也变为低电平,而此时锁存器中的内容仍然为1。这样便出现锁存器和引脚内容不一致的情况。
在单片机的指令系统中,有些指令用来读锁存器中的内容,有些指令则用来读引脚内容。当指令的目的操作数为I/O口时,该指令所读的便是锁存器中的内容,而不是引脚上的内容。
读锁存器的指令,示例如下:
虽然51系列单片机提供了4个8位的并行I/O口用于和外部设备进行数据通信及控制,但是这些I/O一般不能完全用于输入输出操作。
例如,很多时候都需要扩展外部程序存储器或数据存储器,此时P0口和P2口便用做数据和地址总线,提供给用户的I/O端口只有P1口和P3口。如果再使用串行通信或外部中断功能时,则可使用的I/O口便更少。因此,在单片机的系统设计中,经常需要扩展I/O口。
51系列单片机的I/O端口的扩展,一般采用将扩展的I/O口与外部RAM统一编址的方式。用户可以将外部64KB的RAM空间的一部分作为扩展I/O端口的地址空间,CPU使用“MOVX”指令对此扩展I/O接口进行输入/输出操作,即可以像访问外部RAM存储单元一样来访问扩展的I/O端口。
并行I/O口的扩展有两种方式,可以采用普通的锁存器、三态门等芯片来进行简单的I/O口扩展,也可以采用可编程的I/O芯片,如8255、8155等来进行扩展。
可编程的I/O芯片比较贵,而且使用比较复杂。在实际的单片机应用系统中,一般采用第一种方法,这种I/O端口通过P0口扩展,其成本低、电路简单、使用也很方便。
这里给出使用普通的锁存器、三态门等芯片进行并行I/O口扩展的一个例子。电路的示意图如图2-23所示。
在该电路中,采用74LS273作为端口的扩展输出、74LS244作为端口的扩展输入。如果系统中还有其他扩展I/O端口,可以使用线选法或译码法将其所使用的地址空间分开。下面分析一下电路的原理。
在图2-23中,输出控制信号由引脚P2.0和 WR 取或运算而得,当两者都为低电平的时候,或门输出为0,将P0端口的数据锁存到74LS273中。74LS273的输出控制着发光二极管,当某根引脚输出低电平的时候,对应的发光二极管发亮。
输入信号是由引脚P2.0和 RD 取或运算而得,当两者都为低电平的时候,或门输出为0,此时选通74LS244,将外部的数据信息输入到总线。图2-23中,与74LS244相连的按键开关按下的时候,将输入1,否则将输入0。
可见,通过8051的双向数据线P0端口,既可以从74LS244输入数据,又可以将数据传送到74LS273中输出。
输入和输出都是在P2.0引脚为0的时候有效的,分别用 RD 和 WR 来区别控制的,因此不会产生输入/输出冲突。
图2-23 并行I/O扩展
在程序中访问扩展I/O端口是通过“MOVX”指令来实现的。例如,如果需要读入扩展I/O端口的数据,并保存到累加器A中,则程序的示例代码如下:
如果需要将累加器A中的数据输出,则程序的示例代码如下: