资源描述
基于单片机的电梯仿真实验
1. 80c51引脚图管脚图及各引脚功能介绍
图1 80c51引角图
Vss(20脚):接地
VCC(40脚): 主电源+5V
XTAL1(19脚):接外部晶体的一端。在片内它是振荡电路反相放大器的输入端。在采用外部时钟时,对于HMOS单片机,该端引脚必须接地;对于CHMOS单片机,此引脚作为驱动端。
XTAL2(18脚): 接外部晶体的另一端。在片内它是一个振荡电路反相放大器的输出端,振荡电路的频率是晶体振荡频率。若需采用外部时钟电路,对于HMOS单片机,该引脚输入外部时钟脉冲;对于CHMOS单片机,此引脚应悬浮。
RST(9脚): 单片机刚接上电源时,其内部各寄存器处于随机状态,在该脚输入24个时钟周期宽度以上的高电平将使单片机复位(RESET)
PSEN(29脚): 在访问片外程序存储器时,此端输出负脉冲作为存储器读选通信号。CPU在向片外存储器取指令期间,PSEN信号在12个时钟周期中两次生效。不过,在访问片外数据存储器时,这两次有效PSEN信号不出现。PSEN端同样可驱动8个LSTTL负载。我们根据PSEN、ALE和XTAL2输出端是否有信号输出,可以判别80C51是否在工作。
图2 80C51的内部结构图
ALE/PROG(30脚):在访问片外程序存储器时,此端输出负脉冲作为存储器读选通信号。CPU在向片外存储器取指令期间,PSEN信号在12个时钟周期中两次生效。不过,在访问片外数据存储器时,这两次有效PSEN信号不出现。PSEN端同样可驱动8个LSTTL负载。我们根据PSEN、ALE和XTAL2输出端是否有信号输出,可以判别80C51是否在工作。
EA/VPP(31脚): 当EA端输入高电平时,CPU从片内程序存储器地址0000H单元开始执行程序。当地址超出4KB时,将自动执行片外程序存储器的程序。当EA输入低电平时,CPU仅访问片外程序存储器。在对87C51EPROM编程时,此引脚用于施加编程电压VPP。
输入/输出引脚:(1)P0.0—P0.7 (39脚—32脚)(2)P1.0—P1.7 (1脚—8脚)(3)P2.0—P2.7 (26脚—21脚)(4)P3.0—P3.7 (10脚—17脚)
2. 8255A芯片介绍
Intel 8086/8088 系列的可编程外设接口电路(Programmable Peripheral Interface)简称 PPI,型号为8255(改进型为8255A及8255A-5),具有24条输入/输出引脚、可编程的通用并行输入/输出接口电路。它是一片使用单一+5V电源的40脚双列直插式大规模集成电路。8255A的通用性强,使用灵活,通过它CPU可直接与外设相连接。 8255A在使用前要写入一个方式控制字,选择A、B、C三个端口各自的工作方式,共有三种;
方式0 :基本的输入输出方式,即无须联络就可以直接进行的 I/O方式。其中A、B、C口的高四位或低四位可分别设置成输入或输出。
方式1 :选通I/O,此时接口和外围设备需联络信号进行协调,只有A口和B口可以工作在方式1,此时C口的某些线被规定为A口或B口与外围设备的联络信号,余下的线只有基本的I/O功能,即只工作在方式0.
方式2: 双向I/O方式,只有A口可以工作在这种方式,该I/O线即可输入又可输出,此时C口有5条线被规定为A口和外围设备的双向联络线,C口剩下的三条线可作为B口方式1的联络线,也可以和B口一起方式0的I/O线。
图3 8255A引角图
图4 8255A端口选择表
3. 74LS373介绍
内部有八个D 锁存器。373为三态输出的八D 透明锁存器,共有54/74S373和 54/74LS373 两种线路结构型式,其主要电器特性的典型值如下(不同厂家具体值有差别): 型号 tPd PD54S373/74S373 7ns 525mW 54LS373/74LS373 17ns 120mW373的输出端 O0~O7 可直接与总线相连。当三态允许控制端 OE 为低电平时,O0~O7 为正常逻辑状态,可用来驱动负载或总线。当OE为高电平时,O0~O7 呈高阻态,即不驱动总线,也不为总线的负载,但锁存器内部的逻辑操作不受影响。当锁存允许端 LE 为高电平时,O随数据D而变。当 LE 为低电平时,O 被锁存在已建立的数据电平。当 LE 端施密特触发器的输入滞后作用,使交流和直流噪声抗扰度被改善 400mV。
引出端符号: D0~D7 数据输入端 ;OE 三态允许控制端(低电平有效);LE 锁存允许端 ; O0~O7 输出端。
Dn
LE
OE
On
H
H
L
H
L
H
L
L
X
L
L
Q0
X
X
H
高阻态
其真值表:
4. 数码显示管LED
图5数码显示管LED引脚图
LED显示器是单片机应用系统中常见的输出器件,而在单片机的应用上也是被广泛运用的。如果需要显示的内容只有数码和某些字母,使用LED数码管是一种较好的选择。LED数码管显示清晰、成本低廉、配置灵活,与单片机接口简单易行。
LED数码管作为显示字段的数码型显示器件,它是由若干个发光二极管组成的。当发光二极管导通时,相应的一个点或一个笔画发亮,控制不同组合的二极管导通,就能显示出各种字符,常用的LED数码管有7段和“米”字段之分。这种显示器有共阳极和共阴极两种。共阴极LED显示器的发光二极管的阴极连在一起,通常此共阴极接地。当某个发光二极管的阳极为高电平时,发光二极管点亮,相应的段被显示。同样,共阳极LED显示器的发光二极管的阳极接在一起,通常此共阳极接正电压,当某个发光二极管的阴极接低电平时,发光二极管被点亮,相应的段被显示。
5. 行列式键盘
图6 本次仿真是用到的行列式键盘
由于本次实验中用到的按键较多,而单片机的并行口有限,只能用行列式键盘扩展。该行列式键盘的行和列分别接到8255A的PA口和PB口。
在程序中要注意的是先判断行,再判断列。这里要注意8255A的接口工作方式,PA口工作在输入,PB口工作在输出方式。在判断行的时候,PB口全为0,PA口全为1。在判断列的时候,使得PB口依次为0,扫描列来判断是哪一列的按键按下。
6. 中断判断电路
图7 外部中断电路
此电路旨在引入单片机一个外部中断INY0。由两个四输入与门74LS21和一个两输入与门74LS08组成。只要PA口中有一个低电平,INT0就为0。
本实验程序流程图:
本实验仿真图:
本实验程序:
#include<reg51.h>
#include<absacc.h>
bit e; ///定义电梯的方向
sbit door=P3^0;
sbit m0=P3^4;
sbit m1=P3^5;
char bdata yuzh=0x00;
char bdata shang=0x00;
char bdata xia=0x00;
int layer;//当前层
#define COM8255 XBYTE[0X7FFF]
#define PA8255 XBYTE[0x7FFC]
#define PB8255 XBYTE[0x7FFD]
#define DENG8255 XBYTE[0XAFFF]
#define DENGA XBYTE[0xAFF3]
#define DENGB XBYTE[0xAFF7]
#define DENGC XBYTE[0xAFFB]
void delay(int z)///////////延时程序
{ int x,y;
for(x=0;x<z;x++)
for(y=0;y<110;y++);
}///////////延时程序
////////////////中断0
char templayer;
char dir;
char constant1=0xff;
void INT0_srv(void) interrupt 0 using 1
{ //////////////延时去抖动
delay(2);
if(INT0==1){return;}
//////////////延时去抖动
templayer=PA8255;//先读A口。
PB8255=0x06; ///////判断列数////////
if(PA8255!=constant1)
{ dir=0x01; }
else
{ PB8255=0x05;
if(PA8255!=constant1)
{ dir=0x02; }
else
{ dir=0x03; }
} ///////判断列数////////
PB8255=0x00;
////////////标示量赋值
switch(dir)
{ case 0x01: yuzh=(~templayer)^yuzh;DENGC=yuzh;break;
case 0x02: shang=(~templayer)^shang;DENGA=shang;break;
case 0x03: xia=(~templayer)^xia;DENGB=xia;
}
////////////标示量赋值
return;
}///////////////中断0
char code zimo[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,};
char code pickup[]={0xfe,0xfc,0xf8,0xf0,0xe0,0xc0,0x80,0x00,};
char code pickdown[]={0x00,0x01,0x03,0x07,0x0f,0x1f,0x3f,0x7f,};
char code quw[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,};
////停止层,闪动/
int stopat()
{ int i;
for(i=0;i<8;i++)
{
P1=0;
delay(200);
P1=zimo[layer];
delay(400);
}
return 0;
}
////停止层,闪动/
void main()
{ layer=0x01;//当前层
e=1; //1为上,0为下
EA=1;
EX0=1;
//////////按键和灯,初始化
COM8255=0x90; //AB口都工作在方式0,A入 B为出。
PB8255=0x00;
DENG8255=0X80; ///DENG的ABC口都是输出。
//////////按键和灯,初始化
P1=zimo[layer];
askdir: if((yuzh|shang|xia)!=0)
{ if(e==1)
{upcircle: switch(layer)
{
case 0x01: if((quw[layer-1]&shang)||(quw[layer-1]&yuzh)){door=0;yuzh=~quw[layer-1]&yuzh;shang=~quw[layer-1]&shang;DENGA=shang;DENGC=yuzh;stopat();door=1;}break;
case 0x02: if((quw[layer-1]&shang)||(quw[layer-1]&yuzh)){door=0;yuzh=~quw[layer-1]&yuzh;shang=~quw[layer-1]&shang;DENGA=shang;DENGC=yuzh;stopat();door=1;}break;
case 0x03: if((quw[layer-1]&shang)||(quw[layer-1]&yuzh)){door=0;yuzh=~quw[layer-1]&yuzh;shang=~quw[layer-1]&shang;DENGA=shang;DENGC=yuzh;stopat();door=1;}break;
case 0x04: if((quw[layer-1]&yuzh)||(quw[layer-1]&shang)){door=0;yuzh=~quw[layer-1]&yuzh;shang=~quw[layer-1]&shang;DENGA=shang;DENGC=yuzh;stopat();door=1;}break;
case 0x05: if((quw[layer-1]&shang)||(quw[layer-1]&yuzh)){door=0;yuzh=~quw[layer-1]&yuzh;shang=~quw[layer-1]&shang;DENGA=shang;DENGC=yuzh;stopat();door=1;}break;
case 0x06: if((quw[layer-1]&shang)||(quw[layer-1]&yuzh)){door=0;yuzh=~quw[layer-1]&yuzh;shang=~quw[layer-1]&shang;DENGA=shang;DENGC=yuzh;stopat();door=1;}break;
case 0x07: if((quw[layer-1]&shang)||(quw[layer-1]&yuzh)){door=0;yuzh=~quw[layer-1]&yuzh;shang=~quw[layer-1]&shang;DENGA=shang;DENGC=yuzh;stopat();door=1;}break;
case 0x08: if((quw[layer-1]&shang)||(quw[layer-1]&yuzh)){door=0;yuzh=~quw[layer-1]&yuzh;shang=~quw[layer-1]&shang;DENGA=shang;DENGC=yuzh;stopat();door=1;}
}
////////////////判断上面还有没有要去的层。
if(((pickup[layer-1]&yuzh)|(pickup[layer-1]&shang)|(pickup[layer-1]&xia))==0)
{e=0;//反向
goto askdir;
}
////////////////判断上面还有没有要去的层。
layer=layer+1;
m0=1;
m1=0;
delay(1500);
m0=0;m1=0;
P1=zimo[layer];
goto upcircle;
/////////////上移动一层
}
else
{downcircle: switch(layer)
{
case 0x01: if((quw[layer-1]&xia)||(quw[layer-1]&yuzh)){door=0;yuzh=~quw[layer-1]&yuzh;xia=~quw[layer-1]&xia;DENGB=xia;DENGC=yuzh;stopat();door=1;}break;
case 0x02: if((quw[layer-1]&xia)||(quw[layer-1]&yuzh)){door=0;yuzh=~quw[layer-1]&yuzh;xia=~quw[layer-1]&xia;DENGB=xia;DENGC=yuzh;stopat();door=1;}break;
case 0x03: if((quw[layer-1]&xia)||(quw[layer-1]&yuzh)){door=0;yuzh=~quw[layer-1]&yuzh;xia=~quw[layer-1]&xia;DENGB=xia;DENGC=yuzh;stopat();door=1;}break;
case 0x04: if((quw[layer-1]&xia)||(quw[layer-1]&yuzh)){door=0;yuzh=~quw[layer-1]&yuzh;xia=~quw[layer-1]&xia;DENGB=xia;DENGC=yuzh;stopat();door=1;}break;
case 0x05: if((quw[layer-1]&xia)||(quw[layer-1]&yuzh)){door=0;yuzh=~quw[layer-1]&yuzh;xia=~quw[layer-1]&xia;DENGB=xia;DENGC=yuzh;stopat();door=1;}break;
case 0x06: if((quw[layer-1]&xia)||(quw[layer-1]&yuzh)){door=0;yuzh=~quw[layer-1]&yuzh;xia=~quw[layer-1]&xia;DENGB=xia;DENGC=yuzh;stopat();door=1;}break;
case 0x07: if((quw[layer-1]&xia)||(quw[layer-1]&yuzh)){door=0;yuzh=~quw[layer-1]&yuzh;xia=~quw[layer-1]&xia;DENGB=xia;DENGC=yuzh;stopat();door=1;}break;
case 0x08: if((quw[layer-1]&xia)||(quw[layer-1]&yuzh)){door=0;yuzh=~quw[layer-1]&yuzh;xia=~quw[layer-1]&xia;DENGB=xia;DENGC=yuzh;stopat();door=1;}
}
////////////////判断下面还有没有要去的层。
if(((pickdown[layer-1]&yuzh)|(pickdown[layer-1]&xia)|(pickdown[layer-1]&shang))==0)
{e=1;//反向
goto askdir;
}
////////////////判断下面还有没有要去的层
layer=layer-1;
m0=0;m1=1;
delay(1500);
m0=0;m1=0;
P1=zimo[layer];
goto downcircle;
/////////////下移动一层
}///else
}///if
//////////////没有要去的层,原地不动。
goto askdir;
}
展开阅读全文