8051内部结构详解

发布时间:2026/7/1 14:43:11

8051内部结构详解 开局一张图功能全靠猜。数据总线白色负责传输实际数据运算数值、读取的指令、收发的 IO 数据双向传输CPU 和各个外设互相读写数据都走这条线。地址总线蓝色负责指定访问位置比如要读哪块存储单元、哪个 IO 端口先通过地址总线送出地址编号单向输出。控制总线黄色负责传输读写 / 启停 / 中断等控制信号比如读存储器、写端口、定时器启停、中断请求、时钟同步控制等指令。程序存储器ROM顾名思义就是你开发的程序所放置的位置。CPU 上电后从这里逐条读取指令执行注解交互逻辑cpu上电之后的第一件事就是通过蓝色地址总线找到程序存储器然后在通过命令总线下达读取的命令下达完读取的命令程序通过数据总线发给CPU。问题CPU为何来这里读取是所有模块都问一下还是这里有了程序主动上报给CPU然后CPU才来这里读取。答案CPU出厂规定程序存储器有固定专属的地址范围就像档案室大楼1-4096号房间。单片机一上电CPU天生默认第一件事就是去程序存储区0号地址读取第一条指令不要要告诉CPU程序放在哪里硬件底层已经固化了地址分区。不需要谁告诉 CPU 档案室在哪硬件底层已经固化了地址分区0000H ~ FFFFH 这个地址段 只属于程序存储器00H ~ 7FH 这个地址段 只属于数据存储器 CPU 只要往 “0 开头的地址” 发地址信号硬件自动就把信号送到程序存储器不会跑错部门。疑惑 1CPU怎么知道程序存储器的位置硬件提前分好地址区间访问 0 开头地址就是程序存储器天生自带定位不用查找。疑惑 2是存储器主动上报还是 CPU 主动去读100%CPU 主动上门调取存储器只会被动等待指令绝对不会主动上报。 类比 档案室不会每天主动跑到老板办公室递文件一定是老板先报房间号、再喊 “拿文件”档案室才把文件送出来。反向对比什么时候才是外设主动上报只有中断是例外只有定时器、串口、IO 这些模块触发中断时才会主动通过黄色控制线给 CPU 发消息 但程序存储器、数据存储器永远被动只能 CPU 主动读 / 写不会主动发数据。 简单区分读代码、读变量存储类模块CPU 主动找存储器定时到了、收到串口消息外设突发事件外设主动找 CPU中断系统中转极简流程一句话背诵上电→CPU 送出程序存储器地址蓝线→发读取控制命令黄线→程序存储器传回指令数据白线→CPU 执行循环往复。数据存储器RAM存放程序运行时的临时变量、中间运算结果、堆栈数据也可以理解为程序运行中所产生的草稿数据。注解地址指定 RAM 单元控制总线区分 “读数据 / 写数据”数据总线双向读写数值问题存放程序运行时的临时变量、中间运算结果、堆栈数据 在程序运行过程中 是怎么把变量写到数据存储器里面的 cpu怎么执行的 或者老板怎么做的临时变量不可能凭空产生答案先来一段小前奏cpu是不负责分配地址的是编译器提前分好写进程序里面CPU只是照着执行你写c语言int a单片机需要把你的代码翻译成机器所能识别的机器码编译器有两个工作一是把文字翻译成机器所能识别的01指令存到程序存储器二给每一个变量提前制定好固定的RAM分配地址。编译器是如何分配地址的比如你写代码unsigned char a; unsigned char b;8051 内部 RAM 有一堆空闲格子0x20、0x21、0x22…0x7F 编译器编译时自动按顺序分配变量 a → 占用 0x30变量 b → 占用 0x31 这个分配规则是软件定死的编译完成后就不会再变。 最后生成的机器指令里直接写死了 “要存数字就送到 0x30 这个地址”。CPU 完全不用管分配这件事它根本不知道 “a 叫变量 a”。 CPU 眼里只有一串固定指令算出 15 → 把地址 0x30 放到地址总线 → 发写入命令 → 把 15 送到数据总线“0x30 是给变量 a 用的” 这件事只存在你写的代码和编译器里单片机硬件只认数字地址不认变量名。场景 1自动分配普通局部变量、全局变量编译器自动挑空闲 RAM 地址分配你不用手动管。场景 2手动指定地址单片机专用语法你可以强制指定变量固定放在某一格直接写死地址由程序员决定unsigned char a _at_ 0x30;这句代码就是你人为告诉编译器变量 a 必须放在 30 号草稿纸编译器不再自动分配。全程时间线分清先后顺序写代码阶段电脑上操作单片机还没上电 你定义变量 a → 编译器给 a 分配 RAM 地址 0x30编译阶段电脑软件完成 编译器生成机器码指令里自带地址 0x30烧录程序电脑把机器码下载到 8051 程序存储器 包含 “0x30” 地址的指令永久存入档案室单片机上电运行CPU 工作阶段 CPU 读取指令看到地址 0x30直接往这个格子读写数据全程不会重新分配地址。通俗比喻总结编译器 行政文员提前给所有文件变量分好固定的草稿纸编号写进任务清单程序指令CPU 老板 打工执行者只照着清单上写好的编号去存取数字没有分配地址的权限RAM 草稿仓库 一堆空白纸本身没有归属分配工作在上电之前就全部做完了。定时 / 计数器T0/T1定时延时、外部脉冲计数、产生串口波特率交互CPU 通过总线配置计数初值、启停计数溢出后通过中断系统通知 CPU。问题CPU是如何设置定时计数器的代码内又是如何写的一、先分清定时器和 RAM 草稿纸分配完全不一样变量 RAM 地址是电脑编译器提前分 定时计数器T0、T1是出厂硬件固定分配好专属寄存器地址天生就锁死编号编译器不能随便改。1. 8051 硬件规定死的地址行政出厂直接划分不用编译器分配定时计数器本质是几片特殊寄存器统一放在特殊功能寄存器 SFR 区硬件焊死地址TH0、TL0定时器 0 高低 8 位计数寄存器固定地址 0x8C、0x8ATH1、TL1定时器 1 高低 8 位计数寄存器固定地址 0x8D、0x8BTMOD定时器模式设置寄存器固定 0x89TCON定时器启停、溢出标志寄存器固定 0x88类比 程序出厂前厂房行政芯片硬件直接划定 0x88 号格子 定时器开关面板 0x8A/8C 定时器 0 的计数草稿本 0x8B/8D 定时器 1 的计数草稿本 这块区域专门分给计时员任何人不能挪用。二、编译器做什么只是 “翻译名字”不分配地址你写代码TMOD0x01;编译器只做翻译把单词TMOD替换成硬件固定地址0x89不会重新分配地址不能把定时器挪去别的格子生成机器指令里直接写死地址 0x89CPU 上电照着地址操作。三、CPU老板完整操控定时器的执行流程严格遵循先地址→后控制→传数据需求举例开启定时器 0设置成 16 位定时模式步骤 1CPU 从程序存储器读取指令任务清单指令内容翻译成人话把数字 0x01 写入 0x89 号格子TMOD蓝地址总线送出 0x89定时器模式寄存器固定地址黄控制总线发「写入」命令白数据总线把 0x01 送进去定时器硬件收到模式参数步骤 2给定时器设置计数初值比如定时 50ms指令给 TL0 (0x8A) 写 0x06TH0 (0x8C) 写 0xFF地址线依次送出 0x8A、0x8C下发写命令把计算好的初始数字存入定时器专属计数寄存器步骤 3启动定时器操作 TCON 寄存器 0x88写指令 TR01对应地址 0x88 里某一位置 1地址总线 0x88 锁定定时器控制面板写控制信号数据总线送出开启信号计时员正式开始自动倒数四、定时器自动计数不用 CPU 一直盯着时钟晶振给定时器提供脉冲硬件自己逐次减数字CPU 设置完参数、打开开关后就可以去干别的事跑其他代码定时器硬件独立工作每来一个时钟脉冲自动减 1计数减到 0计时完成硬件自动把 TCON 里的溢出标志 TF0 置 1。五、CPU 怎么知道计时结束两种方式方式 1CPU 主动查询老板抽空去看计时员循环读取 TCON 寄存器地址 0x88读出标志位判断是否计时完成地址总线 0x88发读控制信号取回寄存器数据判断 TF0 标志位方式 2中断自动上报计时员走控制线主动通知老板开启定时器中断后 定时器溢出 → 通过黄色控制总线给中断系统发紧急信号 → 中断系统通知 CPU 暂停当前任务处理定时任务。六、核心总结回答你的疑问定时计数器是谁分配、CPU 怎么操作分配者芯片硬件出厂固定分配专属 SFR 地址不是编译器、不是 CPU 分配编译器仅负责把代码里的定时器名称翻译成硬件固定地址CPU 全程只执行读写指令先送定时器寄存器固定地址→发读写控制命令→传输配置 / 计数值定时器是独立硬件配置完成后自动计时到点要么等 CPU 查询要么主动发中断通知 CPU。CPU是如何设置定时计数器的代码内又是如何写的分两部分讲①代码怎么写 ②CPU 硬件内部完整执行过程沿用之前比喻CPU 老板定时器 T0/T1 是独立计时员有固定专属房间号SFR 寄存器地址出厂焊死不能改。一、先认识定时器 4 个核心寄存器硬件固定地址8051 只有 T0、T1 两个定时器配置全靠这 4 个寄存器地址硬件定死TMOD地址0x89设置定时器工作模式定时 / 计数、8 位 / 16 位等TCON地址0x88启停开关 计时完成标记TR01开启 T0TR00关闭 T0TF0计时走完自动置 1 标记TL0(0x8A)、TH0(0x8C)T0 计数高低 8 位存放计时初始值TL1(0x8B)、TH1(0x8D)T1 计数高低 8 位二、C 语言代码示例8051 常用 Keil C51需求配置定时器 016 位定时模式定时 50ms溢出触发中断// 1. 配置模式寄存器TMOD TMOD 0x01; // 0000 0001T0设为16位定时器模式 // 2. 装载计时初值11.0592晶振定时50ms TH0 0x3C; TL0 0xB0; // 3. 开启定时器0中断 ET0 1; EA 1; // 4. 启动定时器0 TR0 1;代码字面意思TMOD0x01给计时员规定工作方式16 位倒计时TH0/TL0给计时员一张初始数字让它从这个数往下数数到 0 就是计时结束ET01;EA1允许计时员时间到了主动喊老板中断TR01按下计时开关开始倒计时三、编译器做了什么上电前电脑完成你写的TMOD、TH0这些英文只是名字编译器提前翻译TMOD→ 硬件地址0x89TH0→ 地址0x8CTL0→ 地址0x8A编译后生成机器码指令里直接写死地址烧录进程序存储器档案室。四、CPU老板执行每一行代码的硬件完整流程重点严格顺序地址→控制→数据以执行TMOD 0x01;这一句举例步骤 1CPU 从程序存储器取出这条指令地址总线送出程序存储器地址 → 控制线发读信号 → 数据总线取回机器码指令CPU 解析指令把数字 0x01写入地址 0x89 的寄存器步骤 2向定时器寄存器写入配置总线三步固定顺序先送地址蓝色地址总线CPU 把0x89放到地址总线上硬件识别这是 TMOD 定时器模式房间锁定目标后发控制命令黄色控制总线CPU 发出「写入」控制信号通知硬件准备接收数据传输数据白色数据总线CPU 把数值0x01放到数据总线存入 TMOD 寄存器定时器模式配置完成。再执行TH0 0x3C;地址总线输出固定地址0x8CTH0 专属地址控制线发送「写入」命令数据线送出0x3C存入 TH0再执行TL0 0xB0;地址总线输出0x8A写控制信号存入0xB0最后执行TR0 1;启动定时器地址总线输出 TCON 地址0x88写入控制信号数据线送入数据把 TR0 开关位置 1定时器正式开始自动计数五、定时器启动后CPU 不用管硬件独立运行晶振提供统一时钟脉冲定时器硬件自动减计数 每一个机器周期TH0 TL0里的数字自动减 1 等数字减到 0硬件自动把标记位 TF0 置 1。两种处理方式查询方式老板主动抽查CPU 循环读 TCON 寄存器地址0x88读取 TF0 位判断是否计时完成中断方式计时员主动上报TF0 置 1 后通过黄色控制总线向中断系统发请求中断系统通知 CPU 停下当前工作执行定时任务。六、汇编底层代码最贴近 CPU 执行看懂 C 语言本质上面 C 语言等价汇编能直观看到地址操作MOV TMOD,#01H ; 等价TMOD0x01#01H是要写入的数据TMOD是0x89地址别名 MOV TH0,#3CH ; TH00x3C MOV TL0,#0B0H ; TL00xB0 SETB ET0 SETB EA SETB TR0 ; 启动定时器汇编里MOV 地址,#数据就是 CPU 标准操作送地址、发写命令、传数据。极简总结代码层直接操作TMOD、TH0、TL0、TR0这几个定时器专用寄存器配置模式、初值、开关编译层软件把寄存器名字翻译成硬件出厂固定的 SFR 地址CPU 硬件执行层每一次配置都遵循固定流程输出寄存器地址→发送写入控制信号→传输配置数值配置完成后定时器硬件独立计时到点主动触发中断通知 CPU。并行 I/O 口P0~P3作用通用数字输入输出控制 LED、按键、继电器等外设交互CPU 通过总线读写端口寄存器实现引脚高低电平控制与外部信号读取。深入理解IO口本质是特殊功能寄存器SFR8051有四组IO口P0P1P2P3硬件出厂直接分配固定地址不能改P00x80P10x90P20xA0P30xB0比喻P1 口就是一块 8 个按钮的控制面板房间号固定 0x90老板CPU只能通过三条总线读写这个房间的数据控制外部 LED、按键。 每条 IO 引脚对应寄存器里的 1 个 bit比如 P1.0 P1 寄存器第 0 位。就是每个端口有b位每位对应着外面一个引脚。1. P1 寄存器 一块 8 格控制面板8bit地址固定房间号0x90一共 8 个小格子bit0 ~ bit7bit0 → P1.0 引脚bit1 → P1.1 引脚bit2 → P1.2 引脚bit3 → P1.3 引脚bit4 → P1.4 引脚bit5 → P1.5 引脚bit6 → P1.6 引脚bit7 → P1.7 引脚每 1 个 bit一对一连着芯片外面一根金属引脚寄存器里这一格存 0/1引脚电平就跟着变。场景 1IO 输出点亮 LEDP1.0 接 LED 负极#include reg51.h sbit LED P1^0; // 单独定义P1第0根引脚 void main(void) { LED 0; // P1.0输出低电平 → LED点亮 LED 1; // P1.0输出高电平 → LED熄灭 // 整体操作整个P1端口8位一次性赋值 P1 0x0F; // P1低4脚输出0高4脚输出1 while(1); }步骤 1CPU 从程序存储器取出指令CPU 通过地址总线、读控制信号拿到机器指令解析出任务把 0 写入地址 0x90 寄存器的第 0 位步骤 2CPU 发起「写 IO 寄存器」总线操作严格顺序蓝色地址总线先输出地址 0x90锁定 P1 口专属硬件模块其余端口全部休眠黄色控制总线发送「写入」控制命令通知 IO 硬件准备接收数据白色数据总线传输数值 0x00数据送入 P1 寄存器内部锁存器P1.0 引脚立刻输出低电平LED 点亮。场景 2IO 输入读取按键P3.2 接按键c运行#include reg51.h sbit KEY P3^2; void main(void) { unsigned char val; while(1) { val KEY; // 读取P3.2引脚电平存入变量val if(val 0) { // 按键按下执行逻辑 } } }任务读取地址 0xB0P3寄存器的值存到 RAM 变量 val蓝色地址总线输出地址 0xB0锁定 P3 口黄色控制总线发送「读取」命令P3 硬件把引脚电平数据放到白色数据总线传回 CPU 内部CPU 把读到的数值再通过「写 RAM 总线流程」存入变量 val 对应的 RAM 草稿地址。串行通信口UART作用串口收发数据和电脑、其他单片机通信交互CPU 把待发数据通过数据总线写入发送寄存器接收数据存入寄存器供 CPU 读取。中断系统作用处理紧急事件定时器溢出、串口收发、外部引脚中断打断当前程序优先处理突发事件交互外设触发中断后通过控制总线向 CPU 发中断请求CPU 响应后跳转中断服务程序。中断系统如何触发的cpu如何交互代码如何写分三层讲1. 中断怎么触发 2.CPU 和中断系统交互完整流程 3. 实际 C 语言代码 底层硬件动作继续沿用比喻 CPU 老板定时器 / 串口 / IO 员工中断系统 前台接待黄色控制线 紧急呼叫铃一、中断系统什么时候触发3 类触发源8051 一共 5 个硬件中断全部是外设硬件自动触发不用 CPU 干预定时器 0 溢出中断T0 计数从初值减到 0硬件自动拉高中断请求信号定时器 1 溢出中断T1 计数走完自动发请求外部中断 0 INT0引脚 P3.2 收到高低电平 / 下降沿触发外部中断 1 INT1引脚 P3.3 信号变化触发串口收发中断串口收到数据 / 数据发送完毕触发触发核心逻辑定时器举例定时器硬件独立计数不用老板盯着 当计数归零瞬间定时器硬件直接走黄色控制总线给中断前台发一条紧急信号「我干完了需要老板处理」重点不是 CPU 主动问是硬件主动通过控制线上报。二、CPU 与中断系统完整交互全过程严格顺序前置硬件开关两个总闸门局部开关ET0/ET1/EX0/EX1/ES —— 单独开启某一个设备的上报权限总闸门EA —— CPU 总开关EA1 老板才愿意接任何紧急电话EA0 所有中断全部无视完整 5 步流程定时器 0 计时完成触发中断外设发起请求T0 计数溢出硬件把 TCON 寄存器 TF0 标记置 1同时向中断系统前台发送脉冲信号黄色控制线。中断系统做筛选判断前台检查两层闸门局部开关 ET01允许定时器上报总开关 EA1老板允许接紧急事件 两个开关全开才把中断请求转发给 CPU只要有一个关闭请求直接作废。CPU 收到信号暂停当前工作CPU 正在执行普通代码收到中断控制线的紧急信号后立刻停下手里正在做的运算 / 读写操作把当前正在运行代码的地址PC 值、寄存器数据临时压入堆栈数据存储器 RAM保存方便事后回来继续干活。自动跳转中断服务程序硬件内置固定跳转地址中断入口地址出厂焊死 定时器 0 中断固定入口000BH CPU 自动把地址 000BH 送到地址总线读取这里的代码执行中断任务。中断处理完成返回原来程序中断里的业务代码执行完毕执行return CPU 从堆栈把之前保存的现场数据恢复回到被打断的地方继续原来没做完的工作。补充两种清除中断标志规则定时器 / 外部下降沿中断CPU 响应中断后硬件自动清零 TF0 标记不用手动操作串口中断必须在代码里手动清零 RI/TI 标志否则会重复触发中断。三、代码怎么写C 语言完整示例定时器 050ms 中断1. 完整可运行代码c运行#include reg51.h sbit led P1^0; // 定义LED引脚 // 定时器0中断服务函数固定interrupt 1对应T0中断编号 void Timer0_Init() interrupt 1 { // 重装计时初值避免每次只计时一次 TH0 0x3C; TL0 0xB0; led ~led; // LED翻转亮灭每50ms翻转一次 } void main(void) { // 1.配置定时器模式 TMOD 0x01; // 2.装载计时初值 TH0 0x3C; TL0 0xB0; // 3.打开定时器0局部中断开关 ET01 ET0 1; // 4.打开CPU中断总开关 EA1必须开否则中断无效 EA 1; // 5.启动定时器T0 TR0 1; // 主循环CPU平时在这里循环跑中断来了自动打断 while(1) { // 主程序日常任务 } }代码关键字解释ET01打开定时器 0 单独上报权限局部闸门EA1打开 CPU 总中断开关总闸门缺一不可interrupt 1告诉编译器这个函数是定时器 0 中断专用处理函数interrupt 0外部中断 0interrupt 1定时器 0 中断interrupt 2外部中断 1interrupt 3定时器 1 中断interrupt 4串口中断编译器底层处理编译器会自动在程序存储器的中断入口地址000BH写入跳转指令一旦触发中断CPU 硬件自动跳转到这个函数执行不用人为判断。四、配套汇编代码看懂机器底层逻辑asmORG 0000H LJMP MAIN ;上电跳主函数 ORG 000BH ;定时器0固定中断入口地址 LJMP Timer0 ;跳转到中断处理程序 MAIN: MOV TMOD,#01H MOV TH0,#3CH MOV TL0,#0B0H SETB ET0 ;开T0局部中断 SETB EA ;开总中断 SETB TR0 ;启动定时器 SJMP $ ;主循环原地等待 Timer0: ;中断服务程序 MOV TH0,#3CH MOV TL0,#0B0H CPL P1.0 ;翻转LED RETI ;中断返回指令恢复现场回到主程序RETI是中断专用返回和普通 RET 不同会清除中断内部标记告知中断系统本次事件处理完毕。五、极简总结梳理触发定时器 / 串口 / 外部引脚硬件完成工作后主动通过黄色控制总线向中断系统发请求交互中断系统校验中断开关→通知 CPU→CPU 保存当前运行现场→跳转专属中断代码→执行完恢复现场继续原程序代码核心两点① 打开局部中断位 全局 EA 总开关 ② 编写带interrupt x的专用中断函数硬件自动触发调用无需手动判断标志。

相关新闻