好的,我来帮你系统地解析这道题。这是一个经典的 8051 单片机扩展外部程序存储器(EPROM) 的题目,涵盖了硬件电路设计和软件编程两个方面。下面分步讲解。
一、题目核心要求解析
要素 说明
MCU 89C51(内部有 4KB Flash,地址 0000H~0FFFH)
EPROM 27128(16K×8 bit,地址 0000H~3FFFH)
真值表位置 外部 ROM 的 1000H 开始的单元
功能 按键计数,在数码管上显示按键次数
关键点 真值表必须放在 外部 ROM 中,程序用 MOVC 查表读取
二、27128 芯片引脚功能
你提到的引脚对应关系:
27128 引脚 功能说明
Q0~Q7 数据输出线(8 位),接 89C51 的 P0 口
A0~A13 地址线(14 位),寻址 16K 空间
/E (OE) 输出使能(低有效),接 89C51 的 PSEN
/G (CE) 片选(低有效),直接 接地 或接译码电路
补充:27128 还有 VCC (+5V)、GND、VPP(编程高压,正常使用时接+5V)等引脚。
三、扩展电路设计原理
8051 访问外部程序存储器时,P0 口分时复用(先送低8位地址,后传数据),P2 口提供高8位地址,因此需要 地址锁存器。
关键信号连接
89C51 引脚 连接目标 作用
P0.0~P0.7 → 74HC373 的 D0~D7(输入侧) 分时输出低8位地址 / 输入数据
74HC373 的 Q0~Q7 → 27128 的 A0~A7 锁存后的低8位地址
P2.0~P2.5 → 27128 的 A8~A13 高6位地址(P2.6、P2.7 可做其他用途)
ALE → 74HC373 的 LE (锁存使能) 地址锁存控制
PSEN → 27128 的 /E (OE) 外部程序存储器读选通
EA → VCC (+5V) 先访问内部 ROM,超范围自动转外部
27128 的 /G (CE) → GND 始终片选有效
P1 口 → 数码管段码(如共阴数码管 a~dp) 显示按键次数
完整电路原理图(文字描述)
+-----------+
P0.0~P0.7 -->| D0~D7 Q0|--> A0~A7 +-----------+
ALE -->| LE Q7|--> | |
| 74HC373 | | 27128 |
+-----------+ | EPROM |
| |
P2.0~P2.5 ----------------------------------->| A8~A13 |
| |
PSEN ------------------------------------->| /E (OE) |
| |
GND ------------------------------------->| /G (CE) |
| |
+5V ------------------------------------->| VPP, VCC |
+-----------+
89C51 EA --> VCC (+5V) // 先访问内部4KB,超0FFFH自动转外部
P1.0~P1.7 --> 数码管段码 (a~dp + dp)
P3.2 (INT0) --> 按键输入 (或P3.3等)
地址映射说明
89C51 内部 ROM 地址范围:0000H ~ 0FFFH(4KB)27128 外部 ROM 地址范围:0000H ~ 3FFFH(16KB)
EA=1 时的访问规则:
地址 0000H~0FFFH:访问内部 Flash(程序代码放这里)
地址 1000H~3FFFH:自动转向外部 27128 读取
所以 真值表放在 1000H~10xxH,程序放在内部 0000H~0FFFH,互不冲突 ✅
四、软件程序设计
4.1 真值表定义(要烧录到 27128 中)
假设使用 共阴极数码管,段码顺序:a→b→c→d→e→f→g→dp
地址 内容 显示
1000H → 3FH 0
1001H → 06H 1
1002H → 5BH 2
1003H → 4FH 3
1004H → 66H 4
1005H → 6DH 5
1006H → 7DH 6
1007H → 07H 7
1008H → 7FH 8
1009H → 6FH 9
假设使用 共阳极数码管,段码顺序:a→b→c→d→e→f→g→dp
地址 内容 显示
1000H → C0H 0
1001H → F9H 1
1002H → A4H 2
1003H → B0H 3
1004H → 99H 4
1005H → 92H 5
1006H → 82H 6
1007H → F8H 7
1008H → 80H 8
1009H → 90H 9
烧录 27128 时需要编程器,将上述数据按地址写入 27128 中。
4.2 89C51 程序(汇编语言)
;============================================
; 89C51 + 27128 外部ROM 按键计数显示程序
; 程序放在内部 Flash,真值表在外部ROM 1000H
;============================================
ORG 0000H ; 复位入口
LJMP MAIN
ORG 0030H ; 主程序起始地址
MAIN:
MOV SP, #60H ; 设置堆栈
MOV P1, #00H ; 数码管初始灭
CLR A
MOV R0, #00H ; R0 作为按键计数器(0~9循环)
LOOP:
; 检测按键(假设按键接P3.2,低有效)
JB P3.2, LOOP ; 没按下则等待
ACALL DELAY_20MS ; 消抖
JB P3.2, LOOP ; 再次确认
; 按键已按下,计数加1
INC R0
CJNE R0, #10, DISP ; 到10则回0
MOV R0, #00H
DISP:
; 从外部ROM 1000H 查表读取段码
MOV DPTR, #1000H ; 真值表基地址
MOV A, R0 ; 取计数值
MOVC A, @A+DPTR ; 从外部ROM读取段码
MOV P1, A ; 输出到数码管
; 等待按键释放
WAIT_UP:
JNB P3.2, WAIT_UP ; 按键未释放则等待
ACALL DELAY_20MS ; 消抖
JNB P3.2, WAIT_UP
SJMP LOOP ; 继续循环
; 简单延时子程序(假设12MHz晶振)
DELAY_20MS:
MOV R6, #40
DLY1:
MOV R7, #248
DJNZ R7, $
DJNZ R6, DLY1
RET
END
4.3 C语言版本(可读性更好)
#include <reg51.h>
sfr P1 = 0x90; // 数码管段码输出口
sbit KEY = P3^2; // 按键输入
void delay_ms(unsigned int ms)
{
unsigned int i, j;
for(i = 0; i < ms; i++)
for(j = 0; j < 125; j++);
}
unsigned char read_external_rom(unsigned int addr)
{
unsigned char code *pt; // code 指向程序存储区
pt = (unsigned char code *)addr;
return *pt;
}
void main()
{
unsigned char count = 0;
unsigned char seg;
while(1)
{
if(KEY == 0) // 检测按键按下
{
delay_ms(20); // 消抖
if(KEY == 0)
{
count++;
if(count >= 10) count = 0;
// 从外部ROM 1000H + count 处读取段码
seg = read_external_rom(0x1000 + count);
P1 = seg; // 输出到数码管
while(KEY == 0); // 等待释放
delay_ms(20);
}
}
}
}
五、关键知识点总结
为什么要用锁存器 74HC373?
8051 的 P0 口是 分时复用 的:在读取外部 ROM 时,P0 先输出 低8位地址(A0~A7),随后切换为 数据总线(D0~D7)。锁存器的作用就是把先出现的地址"锁存"住,让 EPROM 在整个读周期都能拿到稳定的地址。
为什么 PSEN 接 /E 而不是 RD?
PSEN(Program Store Enable)是 8051 专用于读取 外部程序存储器 的选通信号
RD(P3.7)是用于读取 外部数据存储器(RAM/IO)的信号
27128 是 程序存储器(ROM),所以用 PSEN 控制
为什么 EA 接 VCC?
EA=1 时,CPU 优先从内部 ROM 取指,只有 地址超过内部 ROM 范围(89C51 为 0FFFH)时,才自动转向外部 ROM。这样:
程序代码放内部 Flash(0000H~0FFFH)
MOVC 查表时地址 1000H 自动指向外部 ROM ✅
如果 EA=0,则 CPU 完全从外部 ROM 取指,这种情况下程序代码也需烧入 27128。
MOVC 指令与外部 ROM 的关系
MOV DPTR, #1000H ; 指向外部 ROM 地址
MOV A, R0 ; 偏移量 = 计数值
MOVC A, @A+DPTR ; 读取 (1000H + R0) 处的数据
执行 MOVC 时,CPU 自动:
P0/P2 输出地址(1000H+R0)
ALE 锁存地址
PSEN 输出低脉冲 → 27128 的 /E 被选通
27128 输出数据到 P0 → 读入 ACC
题目的本质:你要把数码管的段码真值表(共阴极或共阳极的0~9段码)烧录到27128里,放在地址 1000H 起始的位置。单片机运行时,通过 MOVC 指令 从外部程序存储器读取段码,送给数码管显示按键次数。
✅ 不是把段码写在程序里,而是存在外扩的27128里——这就是老师要考核的外部ROM扩展 + MOVC查表。
|