
简介单片机实验.zip是面向51单片机初学者的实践资源包解决汇编语言与C语言上机时缺少可运行示例、不知从何入手的问题。内容围绕8051芯片展开涵盖LED点亮、按键控制继电器、数码管静态与动态显示、定时器、外部中断、串行通信等典型实验汇编源码可直接对应硬件操作C语言版本便于理解和修改两者互相对照能加深对单片机工作机理的把握。压缩包共28个文件包括18个C源文件、9个汇编源文件和1份实验说明Word文档代码量小且注释清晰整包仅28KB适合随时下载练习说明文档对硬件连接与设计思路也有梳理。目前已有149人学习。通过动手完成这些实验可以熟悉Keil环境下的程序编写、编译、下载与调试流程逐步掌握I/O口控制、中断服务、串口收发、时序处理等核心技能既是课程设计的实用素材也是入门嵌入式开发的高性价比资料。1. 拿到单片机实验.zip先别急着点开工程这一包东西到底能干什么“单片机实验.zip”这个压缩包在课程群和网盘里出现的频率相当高通常是期末前从某位同学手里拷来的几十个文件夹名字写着LED、按键、数码管、定时器、串口双击Keil工程却弹出七八条头文件报错烧录时又可能卡在连接超时。这类实验包大多来自某高校的课程资料整理少数是某开发者自学的汇总里面既有完整可跑的源码也有几个删得不干净的半成品工程。它真正的用法不是“一键运行”而是当作一组最小可复现的模板从点亮一颗LED开始逐个验证编号最小的实验再往里面加自己的逻辑。这篇笔记要帮你的就是把这条路径跑通并说清楚哪些报错值得修、哪些是包本身的问题。适合正在做课程作业、课程设计或者打算用51单片机自学的入门读者也适合被实验包折腾了一晚上、想找个系统排查思路的人。2. 解压后先看目录结构读懂这套实验包再决定先打开哪个工程拿到压缩包的第一件事不是双击工程而是先把整个包解压到一个没有中文路径的目录下然后花十分钟看清楚里面装了什么。常见做法是几十个文件夹每个文件夹对应一个独立实验也有可能是一个大工程目录实验内容靠宏定义切换。判断标准很简单——找工程文件和后缀名。2.1 文件夹命名和芯片型号先确认这套实验包是为哪颗芯片写的用文件管理器或者命令行看一眼根目录。典型的实验包结构大概是这样$ find 单片机实验 -maxdepth 2 \( -name *.uvproj -o -name *.c \) | head -20 单片机实验/01_LED闪烁/main.c 单片机实验/01_LED闪烁/LED.uvproj 单片机实验/02_按键控制/main.c 单片机实验/02_按键控制/KEY.uvproj 单片机实验/03_定时器/main.c 单片机实验/03_定时器/TIMER.uvproj 单片机实验/04_串口通信/main.c 单片机实验/04_串口通信/UART.uvproj这段命令的作用是列出所有Keil工程文件和C源文件。逻辑很简单先确认有没有.uvproj后缀的文件有就说明这套实验包是用Keil写的双击就能打开如果找不到任何工程文件只有一堆.c和.h那就要手工重建工程具体做法见 2.4 节。参数说明-maxdepth 2控制搜索深度避免把子文件夹里的临时文件全翻出来\( ... -o ... \)是find的“或”逻辑括号必须转义head -20限制输出条数防止文件太多刷屏。确认完目录接着确认芯片型号。随便打开一个头文件看引入内容#include reg52.hreg52.h是8051内核芯片的寄存器定义文件对应STC89C52、AT89S52这类芯片如果你看到的是stm32f10x.h那就是另一条ARM路线了。这一眼判断很重要——51系列和STM32系列的烧录方式、IO操作、中断配置完全不同后面的步骤全都要跟着芯片型号走。绝大多数“单片机实验.zip”里的代码都是51内核的下面也以STC89C52为样板展开。2.2 从main.c读起先看主函数再顺着外设文件找依赖很多实验包没有README文档有也是抄来的实验指导书参考价值不大。真正值得读的是main.c。打开一个编号最小的实验文件夹看三件事头文件包含#include reg52.h还是自定义头文件决定了寄存器名能不能直接用。主函数结构while(1)之前做了什么初始化while(1)里面做了什么业务循环。跨文件调用有没有调用其他.c文件里的函数如果有头文件路径有没有配好。典型的主函数长这样#include reg52.h void Delay_ms(unsigned int ms); // 延时函数声明 void Init_LED(void); // LED初始化 void main(void) { Init_LED(); // 先把LED引脚设为输出模式 while (1) { P1 0xFE; // 点亮P1.0对应的LED Delay_ms(500); // 延时500ms P1 0xFF; // 熄灭全部LED Delay_ms(500); } }这段代码的逻辑是让接在P1.0引脚上的LED以500ms为周期闪烁。P1 0xFE的二进制是1111 1110意思是P1.0输出低电平、其余引脚输出高电平。但注意LED到底是低电平点亮还是高电平点亮取决于开发板原理图这是新手最容易翻车的地方后面会专门讲。参数说明Delay_ms(500)的500是软件延时循环次数估算出的毫秒数实际延时会随晶振频率浮动不是精确的500msP1 0xFF是让所有引脚恢复高电平如果板子上LED是高电平点亮这里反而会全亮。2.3 把实验工程导入Keil编译前必须改的4个位置确认是Keil工程后用Keil打开.uvproj文件。编译之前按顺序检查这四处设置缺一个都可能让你卡在莫名奇妙的报错上Project → Options for Target → Device确认芯片型号和实验包一致。比如实验包是STC89C52你选了AT89S52IO操作兼容但内存布局有差异某些宏会出问题。Output选项卡里勾选 Create HEX File。不勾选的话编译成功也生成不了.hex文件烧录器根本没东西可烧。C/C选项卡里的 Include Paths把实验包中所有包含.h文件的目录都加进去否则编译报fatal error: xxx.h: No such file or directory。晶振频率设置在Target选项卡里。这个值影响延时和波特率的准确性先按实验包注释里的频率填后面第3章会细说。如果实验包是旧版Keil工程而你装的是新版Keil经常会出现工程版本不兼容的提示。我一般的处理是不强行兼容直接新建工程、把.c文件重新添加一遍顺便检查一次设置反而比在原工程上修修补补快。2.4 没有Keil工程文件怎么办手工重建工程的最小步骤另一种很常见的情况是压缩包里只有.c和.h文件没有.uvproj。这说明原作者用的是别的编辑环境或者干脆在Linux下用命令行编译。这时候不用慌手工重建一个Keil工程只需要四步第一步Project → New uVision Project选好芯片型号保存到实验文件夹下。第二步把全部.c文件Add to Project.h文件不要手动添加它们会被编译器自动搜索。第三步在Options for Target → C/C → Include Paths里把.h文件所在目录加进去。第四步编译根据报错逐个修。如果你不喜欢Keil也可以直接用SDCC开源编译器在命令行编译$ sdcc main.c $ packihx main.ihx main.hex第一行sdcc main.c把源码编译成Intel HEX格式的中间文件main.ihx第二行packihx把.ihx转成烧录器认的.hex。参数说明SDCC的语法和Keil的C51语法基本兼容但特殊功能寄存器的声明方式略有差异直接拿Keil工程编译报错很正常不要怀疑是代码问题先查头文件路径够不够。提示手工重建工程后如果编译报错内容涉及“变量重复定义”多半是上一步把.h文件也添加进工程了。把.h从工程里移除只保留.c问题就没了。3. 跑通第一个实验点亮板载LED从原理图到烧录的完整链路芯片型号确认了工程能编译了接下来就是实验包的第一次真机验证点亮板载LED。这一步看起来最简单实际是后面所有实验的基准——如果不亮后面的按键、中断、串口全都无从谈起。3.1 先看原理图找LED引脚实验包默认P1.0你的板子可能是P2.0把实验包里的代码当成唯一事实来源是第一个要避开的误区。实验包是在某块特定开发板上写的你的板子不一定一样。点亮LED之前先打开自己板子的原理图搜索“LED”关键字确认两件事LED接在哪个引脚、低电平点亮还是高电平点亮。常见开发板的LED接法有三种接法IO口赋值典型现象踩坑高危点低电平点亮IO串电阻P10xFE 亮P1.0赋值0亮1灭与代码习惯相反最易搞混高电平点亮IO串电阻P10x01 亮P1.0赋值1亮0灭实验包代码常按低电平点亮写经锁存器驱动需先配置锁存器引脚直接改P1无效最常见于增强型板子害人不浅第三种接法最坑LED不是直接挂在单片机IO口上而是经过一个锁存器或驱动芯片。这时候直接给P1赋值电压被锁存器隔离灯根本不亮。实验包里若有“P10xFE”这种代码烧进去没反应先别怀疑代码去原理图里找有没有锁存器控制脚比如“OE”或“LE”引脚需要单独置高。3.2 最小工程代码加一个关看门狗防止程序不停复位确认完引脚和电平极性就可以写一个最小工程做验证了。这个工程不需要实验包里的全部代码只留点灯这一个功能。注意STC系列芯片有个特性部分型号上电默认开启看门狗如果程序运行时间超过看门狗溢出周期芯片会被强制复位现象就是LED闪一下灭掉、再闪一下灭掉看起来像接触不良。#include reg52.h sfr WDT_CONTR 0xE1; // STC89C52看门狗控制寄存器 void Delay(unsigned int t) // 软件延时 { unsigned int i, j; for (i 0; i t; i) for (j 0; j 125; j); // 12MHz下内层循环约1ms } void main(void) { WDT_CONTR 0x00; // 关闭看门狗禁止自动复位 P1 0xFF; // 初始化全部引脚置高 while (1) { P1 0x00; // 全部LED点亮 Delay(500); // 延时约500ms P1 0xFF; // 全部熄灭 Delay(500); } }代码逻辑很直白while(1)里反复执行“点亮→延时→熄灭→延时”。关键在sfr WDT_CONTR 0xE1;这一行——它把STC89C52的看门狗控制寄存器映射到一个变量然后赋0关闭看门狗。参数说明0xE1是看门狗控制寄存器的地址不同STC型号地址可能不同使用前查一下芯片手册Delay(500)里的125是根据12MHz晶振估算的如果你的板子用的是11.0592MHz晶振实际延时约540ms闪烁频率会略偏这属于正常现象不影响功能验证。3.3 烧录命令与硬件连接串口参数和冷启动顺序程序编译通过并生成.hex文件后进入烧录环节。51实验包绝大多数用串口下载接线和参数设置是重灾区。硬件连接先确认三根线USB转串口模块的TXD接单片机RXDRXD接TXDGND接GND。很多人烧录失败是因为只接了两根数据线没共地导致电平参考不一致通信一直超时。注意TXD和RXD必须交叉连接直连的话数据发出去没人收。打开STC-ISP烧录软件按顺序设置芯片型号选STC89C52或对应型号选错会提示“芯片型号错误”或直接超时。串口号选设备管理器里USB转串口对应的COM号。波特率设置最高波特率和最低波特率都填9600。新手喜欢把波特率拉到115200想快一点实际上很多劣质USB转串口模块在高压干扰下115200稳不住9600最稳。点击“下载/编程”按钮这时候软件进入等待状态然后给开发板重新上电冷启动。先点下载、再上电这个顺序是STC芯片的下载流程顺序反了软件就检测不到芯片。烧录到一半提示“连接超时”最常见的两个原因RXD/TXD接反了或者开发板上的下载控制电路需要额外短接某个跳线。去看你板子的串口下载说明比反复换线省时间。3.4 现象不对时先查这3个数晶振频率、延时系数、IO电平LED点亮实验烧录成功但现象和实验包描述不一致优先查下表这3个数字现象优先查什么为什么灯一亮就灭、循环复位看门狗有没有关、供电电压够不够看门狗溢出或电压跌落导致复位闪烁速度明显偏快/偏慢晶振频率和Delay系数匹配11.0592MHz的板子照抄12MHz延时参数偏差最多能到8%完全不亮但烧录成功LED极性、引脚编号、锁存器代码逻辑对硬件连接和你以为的不一样“灯一亮就灭”这种现象特别像电路接触不良很多人会去焊板子查线折腾半小时发现是看门狗没关。我一般的排查顺序是先软后硬——先把看门狗关了、延时加长到1秒人眼能看清再查硬件接线。延时加长这个技巧在排查阶段很有用500ms的闪烁在人眼看来有点急促改成1秒后能清楚分辨亮灭周期是否均匀不均匀说明定时有问题均匀但速度不对说明晶振参数不对。4. 从LED到按键中断实验包里的核心代码模式拆解LED实验跑通了恭喜你已经确认了工具链和硬件都正常。接下来值得花时间拆解的是实验包里另一类高频代码按键、定时器中断、串口。这三块是51单片机实验的核心模板也是后面课程设计和毕设里最常被复用的部分。4.1 按键消抖为什么写10ms~20ms去抖逻辑的代码实现机械按键按下和松开的瞬间簧片会经历数次几个毫秒级别的弹跳如果不处理一次物理按下会被单片机识别成多次触发。实验包里的消抖代码写成这样是有道理的#include reg52.h sbit KEY P3^2; // 按键接在P3.2外部中断0引脚 void Delay(unsigned int t); void main(void) { unsigned char cnt 0; while (1) { if (KEY 0) // 检测到按键被按下低电平 { Delay(15); // 延时15ms跳过弹跳区间 if (KEY 0) // 再次确认仍为低电平确实是按下 { cnt; while (KEY 0); // 等待松手防止长按重复触发 } } } }逻辑分三段第一次检测到低电平不立即采信延时15ms避开机械弹跳延时后再读一次引脚如果还是低电平说明是真实按压而非抖动最后while (KEY 0);等待松手避免长按时计数器反复累加。参数说明消抖延时取10~20ms是根据机械按键簧片弹跳时间的实测范围来的小于5ms消不干净大于50ms会明显觉得按键反应迟钝但这个写法有个缺陷——while (KEY 0);是阻塞式的松手前主循环卡死在这里LED闪烁、串口发送全部暂停。实验包这么写是为了逻辑简单实际项目里应该改成按键状态机后面第6章会演示。4.2 定时器中断初值65536和12MHz是怎么算出这个数的定时器是51单片机实验包里另一个绕不开的模板。很多初学者对着TH0 0x3C; TL0 0xB0;这两个数一脸懵其实计算逻辑非常固定。先讲原理定时器0是16位计数器从初值开始向上计数计满溢出触发中断。16位最大值是65536。在12MHz晶振、默认12T分频模式下机器周期是1µs所以计数器每加1就是1µs。要定时50ms就需要计数50000次初值就是 65536 - 50000 15536换算成十六进制就是0x3CB0所以高8位TH00x3C低8位TL00xB0。#include reg52.h unsigned int g_tick 0; void Timer0_Init(void) { TMOD 0x01; // 定时器0方式116位定时 TH0 0x3C; // 初值高8位 TL0 0xB0; // 初值低8位 ET0 1; // 使能定时器0中断 EA 1; // 使能总中断 TR0 1; // 启动定时器 } void Timer0_ISR(void) interrupt 1 // 定时器0中断服务函数 { TH0 0x3C; // 重装初值 TL0 0xB0; g_tick; // 每次中断累加50ms一次 }代码逻辑初始化函数配置工作方式、写入初值、开中断、启动定时器中断服务函数里重装初值并累加g_tick。参数说明TMOD 0x01的高四位控制定时器1低四位控制定时器00x01只把定时器0设为方式1不影响定时器1interrupt 1是Keil C51的关键字数字1表示定时器0的中断号不能写错写错编译不出错但中断不触发每次中断后必须重装初值否则计数器从0开始计定时时间变成实际设计值的65536倍主循环里的时间全部错乱。如果你板子上的晶振是11.0592MHz机器周期约1.085µs定时50ms需要计数约46082次初值是 65536 - 46082 19454折算成十六进制为0x4BFE。所以换晶振后这两个数必须重算这是“代码复制过去但表现异常”的高发原因。4.3 串口打印调试UART初始化和printf重定向串口是实验包里唯一能“看到”程序运行状态的方式。LED能看出大概但中间变量的值只有通过串口输出才能确认。初始化代码模板#include reg52.h void Uart_Init(void) { SCON 0x50; // 串口方式1允许接收 TMOD 0x20; // 定时器1方式28位自动重装 TH1 0xFD; // 波特率9600 TL1 0xFD; TR1 1; // 启动定时器1作为波特率发生器 ES 1; // 使能串口中断 EA 1; // 使能总中断 }逻辑说明串口工作在方式1下波特率由定时器1的溢出率决定。TH1 0xFD是波特率定时器的初值这个值对应的是11.0592MHz晶振下的9600波特率。参数说明如果你的板子是12MHz晶振照抄0xFD得到的实际波特率约9600但误差接近8%短报文还能忍长报文或通信协议严格的场景会出错建议把晶振换为11.0592MHz这是51单片机串口通信的经典配置。要用printf输出调试信息还要加一个字符发送函数并重定向printfchar putchar(char c) // Keil C51中printf底层调用putchar { SBUF c; // 要发送的字符写入发送缓冲 while (!TI); // 等待发送完成标志置位 TI 0; // 手动清标志 return c; }这段代码的作用是让printf输出的每个字符都通过串口发送出去参数说明SBUF是串口发送缓冲寄存器写入即开始发送while (!TI)阻塞等待硬件完成发送TI是发送完成中断标志必须软件清零否则下一次while (!TI)永远不满足程序卡死。加完这个函数在main里写上printf(tick%d\n, g_tick);复位实验板电脑串口助手就能看到定时器中断的累加值。注意串口助手显示乱码时先查波特率是否匹配再查晶振误差。如果确定波特率没问题检查芯片供电电压3.3V的芯片按5V电平跑串口也会有乱码风险。5. 单片机实验.zip使用中的5个典型坑现象、原因、解决实验包用起来会踩的坑翻来覆去就那几类。下面是踩的人最多、最隐蔽、也最耗时间的5个按“现象→原因→解决”列清楚。5.1 烧录失败连接超时或一直检测不到芯片现象STC-ISP点击“下载/编程”后进度条停住提示“单片机型号选择错误”或“连接超时”反复拔插USB也没用。原因九成是硬件接线问题剩下的一成是驱动或串口号选择错误。最常见的是USB转串口模块的TXD和RXD没有交叉连接单片机收不到数据其次是只接了TXD和RXD忘了共地还有一种情况是开发板上的下载跳线帽没短接芯片的下载引脚被隔离了。解决先确认设备管理器里能看到正确的COM口号看不到就先装USB转串口驱动然后查接线TXD接RXD、RXD接TXD、GND接GND一条条对最后检查下载跳线帽按你板子的说明书把下载模式对应的跳线短接。注意冷启动顺序——必须先在电脑端点击“下载/编程”再给开发板上电。5.2 编译报错找不到头文件或者大量未知标识符现象打开实验包工程直接编译报fatal error: reg52.h: No such file or directory或者一堆P1 undefined、TMOD undefined。原因第一种是头文件搜索路径不对Keil找不到芯片的寄存器定义文件这通常发生在把工程文件移动了位置之后。第二种是芯片型号没有选择或者选错了系列比如选了ARM芯片却编译51代码寄存器名当然不存在。解决对于“找不到头文件”在Options for Target → C/C → Include Paths里把实验包中所有含.h文件的目录都加进去对于“未知标识符”检查Options for Target → Device里的芯片型号要选STC89C52、AT89S52这类8051内核然后重新编译。如果两个都试了还是报错直接新建工程手动添加.c文件比在乱掉的工程里找原因快得多。5.3 程序能烧录但灯不亮LED极性和锁存器两个隐蔽坑现象烧录显示成功板上LED却毫无反应或者接了别的引脚灯亮了但位置不对。原因代码是按实验包的硬件写的你的板子电路不一样。很多入门开发板的LED是低电平点亮但有些板子是高电平点亮还有的板子LED经过锁存器控制直接对P1口赋值无效。解决去翻自己板子的原理图搜“LED”字样看清两个信息LED接在哪个IO口、点亮需要高电平还是低电平。然后把实验包代码里的P1 0xFE改成你自己板子的口和电平。如果板子带锁存器查原理图找到锁存器控制引脚先把它置为高电平或低电平看锁存器类型再操作LED引脚。这一步做完点灯实验才算真正在你的板子上跑通了。5.4 中断不触发定时器和外部中断共用一个总开关现象定时器中断或按键外部中断的代码烧进去了但中断服务函数就是不执行主循环正常跑LED该闪还是闪。原因忘了开总中断。51单片机的中断使能是两级结构EA 1是总开关ET0 1、EX0 1是分开关。很多人只开了分开关没开总开关中断标志产生了但CPU不进中断服务函数而且程序不会报错——这是中断类问题最迷惑人的地方。解决检查初始化代码里有没有EA 1;。以定时器0为例正确顺序是TMOD 0x01;配工作方式 →TH0/TL0写初值 →ET0 1;开定时器中断 →EA 1;开总中断 →TR0 1;启动定时器。顺序颠倒一般也能工作但建议养成先配寄存器、再开中断、最后启动的先后的习惯。外部中断按键还要多查一个IT0 1;——这个寄存器决定是下降沿触发还是低电平触发实验包一般不写但你的按键电路如果是按键接VCC、另一端接IO口边沿触发方式会失效。5.5 按实验包参数换了芯片型号后跑不通晶振频率和分频模式变了现象实验包用的STC89C52你手里是STC15系列或别的增强型芯片代码原样烧进去LED闪烁速度明显不对串口乱码更严重。原因不同芯片的时钟系统差异很大。STC89C52默认12T模式一条机器周期12个时钟STC15系列默认1T模式机器周期就是1个时钟同样的延时循环实际时间缩短到原来的十二分之一——闪烁快得看不清。另外烧录软件里可以用IRC配置内部时钟频率有人把芯片内部时钟调成了12MHz或11.0592MHz但代码里延时函数按另一个频率计算两个频率不匹配。解决第一烧录前在STC-ISP里确认当前芯片的工作频率设置尽量选11.0592MHz或12MHz并记录实际值。第二把代码里的延时循环和内层循环次数按实际频率换算。第三如果换的是STC15系列除了时钟还有寄存器差异定时器初值和中断号可能不同不要拿来直接烧录先在芯片手册里确认寄存器兼容性。实验包背后绑定的不止是代码还有一套时钟参数换芯片等于换了一整套参数集。6. 把实验包改成自己的东西状态机流水灯与一个调试习惯实验包最后能给你留下的不是那几十份能跑的代码而是一套“怎么改”的底子。这里给一个从实验包到自己的项目的改法把实验包里的延时流水灯改成定时器状态机流水灯——这也是实验包轮询代码最常见的升级点。配套一个能让后续实验少走弯路的调试习惯。6.1 状态机流水灯用定时器标志位替代嵌套延时实验包的流水灯一般长这样while(1)里左移一位、延时、再左移一位。这种写法简单直观但致命问题是延时期间CPU被空转占死按键扫描、数码管刷新、串口接收全部停摆。改成定时器状态机后主循环只在定时器置标志位时切换状态#include reg52.h unsigned int g_tick 0; unsigned char g_flag 0; void Timer0_Init(void) { TMOD 0x01; TH0 0x3C; TL0 0xB0; ET0 1; EA 1; TR0 1; } void Timer0_ISR(void) interrupt 1 { TH0 0x3C; TL0 0xB0; g_tick; if (g_tick 20) // 20次中断 1秒 { g_tick 0; g_flag 1; // 置标志位通知主循环 } } void main(void) { unsigned char led 0xFE; // 初值点亮P1.0对应LED Timer0_Init(); while (1) { if (g_flag) // 主循环只查标志位 { g_flag 0; led (led 1) | 0x01; // 左移一位点亮下一个灯 if (led 0xFF) led 0xFE; // 到末尾就重新开始 P1 led; } // 这里可以放心插入按键扫描、串口发送等任务 } }这段代码的核心是分离“时间产生”和“时间消费”定时器中断负责产生1秒的标志位主循环检测到标志位才执行流水灯切换两者不再互相阻塞。参数说明g_tick 20里的20对应20次50ms中断累计1秒想要加快流水速度就改小这个数led (led 1) | 0x01是让位逐次左移低电平点亮模式下点亮位置向右移动到全灭时回到初值。调这个实验时我还有一个从教训里养成的习惯每次只改一个参数烧录后先让程序跑10秒再判断对错。之前折腾流水灯速度新手容易同时改延时系数又改初值重装值结果LED乱闪分不清是逻辑错了还是参数错了。改一行、烧一次、观察一次看起来慢实际排查速度反而最快。另一个习惯是把串口printf当成“调试黑匣子”的钥匙——只要串口能在关键时刻打印变量再多玄学问题都能在串口助手里现出原形。一套“单片机实验.zip”值得你花时间的理由不是里面的代码有多精巧而是它让你在一个晚上之内从“能编译”跨到“能改逻辑”。跑通最小实验、拆透一个中断模板、把轮询改成标志位这三步做完课程设计和毕设里的单机控制逻辑基本就有底了。我从实验包里学到最值钱的东西恰恰是敢于把不理解的代码删掉重写而不是让它一直躺在工程里当黑匣子。希望帮到你。本文还有配套的精品资源点击获取