一、概述
8051有4个8位并行输入/输出接口,称为P0、P1、P2和P3,每个端口有8条I/O线。
这4个口内部都有一个8位数据输出锁存器和两个8位数据输入缓冲器,作输出时数据可以锁存,作输入时数据可以缓冲既可以并行输入或输出8位数据,又可以按位使用,即每1位均能独立作输入或输出用。
每个口都是双向口,可用于信号输入输出。但各自功能都有所差异,具有各自不同的第二功能。
二、P0口
1、 P0口结构
三态双向口,可作为地址/数据分时复用口,也可作为通用I/O接口。
P0口的位电路结构由以下几个部分组成:
⑴ 1个输出锁存器(D触发器),用于进行输出数据的锁存;
⑵ 2个三态输入缓冲器,分别用于锁存器和引脚数据的输入缓冲
⑶ 1个多路开关MUX,用于选择是做为普通I/O口使用还是作为‘地址/数据’总线使用
⑷ 两只场效应管组成的输出驱动电路。

2、P0口访问外部存储器时的地址/数据分时复用功能
⑴ 从P0口输出地址或数据到片外
①“控制信号”为1
②多路开关与“地址/数据”线的反相器输出端相连


⑵从P0口输入片外数据
①“控制信号”为0,V1管截止
②多路开关与锁存器Q端相连,CPU需将高电平‘1’写入P0口锁存器,确保V2管截止。
在读引脚信号控制下,通过读引脚三态门电路将指令码读到内部总线。

3、P0口的通用I/O接口功能
①“控制信号”为0,V1管截止
②多路开关与锁存器Q端连接
⑴ P0口用作I/O口线,由数据总线向引脚输出


⑵ P0口用作I/O口线,由引脚(锁存器)向内部数据总线输入
此时‘控制’信号为‘0’,V1截止.
读引脚(同从P0口输入片外数据)
此时读引脚控制端有效,CPU需将高电平‘1’写入P0口锁存器,确保V2截止,芯片引脚上的数据即可通过内部数据总线输入.

三、端口操作
51单片机有不少指令可直接进行端口操作
例如: ANL P0, A ; (P0)←(P0)∧(A)
ORL C, P0.1 ; CY←CY∨(P0.1)
DEC P1 ; (P1)←(P1)-1
四、并行端口实际应用编程
例1:单片机P1.1接了1个发光二极管, P1.0接了一个开关,要求当键按下点亮发光二级管,断开则熄灭它

汇编解法1:
ORG 0000H
AJMP MAIN
ORG 0200H
MAIN:
SETB P1.0
MOV C,P1.0
JC NEXT
SETB P1.1
SJMP MAIN
NEXT: CLR P1.1
SJMP MAIN
END
汇编解法2:
ORG 0000H
AJMP MAIN
ORG 0200H
MAIN:
ORL P1,#01H
MOV C,P1.0
CPL C
MOV P1.1,C
SJMP MAIN
END
C程序解法:
#include"reg51.h"
sbit p1_0=P1^0;
sbit p1_1=P1^1;
main()
{ while(1)
{ p1_0= 1;
if( p1_0==0) p1_1=1;
else p1_1=0;
}
}
例2:接P1.0的单个LED闪烁(低电平点亮)
ORG 0000H
AJMP MAIN
ORG 0200H
MAIN:
CLR P1.0
ACALL DELAY
SETB P1.0
ACALL DELAY
AJMP MAIN
ORG 0300H
DELAY:
MOV R7,#250
D1: MOV R6,#250
D2: DJNZ R6,D2
DJNZ R7,D1
RET
END
例3:接P1口的8个LED闪烁(低电平点亮)
汇编解法:
ORG 0000H
AJMP MAIN
ORG 0200H
MAIN:
MOV P1,#0FFH
ACALL DELAY
MOV P1,#00H
ACALL DELAY
AJMP MAIN
ORG 0300H
DELAY:
MOV R7,#250
D1: MOV R6,#250
D2: DJNZ R6,D2
DJNZ R7,D1
RET
END
C语言解法:
#include "reg51.h"
void delay(unsigned int time)
{ unsigned int i, j;
for(i=time; i>0; i--)
for(j=112;j>0; j--) ;
}
main( )
{ while(1)
{ P1= 0;
delay(5000);
P1= ~P1;
delay(5000);
}
}
例4:用单片机P1口实现流水灯(低电平点亮)
汇编解法1:
ORG 0000H
AJMP MAIN
ORG 0200H
MAIN:
MOV P1,#0FEH
ACALL DELAY
MOV P1,0FDH
ACALL DELAY
MOV P1,#0FBH
ACALL DELAY
MOV P1,#0F7H
ACALL DELAY
……
AJMP MAIN
ORG 0300H
DELAY:
MOV R7,#250
D1: MOV R6,#250
D2: DJNZ R6,D2
DJNZ R7,D1
RET
END
汇编解法2:
ORG 0000H
AJMP MAIN
ORG 0200H
MAIN:
MOV P1, #0FEH
MOV A, P1
LOOP:
RL A
LCALL DELAY
MOV P1, A
AJMP LOOP
ORG 0300H
DELAY:
MOV R7,#250
D1: MOV R6,#250
D2: DJNZ R6,D2
DJNZ R7,D1
RET
END
汇编解法3:
ORG 0000H
AJMP MAIN
ORG 0200H
MAIN:
MOV DPTR,#0400H
L2: CLR A
MOVC A,@A+DPTR
CJNE A,#01H, L1
SJMP MAIN
L1: MOV P1,A
ACALL DELAY
INC DPTR
SJMP L2
ORG 0300H
DELAY:
MOV R7,#250
D1: MOV R6,#250
D2: DJNZ R6,D2
DJNZ R7,D1
RET
ORG 0400H
TAB DB 0FEH, 0FDH,0FBH
0F7H,0EFH,0DFH
0BFH,7FH, 01H
END
C程序解法1:
#include "reg51.h"
void delay(unsigned int time)
{ ……
}
main( )
{ unsigned char i,sel;
while(1)
{ sel=0xfe;
for(i=0;i<8;i++)
{ P1=sel;
delay(5000);
sel=sel<<1;
sel=sel|0x01;
}
}
}
C程序解法2:
#include "reg51.h"
#include "intrins.h"
void delay(unsigned int time)
{ ……
}
main( )
{ unsigned char i,sel;
while(1)
{ sel=0xfe;
for(i=0;i<8;i++)
{ P1=sel;
delay(5000);
sel=_crol_(sel,1);
}
}
}
C51语言的本征库函数
C语言提供的本征库函数在编译时直接将其固定代码插入当前行,而不用CALL指令实现,即可大大提高函数访问效率
本征库函数:
⑴_crol_:将char型变量循环左移指定位数后返回
⑵_cror_:将char型变量循环右移指定位数后返回
⑶_irol_:将int型变量循环左移指定位数后返回
⑷_iror_:将int型变量循环右移指定位数后返回
⑸_lrol_:将long型变量循环左移指定位数后返回
⑹ _lror_:将long型变量循环右移指定位数后返回
⑺_nop_:相当于插入汇编指令nop
若需使用上述函数,则必须在程序开头加入intrins.h头文件

