单片机交流
直播中

半导体开发

10年用户 854经验值
擅长:可编程逻辑
私信 关注
[问答]

如何用89C51单片机控制八段LED数码管显示?

如何用89C51单片机控制八段LED数码管显示?

回帖(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];
}
举报

更多回帖

发帖
×
20
完善资料,
赚取积分