用89C51单片机控制并行接口芯片8255实现6 位八段码 LED 动态方式循环显示一组数据。
8255A是一种可编程并行I/O口的拓展芯片,可用于拓展多组8位并行I/O口。
其实,在程序编写上,8255芯片就相当于拓展一个外部RAM,对它的操作就用指令MOVX即可
我们需要对它的操作是:
所以我们如果需要使用PA口和PB口输出并且使用方式1的话,那么控制字写为1000 0000,则程序为:
MOV DPTR,#0FF23H //控制口地址
MOV A,#80H
MOVX @DPTR,A
MOV DPTR,#0FF21H //写入PB口数据
MOVX @DPTR,A
MOV DPTR,#0FF20H //写入PA口数据
MOV A,R2
MOVX @DPTR,A
单片机在拓展外部芯片时,通常都会使用74LS373作为地址锁存器。
值得一提的是,RD和WR是由硬件自动控制,不需要对其进行软件编程控制。
则单片机与8255的连接如下:
1.汇编语言程序
OUTBIT EQU 0FF20H
LEDBUF EQU 60H //存储数据
NUM EQU 70H //显示数据
DELAYT EQU 75H
ORG 0000H
LJMP START
LEDMAP:DB 0C0H,0F9H,0A4H,0B0H,99H,92H,82H,0F8H
DB 80H,90H,88H,83H,0C6H,0A1H,86H,8EH
DELAY:
MOV R7,#0
DELAYLOOP:
DJNZ R7,DELAYLOOP
DJNZ R6,DELAYLOOP
RET
DISPLAYLDE:
MOV R0,#LEDBUF
MOV R1,#6
MOV R2,#11011111B //从左边开始显示
LOOP:
MOV DPTR,#OUTBIT
MOV A,#0FFH
MOVX @DPTR,A
MOV A,@R0
MOV DPTR,#0FF21H
MOVX @DPTR,A
MOV DPTR,#OUTBIT
MOV A,R2
MOVX @DPTR,A
MOV R6,#8
CALL DELAY
MOV A,R2
RR A //A循环右移
MOV R2,A
INC R0
DJNZ R1,LOOP
MOV DPTR,#OUTBIT
MOV A,#0FFH
MOVX @DPTR,A
RET
START:
MOV DPTR,#0FF23H //控制口地址
MOV A,#81H
MOVX @DPTR,A
MOV SP,#40H //这句话是什么意思?
MOV NUM,#0
MLOOP:
INC NUM
MOV A,NUM
MOV B,A
MOV R0,#LEDBUF
FILLBUF:
MOV A,B
ANL A,#0FH //确保A只有一位数(16进制)
MOV DPTR,#LEDMAP
MOVC A,@A+DPTR
MOV @R0,A
INC R0
INC B
CJNE R0,#LEDBUF+6,FILLBUF
MOV DELAYT,#00
DISPAGAIN:
CALL DISPLAYLDE
DJNZ DELAYT,DISPAGAIN
LJMP MLOOP
END
2.C语言程序
(在仿真的时候有点快,但i也不能再小了(手动捂脸))
#include "reg51.h"
#include "intrins.h"
#define u8 unsigned char
#define u16 unsigned int
u8 xdata*PA=0xFF20;
u8 xdata*PB=0xFF21;
u8 xdata*CTR=0xFF23;
u16 i,j,a,b=0,p;
u16 Aa;
u8 display[16]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};
void delayms(a)
{
for(j=a;j>0;j--)
{
for(i=110;i>0;i--) ;
}
}
void main()
{
*CTR=0x80;
while(1)
{
for(p=0;p<16;p++)
{
b=p;
Aa=0xDF;
for(j=0;j<6;j++)
{
for(i=0;i<40;i++)
{
*PA=Aa;
*PB=display[b%16];
}
Aa=(Aa>>1)|(Aa<<5);
b=b+1;
}
delayms(200);
}
}
}
(1)EQU
用一个习惯的符号代替汇编语言中的关键字或指令助记符
(2)RR A
RR表循环右移,循环右移和逻辑右移的区别是:循环右移一位后,最左的数据放在最右;逻辑右移一位后,最左补零。
C语言里没有循环左移或循环右移的操作符,但可以灵活处理,比如,操作数x有s位循环n位
则循环左移:x=(x<
循环右移:x=(x>>n)|(x<<(s-n))
(3)6位动态数码管显示的实现:
MOV R2,#11011111B
MOV A,R2
RR A
(4)proteus中图纸大小的设置是在:系统—>设置纸张大小
(5)unsigned char xdata 无符号片外数据指针
unsigned char xdata * p
表指针指向一个处于xdata的元素
xdata unsigned char * p=unsigned char * xdata p
表明指针本身位于xdata中
(1)#define unsigned char u8
报错:attempt to redefine macro ‘unsigned’
正确的写法:#define u8 unsigned char
(2)先对PA赋值再对PB赋值
两者孰前孰后还是很有区别的
(3)这个for循环是必要的,虽然不知道为什么
for(i=0;i<40;i++)
{
*PA=Aa;
*PB=display[b%16];
}