一、汇编程序
  ORG 0000H
 LJMP MAIN
 ORG 0003h
Ljmp ZD0
 ORG 000Bh
 LJMP TZD0
ORG 0013h
 Ljmp ZD1
 ORG 001Bh
 LJMP TZD1
 ORG 0040H
MAIN: Mov TMOD,#66h
 MOV TH0,#0ffh
 MOV TL0,#0ffh
 MOV TH1,#0ffh
 MOV TL1,#0ffh
 SETB EA
 SETB ET0
 SETB TR0
 SETB ET1
 SETB TR1
 SETB IT0
 SETB IT1
 SETB EX0
 SETB EX1
xh: mov P1,#0feh
 Lcall Delay
 mov P1,#0fdh
 Lcall Delay
 mov P1,#0fbh
 Lcall Delay
 mov P1,#0f7h
 Lcall Delay
 SJMP xh
ZD0: JNB P1.0,dat1
 JNB P1.1,dat2
 JNB P1.2,dat3
 JNB P1.3,dat4
dat1: mov P2,#06h ;1
 sjmp ZD0R
dat2: mov P2,#5bh ;2
 sjmp ZD0R
dat3: mov P2,#4fh ;3
 sjmp ZD0R
dat4: mov P2,#66h ;4
ZD0R: reti
ZD1: JNB P1.0,dat5
 JNB P1.1,dat6
 JNB P1.2,dat7
 JNB P1.3,dat8
dat5: mov P2,#6dh ;5 0110
 sjmp ZD1R
dat6: mov P2,#7dh ;6
 sjmp ZD1R
dat7: mov P2,#07h ;7
 sjmp ZD1R
dat8: mov P2,#7fh ;8
ZD1R: reti
TZD0: JNB P1.0,dat9
  JNB P1.1,dat0
 JNB P1.2,dat10
 JNB P1.3,dat11
dat9: mov P2,#6fh ;9
 sjmp ZD0R
dat0: mov P2,#3fh ;0
 sjmp ZD0R
dat10: mov P2,#77h ;A
 sjmp ZD0R
dat11: mov P2,#7ch ;B
TZD0R:reti
TZD1: JNB P1.0,dat12
 JNB P1.1,dat13
 JNB P1.2,dat14
 JNB P1.3,dat15
dat12: mov P2,#39h ;C
 sjmp TZD1R
dat13:mov P2,#5eh ;D
 sjmp TZD1R
dat14:mov P2,#79h ;E
 sjmp TZD1R
dat15:mov P2,#71h ;F
TZD1R:reti
Delay:mov r7,#10d
 djnz r7,$
 ret
 end

二、C语言程序(扫描P1)
#include"reg51.h"
int yu[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
 0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
int i,j,k,time,temp,dat;
void delay(time)
{
 while(time--)
 for(i=0;i<120;i++);
}
void main()
{
 P2=0x40;
 TMOD=0x66; //设定定时计数器T0、T1为方式2计数模式
 TH0=0xFF;
 TL0=0xFF;
 TH1=0xFF;
 TL1=0xFF;
 IE=0x8F; //开总中断和定时计数器两个中断,两个外中断
 IT0=1;
 IT1=1; //设置外中断为下降沿触发
 TR0=1;
 TR1=1; //打开定时计数器开始计数
 while(1)
 {
 P1=0xfe;
 delay(1);
 P1=0xfd;
 delay(1);
 P1=0xfb;
 delay(1);
 P1=0xf7;
 delay(1);
 }
}
void intsvr0(void) interrupt 0 using 1
{
 
 temp=P1;
 switch(temp)
 {
 case 0xfe:key=0;break;
 case 0xfd:key=1;break;
 case 0xfb:key=2;break;
 case 0xf7:key=3;break;
 default:break;
 }
 P2=yu[dat];
}
void timer0(void) interrupt 1 using 1
{
 temp=P1;
 if(temp==0xfe) dat=4;
 if(temp==0xfd) dat=5;
 if(temp==0xfb) dat=6;
 if(temp==0xf7) dat=7;
 P2=yu[dat];
}
void intsvr1(void) interrupt 2 using 1
{
 
 temp=P1;
if(temp==0xfe)dat=8;
 if(temp==0xfd) dat=9;
 if(temp==0xfb) dat=10;
 if(temp==0xf7) dat=11;
 P2=yu[dat];
}
void timer1(void) interrupt 3 using 1
{
 int dat;
 temp=P1;
 switch(temp)
 {
 case 0xfe:key=12;break;
 case 0xfd:key=13;break;
 case 0xfb:key=14;break;
 case 0xf7:key=15;break;
 default:break;
 }
 P2=yu[dat];
} 
/*************************************************************/
三、C语言(扫描P3的P3.0、P3.1、P3.6、P3.7)
从这个程序也可以看出51单片机I/O口没有方向性,输入输出都可读写,而且在一个寄存器中。注意该程序对应电路图与上图的区别。

#include"reg51.h"
sbit pp0=P3^0;
sbit pp1=P3^1;
sbit pp2=P3^6;
sbit pp3=P3^7;
int yu[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
 0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
int i,j,k,time,temp,dat;
void delay(time)
{
 while(time--)
 for(i=0;i<120;i++);
}
void main()
{
 P2=0x40;
 TMOD=0x66; //设定定时计数器T0、T1为方式2计数模式
 TH0=0xFF;
 TL0=0xFF;
 TH1=0xFF;
 TL1=0xFF;
 IE=0x8F; //开总中断和定时计数器两个中断,两个外中断
 IT0=1;
 IT1=1; //设置外中断为下降沿触发
 TR0=1;
 TR1=1; //打开定时计数器开始计数
 while(1)
 {
 pp0=0;
 delay(5);
 pp0=1;
 pp1=0;
 delay(5);
 pp1=1;
 pp2=0;
 delay(5);
 pp2=1;
 pp3=0;
 delay(5);
 pp3=1;
/*以上可用下列这段代替
 P3=0xfe;
 delay(5);
 P3=0xfd;
 delay(5);
 P3=0xbf;
 delay(5);
 P3=0x7f;
 delay(5);*/
 }
}
void intsvr0(void) interrupt 0 using 1
{
 
 temp=P3;
 switch(temp) 
 { 
 case 0xfa:dat=0;break; 
 case 0xf9:dat=1;break; 
 case 0xbb:dat=2;break; 
 case 0x7b:dat=3;break;
 default: break;
 }
 P2=yu[dat];
}
void timer0(void) interrupt 1 using 1
{
 temp=P3;
 if(temp==0xee) dat=8;
 if(temp==0xed) dat=9;
 if(temp==0xaf) dat=10;
 if(temp==0x6f) dat=11;
 P2=yu[dat];
}
void intsvr1(void) interrupt 2 using 3
{
 
 temp=P3;
 if(temp==0xf6) dat=4;
 if(temp==0xf5) dat=5;
 if(temp==0xb7) dat=6;
 if(temp==0x77) dat=7;
 P2=yu[dat];
}
void timer1(void) interrupt 3 using 1
{
 int dat;
 temp=P3;
 switch(temp) 
 { 
 case 0xde:dat=12;break; 
 case 0xdd:dat=13;break; 
 case 0x9f:dat=14;break; 
 case 0x5f:dat=15;break;
 default: break;
 }
 P2=yu[dat];
}