实验7-1_八段 LED 数码管显示实验

一、实验要求

用89C51单片机控制并行接口芯片8255实现6 位八段码 LED 动态方式循环显示一组数据。

二、8255接口芯片的简介

(1)8255芯片是什么

8255A是一种可编程并行I/O口的拓展芯片,可用于拓展多组8位并行I/O口。

(2)如何对8255芯片编程

其实,在程序编写上,8255芯片就相当于拓展一个外部RAM,对它的操作就用指令MOVX即可
我们需要对它的操作是:

1)对其控制字地址写入对各个I/O口的模式

实验7-1_八段 LED 数码管显示实验_第1张图片

实验7-1_八段 LED 数码管显示实验_第2张图片
其中方式0、方式1、方式2为:
实验7-1_八段 LED 数码管显示实验_第3张图片
实验7-1_八段 LED 数码管显示实验_第4张图片
实验7-1_八段 LED 数码管显示实验_第5张图片

所以我们如果需要使用PA口和PB口输出并且使用方式1的话,那么控制字写为1000 0000,则程序为:

MOV DPTR,#0FF23H //控制口地址
MOV A,#80H
MOVX @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的连接如下:
实验7-1_八段 LED 数码管显示实验_第6张图片

三、代码

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);	 
			}	
	}
}
四、仿真结果

实验7-1_八段 LED 数码管显示实验_第7张图片
实验7-1_八段 LED 数码管显示实验_第8张图片

实验7-1_八段 LED 数码管显示实验_第9张图片

五、学习小得

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];
}

你可能感兴趣的:(#,51单片机编程与仿真,单片机,嵌入式)