【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;
📚仿真示例一资源和程序源码
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
✨#include<absacc.h>//绝对地址处理头文件,包含XBYTE,用XBYTE来定义扩展的IO端口及外部RAM单元地址, 用XBYTE定义的目的是将外部电路不同的功能编程不同的地址而已这样就可以在程序里面通过直接对地址附置,就能使外部电路实现需要的功能,这样做还有一个好处就是在编译的时候会产生MOVX 指令,这样可以操作WR和RD引脚(在本示例中,的WR和WD分别接各自对应的WR和WD引脚,所以在执行读写的时候是有单片机自动完成时序控制的),以实现特定的功能,至于用XBYTE定义的地址是多少就得根据实际的外围电路的连接来确定,不是随便写的.
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!