跳转到内容

二、并行 I/O 口原理与应用

下面讲复习提纲第二部分:二、并行 I/O 口原理与应用。这一部分很容易考端口特点、输入输出规则、电路图、流水灯程序、按键检测程序,也是后面综合控制系统的基础。


I/O 是 Input/Output,也就是输入和输出。

单片机本身只是芯片,想要控制外部世界,就必须通过 I/O 口和外设连接。

可以这样理解:

单片机内部:CPU执行程序
单片机外部:按键、LED、蜂鸣器、继电器、传感器
中间桥梁:I/O口

I/O 口主要做两类事情。

例如:

按键是否按下
开关是否闭合
红外传感器是否检测到物体
限位开关是否触发

程序里常见写法:

if (KEY == 0)
{
// 按键被按下
}

例如:

控制LED亮灭
控制蜂鸣器响
控制继电器吸合
控制数码管显示
控制电机驱动芯片

程序里常见写法:

LED = 0; // 如果低电平点亮,则LED亮
P1 = 0xFE; // 控制P1口8个引脚输出不同电平

考试简答可以写:

并行 I/O 口是单片机与外部设备交换数字信号的接口,可用于读取按键、开关、传感器等输入信号,也可用于控制 LED、蜂鸣器、继电器等输出设备。

复习提纲要求掌握:

P0、P1、P2、P3,共4组I/O口
每组8位,共32根I/O线

可以理解成:

P0 = P0.0 ~ P0.7
P1 = P1.0 ~ P1.7
P2 = P2.0 ~ P2.7
P3 = P3.0 ~ P3.7

在 C51 中,可以按字节操作:

P1 = 0x00; // P1口8位全部输出0
P1 = 0xFF; // P1口8位全部输出1

也可以按位操作:

sbit LED = P1^0;
LED = 0;

这里 P1^0 表示 P1.0 引脚。


这部分是高频考点,尤其是 P0 口和 P3 口。

3.1 P0 口:双向口、无内部上拉、可作地址/数据总线

Section titled “3.1 P0 口:双向口、无内部上拉、可作地址/数据总线”

复习提纲中 P0 的特点是:

P0口:双向口、无内部上拉电阻,做输出必须外接上拉电阻;可做地址/数据总线。

拆开理解。

第一层:P0 作普通 I/O 口时没有内部上拉

Section titled “第一层:P0 作普通 I/O 口时没有内部上拉”

P0 口作为普通 I/O 使用时,是漏极开路结构。它能很容易输出低电平,但输出高电平时,内部没有上拉电阻把引脚拉到高电平。

所以:

P0输出0:可以可靠拉低
P0输出1:如果没有外接上拉,电平可能悬空,不可靠

因此考试常问:

P0口作通用I/O输出时为什么要外接上拉电阻?

答案可以写:

因为P0口为漏极开路结构,内部没有上拉电阻,作为普通I/O输出高电平时不能主动拉高,所以必须外接上拉电阻才能输出稳定高电平。

第二层:P0 可作地址/数据复用总线

Section titled “第二层:P0 可作地址/数据复用总线”

当单片机外扩程序存储器、数据存储器或 I/O 接口时,P0 口不再只是普通 I/O,而是作为:

低8位地址总线 + 8位数据总线

由于引脚数量有限,P0 分时复用:

先输出低8位地址
再作为8位数据线传输数据

这时配合 ALE 信号,把低 8 位地址锁存起来。

所以 P0 的考点可以总结为:

普通I/O:需外接上拉
外扩总线:作低8位地址/数据复用总线

复习提纲中 P1 的特点是:

P1口:准双向通用I/O口,纯普通输入输出。

P1 口内部有上拉电阻,所以比 P0 简单,常用于:

LED流水灯
按键输入
蜂鸣器控制
普通开关量输入输出

初学 51 单片机时,很多例子都用 P1 口接 8 个 LED,因为它比较适合做普通 I/O。

例如:

P1 = 0xFE; // 控制P1.0为0,其余为1

如果 LED 低电平点亮,那么这句就是让 P1.0 对应的 LED 点亮。

注意:AT89S52 的 P1.0、P1.1 还有 T2、T2EX 等第二功能,但在普通 51 基础题里,P1 一般作为普通 I/O 口理解。


3.3 P2 口:准双向口,可作高8位地址总线

Section titled “3.3 P2 口:准双向口,可作高8位地址总线”

复习提纲中 P2 的特点是:

P2口:准双向口,可做高8位地址总线。

拆开理解:

P2 和 P1 类似,可以作为普通 I/O:

接LED
接按键
输出控制信号

如果系统要访问外部存储器,P2 口常作为高 8 位地址线:

P2输出高8位地址
P0输出低8位地址并复用数据

合起来可以形成 16 位地址:

高8位地址(P2) + 低8位地址(P0) = 16位地址

16 位地址最多寻址:

2^16 = 65536 = 64KB

所以 P2 的考点是:

P2可作普通I/O;外扩存储器时作为高8位地址总线。

3.4 P3 口:准双向口,具有第二功能

Section titled “3.4 P3 口:准双向口,具有第二功能”

复习提纲中 P3 的特点是:

P3口:准双向口,具有第二功能(串口、中断、定时器引脚等)。

P3 既能当普通 I/O,又有非常重要的第二功能。

引脚第二功能含义
P3.0RXD串口接收
P3.1TXD串口发送
P3.2INT0外部中断0
P3.3INT1外部中断1
P3.4T0定时器/计数器0外部输入
P3.5T1定时器/计数器1外部输入
P3.6WR外部数据存储器写控制
P3.7RD外部数据存储器读控制

这张表非常重要,尤其是:

P3.0 = RXD
P3.1 = TXD
P3.2 = INT0
P3.3 = INT1
P3.4 = T0
P3.5 = T1

如果题目说“外部中断0接哪个引脚”,答 P3.2/INT0

如果题目说“串口发送引脚是什么”,答 P3.1/TXD

如果题目说“计数器T0外部脉冲输入引脚是什么”,答 P3.4/T0


P1、P2、P3 都常被称为准双向口。

准双向口最重要的规则是:

作为输入使用前,必须先向端口写1。

为什么?

因为准双向口内部结构中,如果锁存器原来写的是 0,那么引脚会被单片机主动拉低。此时外部设备即使想输出高电平,也可能被单片机拉低,导致读数错误。

所以输入前先写 1,相当于“释放端口”:

先写1 -> 内部下拉关闭 -> 外部信号可以决定引脚电平 -> 再读取引脚

例如按键输入:

sbit KEY = P1^0;
void main(void)
{
KEY = 1; // 输入前先写1
while (1)
{
if (KEY == 0)
{
// 按键按下
}
}
}

考试答法:

准双向口作为输入口使用时,应先向该口写1,使输出管截止,释放引脚,然后才能正确读取外部输入电平。

LED 是最常见的输出外设。

复习提纲明确要求掌握:

LED电路串联限流电阻,防止电流过大烧毁芯片和LED。

LED 本质上是二极管,导通后如果没有电阻限制,电流可能过大。

限流电阻的作用:

限制LED电流
保护LED
保护单片机I/O口
调节亮度

考试答法:

限流电阻用于限制流过LED和单片机I/O口的电流,防止电流过大烧毁LED或损坏单片机端口。

PPT 第5章提到,P1~P3 口高电平输出时拉电流能力较弱,低电平输出时灌电流能力较强。因此 51 单片机常用低电平驱动 LED。

典型连接:

+5V -> 限流电阻 -> LED -> 单片机I/O引脚

此时:

I/O输出0:电流从+5V流过电阻和LED,再流入I/O口,LED亮
I/O输出1:LED两端电压不足,LED灭

所以程序中:

LED = 0; // 点亮
LED = 1; // 熄灭

这和直觉有点反,必须记住:

低电平有效:0表示亮,1表示灭

按键常用接法:

I/O引脚通过上拉电阻接+5V
按键另一端接地

此时:

按键未按下:I/O被上拉为1
按键按下:I/O接地为0

所以按键也常是低电平有效。

程序:

#include <reg51.h>
sbit KEY = P1^4;
sbit LED = P1^0;
void main(void)
{
KEY = 1; // 作为输入前先写1
LED = 1; // 初始熄灭,低电平点亮
while (1)
{
if (KEY == 0)
{
LED = 0; // 按下点亮
}
else
{
LED = 1; // 松开熄灭
}
}
}

机械按键按下和松开时,触点会抖动,电平不会立刻稳定。

常见消抖方法:

检测到按下 -> 延时10ms左右 -> 再检测一次 -> 仍然按下才确认

示例:

if (KEY == 0)
{
delay_ms(10);
if (KEY == 0)
{
// 确认按键按下
while (KEY == 0); // 等待松开
}
}

考试如果只是基础按键检测,不一定要求写消抖;但如果题目说“可靠检测按键”,就要写消抖。


流水灯是 I/O 口应用最经典的题型。

题目常见描述:

P1口接8个LED,编写程序实现流水灯。

假设 LED 低电平点亮,则点亮数据通常是:

1111 1110 = 0xFE
1111 1101 = 0xFD
1111 1011 = 0xFB
1111 0111 = 0xF7
...

也就是只有一位为 0,那一位对应 LED 点亮。

查表法最容易理解,也最适合考试写程序。

#include <reg51.h>
typedef unsigned char uchar;
typedef unsigned int uint;
uchar code led_tab[] = {
0xfe, 0xfd, 0xfb, 0xf7,
0xef, 0xdf, 0xbf, 0x7f
};
void delay(uint x)
{
uint i, j;
for (i = 0; i < x; i++)
for (j = 0; j < 120; j++);
}
void main(void)
{
uchar i;
while (1)
{
for (i = 0; i < 8; i++)
{
P1 = led_tab[i];
delay(500);
}
}
}

优点:

思路清楚
花样可改
适合来回流水、间隔点亮等复杂显示

PPT 第5章中也使用了循环移位函数。

#include <reg51.h>
#include <intrins.h>
void delay(unsigned int x)
{
unsigned int i, j;
for (i = 0; i < x; i++)
for (j = 0; j < 120; j++);
}
void main(void)
{
P1 = 0xfe;
while (1)
{
delay(500);
P1 = _crol_(P1, 1);
}
}

这里:

_crol_(P1, 1) 表示把P1中的数据循环左移1位

注意要包含:

#include <intrins.h>

也可以用变量左移,再取反输出。

unsigned char temp = 0x01;
while (1)
{
P1 = ~temp;
delay(500);
temp <<= 1;
if (temp == 0)
{
temp = 0x01;
}
}

因为 LED 低电平点亮,所以 temp 中的 1 表示“想点亮的位置”,输出到 P1 前要取反。


如果题目要求“绘制 LED、开关、流水灯电路”,不要只画单片机和 LED,要体现关键连接。

必须包含:

单片机I/O口
LED
限流电阻
电源或地

常见低电平点亮连接:

+5V -> 限流电阻 -> LED -> P1.x

常见低电平有效连接:

+5V -> 上拉电阻 -> I/O引脚
I/O引脚 -> 按键 -> GND

按下读 0,松开读 1。

如果用 P0 接 LED 或按键,要额外注意:

P0作普通I/O时要外接上拉电阻

题目:

51单片机有哪几组并行I/O口?共有多少根I/O线?

答案:

有P0、P1、P2、P3四组并行I/O口,每组8位,共32根I/O线。

题目:

简述P0口的特点。

答案:

P0口是8位双向I/O口,内部无上拉电阻,作为通用I/O口输出高电平时必须外接上拉电阻;在外扩存储器或I/O接口时,P0口可作为低8位地址/数据复用总线。

题目:

为什么准双向I/O口作输入前要先写1?

答案:

准双向口作输入时,应先向端口锁存器写1,使内部输出管截止,释放引脚,这样外部信号才能决定引脚电平,从而被正确读取。

题目:

LED为什么要串联限流电阻?

答案:

限流电阻用于限制LED回路电流,防止电流过大烧毁LED或损坏单片机I/O口,同时也可调节LED亮度。

核心要点:

设置P1输出初值
延时
改变P1输出数据
循环执行

如果低电平点亮,常用初值:

P1 = 0xFE

P0:无内部上拉,普通I/O时要外接上拉
P1:内部有上拉,普通I/O更方便

准双向口不是直接读就一定对。

输入前写1 = 释放引脚

不要看到 P1=0xFE 就以为输出 1 的灯亮。要看电路连接。

如果 LED 阳极接 +5V、阴极接 I/O:

I/O=0 点亮
I/O=1 熄灭

尤其是:

P3.0 RXD
P3.1 TXD
P3.2 INT0
P3.3 INT1
P3.4 T0
P3.5 T1

51单片机有P0、P1、P2、P3四组8位并行I/O口,共32根I/O线。P0口为双向口,内部无上拉电阻,作为通用I/O口输出高电平时必须外接上拉电阻,也可作为低8位地址/数据复用总线。P1口为准双向通用I/O口,常用于普通输入输出。P2口为准双向口,既可作普通I/O,也可在外扩存储器时作为高8位地址总线。P3口为准双向口,具有第二功能,如RXD、TXD、INT0、INT1、T0、T1、WR、RD等。
准双向I/O口作为输入使用前,应先向端口写1,释放引脚后再读取外部电平。LED接口电路中应串联限流电阻,以防止电流过大损坏LED或单片机端口。51单片机常采用低电平驱动LED,即I/O输出0时LED点亮,输出1时LED熄灭。流水灯程序可采用查表法、循环移位法或移位运算法实现。