【Proteus仿真】51单片机+8255A IO扩展例程

【Proteus仿真】51单片机+8255A IO扩展例程


在这里插入图片描述

📓8255A与51单片机连接

  • 🔖8051单片机和8255A连接示意图:
    在这里插入图片描述
  • 🌿51单片机的P0口作为数据总线使用,与8255A的D7~D0数据信号线进行连接,当P00 - P07不作为8255A 的A、B、C端口地址使用时,可以不接上拉电阻或者74HC373锁存器。
  • 🌿8255A的CS:片选信号输入引脚直接接GND。
  • 🌿RD读信号输入引脚接51单片机P37.
  • 🌿WR写信号输入引脚接51单片机P36
    在这里插入图片描述

⛳8255A端口地址确认方法

  • 🌿CS、A1、A0接单片机的地址总线,构成单片机访问8255A的16位地址.
  • 🌿16位总线访间地址=片选地址(CS) +片内地址(A1、A0)
  • 🔖CS引脚直接接GND的话,该位(BIT)配置不受影响,只需配置A1、A2这两位.
    在这里插入图片描述

✨避开配置端口P0情况下,使用P2端口进行地址配置:

  • 🌿地址配置一:51单片机访问8255A端口地址。(没接的地址设为1)
    在这里插入图片描述
1
2
3
4
5
6
//CS->GND;A0 ->P22;A1 ->P23
#define PA XBYTE[0xf3ff]//定义PA端口
#define PB XBYTE[0xf7ff]//定义PB端口
#define PC XBYTE[0xfbff]//定义PC端口
#define PK XBYTE[0xffff]//控制寄存器端口

在这里插入图片描述

  • 🌿地址配置二:
    在这里插入图片描述
1
2
3
4
5
6
//CS->GND;A0 ->P20;A1 ->P21
#define PA XBYTE[0xfcff]//定义PA端口
#define PB XBYTE[0xfdff]//定义PB端口
#define PC XBYTE[0xfeff]//定义PC端口
#define PK XBYTE[0xffff]//控制寄存器端口

在这里插入图片描述

⚡CS不接地的情况下:

  • 🌴配置一:
    在这里插入图片描述
1
2
3
4
5
6
//CS->P27;A0 ->P22;A1 ->P23
#define PA XBYTE[0x73ff]//定义PA端口
#define PB XBYTE[0x77ff]//定义PB端口
#define PC XBYTE[0x7bff]//定义PC端口
#define PK XBYTE[0x7fff]//控制寄存器端口

在这里插入图片描述

  • 🌴配置二:
    在这里插入图片描述
1
2
3
4
5
6
//CS->P27;A0 ->P20;A1 ->P21
#define PA XBYTE[0x7cff]//定义PA端口
#define PB XBYTE[0x7dff]//定义PB端口
#define PC XBYTE[0x7eff]//定义PC端口
#define PK XBYTE[0x7fff]//控制寄存器端口

在这里插入图片描述

⛳不选择P0作为A1和A0地址线说明

✨如果将P0端口作为A1、A0地址线,那么P0端口不仅作为数据总线还作为了地址线,需要接上拉电阻,或者接74HC373锁存器才行。

📝程序代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <REGX52.H>
#include <absacc.h>//包含访问外部扩展指针变量XBYTE

#define uchar unsigned char //宏定义
#define uint unsigned int //宏定义
//8255A
//CS->GND;A0 ->P20;A1 ->P21
#define PA XBYTE[0xfcff]//定义PA端口
#define PB XBYTE[0xfdff]//定义PB端口
#define PC XBYTE[0xfeff]//定义PC端口
#define PK XBYTE[0xffff]//控制寄存器端口
//CS->P27;A0 ->P20;A1 ->P21
//#define PA XBYTE[0x7cff]//定义PA端口
//#define PB XBYTE[0x7dff]//定义PB端口
//#define PC XBYTE[0x7eff]//定义PC端口
//#define PK XBYTE[0x7fff]//控制寄存器端口
//CS->GND;A0 ->P22;A1 ->P23
//#define PA XBYTE[0xf3ff]//定义PA端口
//#define PB XBYTE[0xf7ff]//定义PB端口
//#define PC XBYTE[0xfbff]//定义PC端口
//#define PK XBYTE[0xffff]//控制寄存器端口
//CS->P27;A0 ->P22;A1 ->P23
//#define PA XBYTE[0x73ff]//定义PA端口
//#define PB XBYTE[0x77ff]//定义PB端口
//#define PC XBYTE[0x7bff]//定义PC端口
//#define PK XBYTE[0x7fff]//控制寄存器端口

sbit dat = P0; //8255的D0~D7的数据口

void delay(uint ms)//1ms延时
{
uint i, j;
for(i = ms; i > 0; i--)
for(j = 120; j > 0; j--);

}

void main()
{
unsigned char a;
PK = 0x80; //方式控制字,端口ABC都工作于方式0,基本输入输出
PA = 0x00;
PB = 0x00;
PC = 0x00;

while(1)
{
PC =PA =PB = (1 << a++);// 第一次运行时 0000 0001<< 0 = 0000 0001
delay(500);//延时
if(a == 0x08) // 允许左移8次。
{
a = 0;
}
}

}

🏳‍🌈不包含absacc.h头文件定义方式

  • 👉🏻使用_at_关键字,对存储器进行绝对地址访问。
1
2
3
4
5
6
7
8
9
10
//CS->GND;A0 ->P20;A1 ->P21
//#define PA XBYTE[0xfcff]//定义PA端口
unsigned char xdata PA _at_ 0xfcff;
//#define PB XBYTE[0xfdff]//定义PB端口
unsigned char xdata PB _at_ 0xfdff;
//#define PC XBYTE[0xfeff]//定义PC端口
unsigned char xdata PC _at_ 0xfeff;
//#define PK XBYTE[0xffff]//控制寄存器端口
unsigned char xdata PK _at_ 0xffff;

📚仿真示例一资源和程序源码

  • 🔖基于Proteus8.12平台
1
2
3
链接:https://pan.baidu.com/s/1CKtrOxDQgMJWRrOLrhHQpQ 
提取码:s3qw

📝仿真示例二(使用CS->P02、A0->P00、A1->01)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#include <reg52.h>
#include <absacc.h> //访问外部扩展RAM
#define uint unsigned int
#define uchar unsigned char
//#define PA XBYTE[0x0000] //定义PA端口
//#define PB XBYTE[0x0001]//定义PB端口
//#define PC XBYTE[0x0002]//定义PC端口
//#define COM XBYTE[0x0003]//控制寄存器端口

#define PA XBYTE[0xFFF8] //定义PA端口
#define PB XBYTE[0xFFF9]//定义PB端口
#define PC XBYTE[0xFFFa]//定义PC端口
#define COM XBYTE[0xFFFb]//控制寄存器端口


uchar code smgduan[10] =
{0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90};//0~9 7SegCA共阳数码管
//{0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f}; //共阴数码管段码

//秒、分、时标志
uchar miao = 0, fen = 0, shi = 0;

//秒、分、时高位低位
uchar miao_L, miao_H, fen_L, fen_H, shi_L, shi_H;

//计数
uint counter = 0;

void delay(uint x)
{
uchar i;
while(x--)
{
for(i = 0; i < 120; i++);
}
}

void display() //显示函数
{

PB = 0x20; //0010 0000
PA = 0xbf; //显示‘-’
delay(5);

PB = 0x04; //0100
PA = 0xbf;
delay(5);

PB = 0x80; // 1000 0000
PA = smgduan[miao_L];
delay(5);

PB = 0x40; // 0100 0000
PA = smgduan[miao_H];
delay(5);

PB = 0x10; // 0001 0000
PA = smgduan[fen_L];
delay(5);

PB = 0x08; // 0000 1000
PA = smgduan[fen_H];
delay(5);

PB = 0x02; // 0000 0010
PA = smgduan[shi_L];
delay(5);

PB = 0x01; // 0000 0001
PA = smgduan[shi_H];
delay(5);

}

void T0_Init() //定时器0初始化
{
TMOD = 0x01;
TH0 = 0x3c;
TL0 = 0xb0;
EA = 1; //开总中断
ET0 = 1;
TR0 = 1;
}

void main()
{
// uchar i, j, k;
COM = 0x80;//方式控制字,端口ABC都工作于方式0,基本输入输出
PA = 0x00;
PB = 0x00;
PC = 0x00;
T0_Init();//定时器0初始化
while(1)
{
display();//显示
}
}

void timer0_Init() interrupt 1 //定时器0中断函数
{

TL0 = (65536 - 50000) % 256; //50ms预装载值
TH0 = (65536 - 50000) / 256;
counter++;
//1秒钟=50ms*20=1000ms,20次计数为1秒钟
if(counter == 20)
{
counter = 0;
miao++; //i = 100

if(miao == 60)
{
miao = 0;
fen++;

if(fen == 60)
{
fen = 0;
shi++;

if(shi == 24)
{
shi = 0;
fen = 0;
miao = 0;
}
}
}

miao_L = miao % 10;
miao_H = miao / 10;

fen_L = fen % 10;
fen_H = fen / 10;

shi_L = shi % 10;
shi_H = shi / 10;

}
}



📚仿真示例二资源文件和程序

1
2
3
链接:https://pan.baidu.com/s/1xTLmVUX0bPQFaO\_ApY4gNw 
提取码:8d2e

🏳‍🌈相关知识补充说明

  • 🌿使用了XBYTE后,就不用顾及其时序,(读写数据的时候,WR和RD信号引脚怎么都不用用程序去控制)

外部总线由3组总线组成:数据、地址、控制,我们常常一般就叫他外部总线,既然是有3组不同的信号,那么他们是怎么协调工作的呢?一般情况CPU有特殊的外部数据访问指令如你这里讲51的MOVX指令(在C语言中他会编译成这个指令)在执行这个指令的时候3组线是协调工作。

  • 👉🏻参考ARM for 8051对XDATA的举例说明:https://developer.arm.com/documentation/101655/0961/Ax51-User-s-Guide/Writing-Assembly-Programs/Memory-Access/XDATA?lang=en
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
?XD?my_seg SEGMENT XDATA                ; define a SEGMENT of class XDATA
RSEG ?ED?my_seg
XBUFFER: DS 100 ; reserve 100 Bytes

?PD?myvars SEGMENT XDATA INPAGE ; define a paged XDATA segment
RSEG ?PD?myvars
VAR1: DS 1 ; reserve 1 byte

?PR?myprog SEGMENT CODE ; define a segment for program code
RSEG ?PR?myprog
MOV P2,#HIGH ?PD?myvars ; load page address register
:
MOV DPTR,#XBUFFER ; load address
MOVX A,@DPTR ; access via DPTR
MOV R1,#VAR1 ; load address
MOVX @R1,A ; access via R0 or R1


  • 🌿头文件absacc.h
✨#include<absacc.h>//绝对地址处理头文件,包含XBYTE,用XBYTE来定义扩展的IO端口及外部RAM单元地址, 用XBYTE定义的目的是将外部电路不同的功能编程不同的地址而已这样就可以在程序里面通过直接对地址附置,就能使外部电路实现需要的功能,这样做还有一个好处就是在编译的时候会产生MOVX 指令,这样可以操作WR和RD引脚(在本示例中,的WR和WD分别接各自对应的WR和WD引脚,所以在执行读写的时候是有单片机自动完成时序控制的),以实现特定的功能,至于用XBYTE定义的地址是多少就得根据实际的外围电路的连接来确定,不是随便写的.