简介这份实验指导书面向电子信息、自动化等专业学习嵌入式系统的学生由襄樊学院物理与电子信息工程学院编写用于支撑单片机与嵌入式课程实验教学。全包共1个doc文档约965KB内容完整覆盖6个实验从实验目的、设备、原理环境到内容、步骤及报告格式均有规范说明。首个实验围绕Keil C51汇编语言与ZY15MCU12BD综合单片机实验箱展开讲解工程建立、源文件加入、编译连接、软件模拟与硬件仿真并实现P1.0输出1Hz方波、P1.0与P1.1输出反相方波等任务后续实验延伸至十六进制与十进制转换等顺序结构编程训练。文档还明确预习报告、程序清单与实验总结的撰写要求可作为课程配套上机手册与实验报告模板使用。已有338人学习下载适合需要按步骤完成实验、理解开发流程与汇编编程的读者参考。1. 六个实验拆开看这份 8051 实验指导书到底能跑通什么手上这份《嵌入式系统实验指导书6个实验》不是那种只给目录和思考题的“空壳文档”它把每个实验的目的、设备、原理、接线、流程图、参考程序清单和实验报告格式都写全了。核心平台是 8051 内核单片机加一片 8255 扩展口工具链是 Keil C51 汇编环境六个实验从点灯、进制转换、数码管动态扫描、矩阵键盘一直做到 ADC0809 采样显示。适合谁一类是课程设计要交报告、要现场调试的学生另一类是刚接手 8051 老平台、需要一份能照着接线的工程人员。它解决的不是“学嵌入式要读什么”的问题而是“实验箱摆在那线怎么接、程序怎么编、结果不对看哪里”的落地问题。下面按资源结构、关键实验复现、避坑排查、进阶验证四段推进能抄的代码和参数我尽量给全。2. 实验平台与工具链先把 Keil 工程和 8255 地址空间立住2.1 硬件资源映射与地址分配这份指导书的实验全部围绕同一套硬件展开先把资源映射搞清楚后面写程序才不会乱。核心是一台综合单片机实验箱CPU 选 Atmel 89C51晶振 12MHz通过 RS232 串口与 PC 连接做硬件仿真。片外扩展了一片 8255A、B、C、控制口分别映射到片外 RAM 的 4000H、4001H、4002H、4003H。这个地址不是随便定的是实验箱译码电路决定的写程序时用MOVX DPTR,A访问DPTR 装 4000H 就是往 A 口写。8255 在六个实验里承担了不同角色实验 3 里 B 口驱动 8 段 LED 的段码A 口驱动位选实验 4 里 C 口低 4 位做行输入、高 4 位做列驱动实验 5 里 ADC0809 的启动和读取映射到 8004H。把这张表贴在显示器边上比翻文档快得多外设端口/地址方向用途8255 A 口4000H输出LED 位选低有效8255 B 口4001H输出LED 段码低有效8255 C 口4002H高4出/低4入矩阵键盘列驱动/行读入8255 控制口4003H写方式字 10000001BADC08098004H读写启动转换/读结果EOC 反相P1.0输入查询转换结束8255 初始化方式字10000001B的含义要拆开看D71 标志位D6D500 选 A 口方式 0D40 A 口输出D30 C 口高 4 位输出D20 B 口方式 0D10 B 口输出D01 C 口低 4 位输入。这个字在实验 4 的参考程序里直接给了但实验 3 只写“A 口、B 口方式 0 输出C 口任意”实际写10000000B也能跑因为实验 3 不读 C 口。我一般统一用10000001B省得两个实验之间来回改。2.2 Keil 工程建立与汇编源文件组织指导书给的建工程流程是Project→New Project→选 Atmel 89C51→Target 选项里把晶振改成 12MHz→Output 页勾选生成 HEX→新建 .asm 文件→Add Files to Group。这套操作在 Keil C51 各版本里基本一致但有两个细节文档没强调一是工程路径不要带中文和空格E:\TEST 这种纯英文短路径最稳二是汇编文件保存时编码选 ANSI带中文注释的源文件如果存成 UTF-8老版本 Keil 打开会乱码编译报错位置还会偏移。下面这段是实验 1 的参考程序我补了注释和延时参数说明ORG 0000H ; 复位入口必须从 0000H 开始 AGAIN: CPL P1.0 ; P1.0 取反产生方波翻转 MOV R0,#10 ; 外层循环 10 次 LOOP1: MOV R1,#100 LOOP2: MOV R2,#250 DJNZ R2,$ ; 内层空转 250 次 DJNZ R1,LOOP2 DJNZ R0,LOOP1 SJMP AGAIN ; 无限循环 END延时怎么算12MHz 晶振下机器周期 1μsDJNZ R2,$本身 2 个机器周期加上循环开销约 2.5μs 一次250 次约 0.6ms乘 100 约 60ms乘 10 约 0.6s。所以实际输出接近 0.8Hz 而不是精确 1Hz文档写“1Hz”是近似值。要更准就把 R0 改成 8 或微调 R1但实验箱上肉眼看不出来不必死磕。实验 1 的第二个要求是在 P1.0 和 P1.1 输出反相方波改法很简单CPL P1.0后面加一句CPL P1.1不行那样两个口同相正确做法是初始化时SETB P1.1循环里只CPL P1.0P1.1 保持高电平反相关系或者用MOV C,P1.0再取反送 P1.1。我一般直接写AGAIN: CPL P1.0 CPL P1.1 ; 两次取反间隔一个指令周期严格说不是同时反相 ; 延时... SJMP AGAIN这样两个口电平始终相反频率一致只是翻转有 1μs 偏差实验要求“电平状态相反”完全满足。2.3 软件仿真与硬件仿真的切换条件指导书明确区分了两种运行方式程序不驱动硬件时用软件仿真Debug→Start/Stop Debug Session有硬件动作时必须连实验箱、拨 K10 到 B 端、按 SS10 复位后再进硬件仿真。这个切换点很多人翻车在软件仿真里跑得好好的程序一接硬件就没反应八成是 Debug 页没选“Use”硬件仿真器或者串口被其他软件占用。另外文档反复强调“修改程序后必须退出连接、重新编译、再重新连接”这是因为 Keil 的硬件仿真会话不会自动加载新 HEX不退出重连跑的还是旧程序。3. 三个核心实验复现数码管动态扫描、矩阵键盘、ADC 采样3.1 8 段 LED 动态显示字形表与 0.5ms 刷新节奏实验 3 是整个指导书里信息密度最高的一节。6 位 8 段 LED 采用动态驱动段码走 8255 B 口低电平有效位选走 A 口低电平有效刷新频率不低于 50Hz 才能看起来不闪。文档给了完整字形表从 0 到 F、带小数点、横杠、全灭共 34 个码按顺序排成表待显示数 00H1FH 直接做表索引。这个设计很省事20H25H 六个单元存 00H1FH 的索引显示子程序逐个取出查表送段口位码从 FEH 开始左移。显示子程序的关键参数是每位停留 0.5ms六位一轮 3ms刷新率约 333Hz远高于 50Hz不会闪。但 0.5ms 延时如果用三层循环写实际会偏长导致亮度下降。我一般用 R1 做单层计数DISP: MOV R0,#20H ; 显示缓冲区首址 MOV R2,#0FEH ; 位码左起第一位低有效 MOV DPTR,#SEGTAB ; 字形表首址 DISP1: MOV A,R0 ; 取待显示索引 MOVC A,ADPTR ; 查字形码 MOV DPTR,#4001H MOVX DPTR,A ; 段码送 B 口 MOV A,R2 MOV DPTR,#4000H MOVX DPTR,A ; 位码送 A 口 LCALL DELAY05 ; 延时 0.5ms MOV A,#0FFH MOVX DPTR,A ; 关所有位防重影 MOV A,R2 RL A ; 位码左移 MOV R2,A INC R0 CJNE R0,#26H,DISP1 RET这里有个容易忽略的点关显示要在位码移位之前做否则换位瞬间上一位的段码还留在 B 口下一位会短暂显示错误内容看起来就是“拖影”。文档流程图里画了“关闭所有显示位”这一步但参考程序清单没给完整实现很多人抄漏了。字形表按文档顺序从 0 开始排SEGTAB: DB 0C0H,0F9H,0A4H...注意 0.F. 那一段和 0F 是分开的索引 10H 对应 0.别把表排错位。实验 3 的第三个内容是左移显示 0F每 0.5 秒把 20H25H 的内容整体左移一位25H 加 1 后与 0FH 相与。这里“调用显示子程序 330 次约 1 秒”是文档给的估算实际 330×3ms≈1 秒但如果你把延时改短了这个次数要跟着调否则移动速度会变快。我一般把 330 改成 160配合 0.5ms 延时刚好 0.5 秒左右视觉上更舒服。3.2 矩阵键盘扫描列驱动、行读入与 20ms 消抖实验 4 的键盘是 4×4 接在 8255 C 口PC0PC3 行输入、PC4PC7 列驱动。扫描逻辑是依次让某一列输出低、其余列高读行状态如果低 4 位不全为 1 说明该列有键按下。文档给了查键值子程序 KEY20入口 A 高 4 位是列驱动码、低 4 位是行状态出口 A 是键值 00H0FH。这个子程序用移位计数算行列号再查 KEYTAB 表思路清晰但有个坑JNB ACC.4,KEY22判断的是列驱动码里第一个 0 的位置如果列驱动码不是标准单 0 模式比如消抖时读回的值混进去列号会算错。扫描主流程里 20ms 消抖是必须的文档流程图写了“软件延时 20mS 再读行状态二次相同才确认”。20ms 用 12MHz 下约 20000 个机器周期可以写三层循环也可以复用实验 1 的延时结构把 R0 改成 33 左右。消抖之后还要“读行状态直到键松开”这一步文档特别提醒要滤掉高 4 位因为 C 口高 4 位是输出列驱动码读回来不是稳定的 1。正确做法是ANL A,#0FH再判断是否等于 0FH。主程序里键盘值和显示缓冲区的移位逻辑是有新键值时 20H←21H、21H←22H……25H←A相当于从右端挤入。这个移位顺序和实验 3 的左移显示正好相反组合起来就是“按键数字从右边进来、整体往左走”。调试时如果发现按一个键显示两个数多半是消抖没做或者键松开检测漏了如果显示的数字和按键对不上先查 KEYTAB 表顺序文档给的表是 0FH,0BH,07H,03H 开头对应第一行从右到左别自己重排。3.3 ADC0809 采样与十六进制转十进制显示实验 5 把前面几个实验串起来了电位器分压送 IN4写 8004H 启动转换查询 P1.0EOC 经反相器等待结束读 8004H 得 8 位结果再把 2 位十六进制转 3 位十进制送 LED 第四六位显示。转换算法文档在实验 2 里给了依次除以 100、10商和余数就是百位、十位、个位。实验 2 是纯软件仿真30H 放十六进制数31H33H 放非压缩 BCD实验 5 把这段算法嵌进采样流程输入从 30H 换成 ADC 结果。除法用 8051 的 DIV AB 指令最直接A 装被除数B 装除数 100执行后 A 是商、B 是余数余数再除 10A 是十位、B 是个位。三段结果分别存 33H、32H、31H注意高低位顺序然后 20H25H 里 20H22H 放灭或前导零处理、23H25H 放三位数字索引。这里有个显示细节ADC 结果 00HFFH 对应 0255百位可能是 0文档没要求消隐前导零直接显示“0xx”也能接受但看起来不如消隐舒服。我一般判断百位为 0 时送“灭”码索引 21H十位为 0 且百位也为 0 时也送灭这样小电压时只显示个位。EOC 查询要加超时虽然文档没写但实际调试时如果 ADC 没接好或者启动信号没发出去JB P1.0,$会死等。加个计数器循环几十次还等不到就跳出错处理至少不会卡死整个程序MOV DPTR,#8004H MOVX DPTR,A ; 写任意数启动转换 MOV R7,#0FFH WAIT: JNB P1.0,READ ; EOC 反相后低电平表示转换中按文档接法确认极性 DJNZ R7,WAIT SJMP ERR ; 超时 READ: MOVX A,DPTR ; 读结果极性这里要特别注意文档说 EOC 通过反相器接 P1.0那么转换结束时 P1.0 应该是低电平还是高电平取决于反相器接法。指导书写“查询 P1.0 的状态”但没给判断方向实际以实验箱为准用单步看一次就清楚了。我遇到过学生把JNB和JB写反程序要么立刻读要么永远等这是典型的“文档没写死、现场试出来”的坑。4. 避坑与排查六个实验里最容易翻车的五件事4.1 中文符号混入汇编导致编译报错现象编译输出窗口报错行号指向一条看起来完全正确的指令错误信息是“undefined symbol”或“syntax error”。原因指令里的逗号、分号、冒号用了中文全角字符或者数字 0 和字母 o 混淆。指导书在实验 1 的重要提示第一条就写了这个但每年还是有人中招。解决Keil 编辑器里把字体换成等宽字体中文符号明显更宽编译前用查找替换把全角逗号、分号批量换成半角养成注释用中文、代码区只用英文输入法的习惯。4.2 硬件仿真连不上或跑旧程序现象点 Start/Stop Debug Session 后提示连接失败或者连上了但程序行为跟刚改的代码对不上。原因串口被占用、K10 没拨到 B 端、没按 SS10 复位或者改完程序没退出会话重新编译。解决先关掉其他可能占串口的软件确认 K10 位置按一次 SS10 再连每次修改源文件后执行 Build然后 Stop→Start 重新进会话。指导书反复写“修改后必须退出连接、编译、再连接”不是啰嗦是硬件仿真器只认进入会话那一刻加载的 HEX。4.3 数码管显示重影或亮度不均现象数字边缘有暗影或者某一位明显比别的位暗。原因换位前没关显示上一位段码残留或者每位延时不一致某一位查表路径长了几个周期。解决在送新位码之前先往 A 口写 FFH 关所有位再送段码、送位码延时用固定子程序不要在不同位之间插条件判断。如果某一位特别暗检查该位的位选驱动三极管或限流电阻实验箱用久了接插件接触不良也会这样拔插一下排线往往就好了。4.4 键盘扫描误触发或键值错位现象没按键也偶尔出数或者按 1 显示 4、按 5 显示 8。原因消抖时间不够、键松开检测没滤高 4 位、KEYTAB 表顺序和实际接线行列反了。解决消抖延时加到 20ms 以上读行状态后ANL A,#0FH用单步在查表前看 A 的高 4 位列码和低 4 位行码是否符合预期不符合就查接线键值错位固定偏移时直接调 KEYTAB 表顺序比改算法快。4.5 ADC 读数跳变或始终为 0/FF现象采样值在小范围内乱跳或者一直读 00H、FFH。原因参考电压不稳、IN4 输入悬空、启动写地址错、EOC 极性判断反。解决先用万用表量电位器中间抽头电压是否随旋钮变化确认写的是 8004H 不是 8000H用单步看启动后 P1.0 是否按预期翻转翻转方向反了就把 JNB 改 JB读数跳变在 ±2 以内属正常8 位 ADC 低位噪声显示时右移一位或做四次平均都能压下去。5. 从跑通到写进报告用单步和存储器窗口做验证六个实验跑通只是及格线指导书对实验报告的要求其实透露了验证方法实验原理及环境、实验内容文字叙述、程序清单、实验步骤、实验总结里要写“调试过程、错误及产生的原因”。这意味着验收时老师看的是你能不能定位问题而不是灯亮没亮。我常用的验证套路是每个实验先在软件仿真里用单步跑一遍打开 View→Memory Window地址栏输d:20H看片内 RAM 缓冲区输x:4000H看片外 8255 端口实验 2 重点看 30H 输入和 31H33H 输出是否符合除权算法实验 3 看 20H25H 移位是否按预期滚动实验 4 按键时看 C 口读回值和 A 返回值是否对应 KEYTAB实验 5 看 8004H 读出值和后续 BCD 拆分。单步有个技巧Step Over 把LCALL DISP当一条指令过适合看主流程Step 进去看显示子程序内部适合查重影和位码。断点设在MOVX DPTR,A后面停下来看外设端口实际写进去的值比盯着 LED 猜快得多。硬件仿真时如果单步导致外设时序乱掉比如键盘扫描需要连续跑就改用“运行到光标处”加断点组合。最后说一个我自己的习惯每次改完程序不管改多小都先 Build 看 Output 窗口有没有 Warning再进仿真。汇编的 Warning 经常是“符号未定义但地址默认为 0”这种程序跑起来可能碰巧对换个芯片就翻车。从那以后我每次交报告前都把 Build 输出截一张图贴在调试过程里既证明编译干净也逼自己把 Warning 清零。希望这份拆解能帮你把六个实验从“照着抄”变成“知道为什么这么写”。本文还有配套的精品资源点击获取