89C51
回帖(1)
2021-10-8 15:10:26
一、实验要求
用89C51单片机控制并行接口芯片8255实现6 位八段码 LED 动态方式循环显示一组数据。
二、8255接口芯片的简介
(1)8255芯片是什么
8255A是一种可编程并行I/O口的拓展芯片,可用于拓展多组8位并行I/O口。
(2)如何对8255芯片编程
其实,在程序编写上,8255芯片就相当于拓展一个外部RAM,对它的操作就用指令MOVX即可
我们需要对它的操作是:
1)对其控制字地址写入对各个I/O口的模式
其中方式0、方式1、方式2为:
所以我们如果需要使用PA口和PB口输出并且使用方式1的话,那么控制字写为1000 0000,则程序为:
MOV DPTR,#0FF23H //控制口地址MOV A,#80HMOVX @DPTR,A 2)对各个I/O的地址写入需要显示的数字
MOV DPTR,#0FF21H //写入PB口数据 MOVX @DPTR,A MOV DPTR,#0FF20H //写入PA口数据 MOV A,R2 MOVX @DPTR,A (3)8255芯片与51单片机如何连接
单片机在拓展外部芯片时,通常都会使用74LS373作为地址锁存器。
值得一提的是,RD和WR是由硬件自动控制,不需要对其进行软件编程控制。
则单片机与8255的连接如下:
三、代码
1.汇编语言程序
OUTBIT EQU 0FF20HLEDBUF 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.学到了学到了
(1)EQU
用一个习惯的符号代替汇编语言中的关键字或指令助记符
(2)RR A
RR表循环右移,循环右移和逻辑右移的区别是:循环右移一位后,最左的数据放在最右;逻辑右移一位后,最左补零。
C语言里没有循环左移或循环右移的操作符,但可以灵活处理,比如,操作数x有s位循环n位
则循环左移:x=(x<>(s-n))
循环右移: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中
2.调程序有得
(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];
}
一、实验要求
用89C51单片机控制并行接口芯片8255实现6 位八段码 LED 动态方式循环显示一组数据。
二、8255接口芯片的简介
(1)8255芯片是什么
8255A是一种可编程并行I/O口的拓展芯片,可用于拓展多组8位并行I/O口。
(2)如何对8255芯片编程
其实,在程序编写上,8255芯片就相当于拓展一个外部RAM,对它的操作就用指令MOVX即可
我们需要对它的操作是:
1)对其控制字地址写入对各个I/O口的模式
其中方式0、方式1、方式2为:
所以我们如果需要使用PA口和PB口输出并且使用方式1的话,那么控制字写为1000 0000,则程序为:
MOV DPTR,#0FF23H //控制口地址MOV A,#80HMOVX @DPTR,A 2)对各个I/O的地址写入需要显示的数字
MOV DPTR,#0FF21H //写入PB口数据 MOVX @DPTR,A MOV DPTR,#0FF20H //写入PA口数据 MOV A,R2 MOVX @DPTR,A (3)8255芯片与51单片机如何连接
单片机在拓展外部芯片时,通常都会使用74LS373作为地址锁存器。
值得一提的是,RD和WR是由硬件自动控制,不需要对其进行软件编程控制。
则单片机与8255的连接如下:
三、代码
1.汇编语言程序
OUTBIT EQU 0FF20HLEDBUF 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.学到了学到了
(1)EQU
用一个习惯的符号代替汇编语言中的关键字或指令助记符
(2)RR A
RR表循环右移,循环右移和逻辑右移的区别是:循环右移一位后,最左的数据放在最右;逻辑右移一位后,最左补零。
C语言里没有循环左移或循环右移的操作符,但可以灵活处理,比如,操作数x有s位循环n位
则循环左移:x=(x<>(s-n))
循环右移: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中
2.调程序有得
(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];
}
举报
更多回帖