1. 期末速成前必须搞清楚的几件事
1.1 这门课到底在考什么
《单片机原理与应用》这门课,名字里带“原理”两个字,很多人就以为要背一大堆寄存器地址和时序图。其实从期末考试的出题规律来看,真正拉分的从来不是死记硬背,而是你能不能看懂一段C语言代码在51单片机上跑起来之后,硬件会发生什么反应。我翻过不下二十套各高校的期末卷子,题型基本跑不出这几类:选择题考基本概念(比如晶振周期和机器周期的关系)、填空题考寄存器配置位、简答题考中断流程和定时器工作方式、编程题考LED控制或数码管动态扫描、综合分析题考交通灯或者按键消抖这类小系统。
所以复习的第一步不是翻开课本从第一章看起,而是先搞清楚你们学校往年的卷子长什么样。如果找不到真题,就去问学长学姐,或者看老师平时布置的作业题——期末出题大概率是从作业题里改数字、改条件。我见过太多人把课本从头到尾背了三遍,结果考试的时候发现编程题让写一个流水灯,他连#include <reg52.h>都写不利索。
1.2 4.5小时怎么分配才合理
标题里说“4.5小时掌握全部内容”,这个时间确实紧,但也不是不可能。前提是你得把时间花在刀刃上。我的建议是这样切:
- 前1小时:过一遍核心概念,重点看中断系统、定时器/计数器、串口通信这三块。这三块是期末考试的“铁三角”,几乎每张卷子都会涉及。
- 中间2小时:动手写代码。不要只看不写,打开Keil,把LED点亮、流水灯、数码管静态显示、数码管动态扫描、按键检测、定时器中断这几个基础程序亲手敲一遍。敲的过程中你会发现自己以为懂的地方其实写不出来。
- 最后1.5小时:做综合题。找两三道交通灯或者电子秤之类的综合题,自己画流程图、写代码框架,然后对照答案看差距在哪里。
这个分配的逻辑是:概念题靠短期记忆能拿分,编程题必须手熟。你光看代码觉得“哦,原来是这样”,真到考场上让你写,你会发现连延时函数都写不对。
1.3 51单片机的最小系统你得先认识
很多人复习到一半卡住了,是因为连单片机怎么跑起来都没搞明白。51单片机要工作,最少需要这几样东西:电源(5V)、晶振(通常11.0592MHz或12MHz)、复位电路、以及烧录接口。晶振决定了单片机的“心跳速度”,12MHz的晶振意味着一个机器周期是1微秒(12个时钟周期),这个换算关系考试必考。
复位电路一般是上电复位加按键复位,考试里常问“复位后各寄存器的初始值是什么”。这个你得记住:复位后P0-P3口全是高电平,SP指向07H,PC指向0000H。这些数字看起来枯燥,但选择题就爱考这种。
烧录这块,现在常用的有两种方式:一种是老式的STC-ISP串口下载,需要USB转TTL模块;另一种是用STC官方提供的下载软件直接通过串口烧录。考试一般不考烧录操作,但实验报告里可能会让你写步骤,所以至少要知道流程:编译生成HEX文件→打开下载软件→选择单片机型号和串口号→下载/编程。
注意:不同型号的51单片机(比如STC89C52和AT89C51)在烧录方式上可能有差异,复习时以你们实验室用的型号为准。
2. C语言在51单片机上的核心考点拆解
2.1 位操作:单片机编程的半条命
51单片机编程和普通C语言最大的区别,就是位操作无处不在。你写PC上的C程序,很少会去操作一个字节里的某一位,但在51单片机里,点亮一个LED可能就要写sbit LED = P1^0;,然后LED = 0;。这里的sbit是Keil C51扩展的关键字,用来定义位变量。
为什么51单片机这么依赖位操作?因为它的硬件设计就是按位可控的。P1口有8个引脚,每个引脚对应一个LED或者一个按键,你要单独控制某一个引脚,就得用位寻址。考试里常见的位操作考点包括:
- 用
sbit定义位变量 - 用
^运算符操作寄存器的某一位,比如P1 ^= 0x01;是把P1的第0位取反 - 用
&和|来置位和清零,比如P1 |= 0x01;是置位,P1 &= ~0x01;是清零
我见过很多同学在考试时写P1 = 0x01;想点亮第一个LED,结果其他LED的状态全被覆盖了。正确的做法是P1 &= ~0x01;或者用位变量单独操作。这个坑我在第一次做流水灯的时候踩过,当时调了半天以为硬件坏了,后来才发现是直接赋值把其他位都清了。
2.2 中断系统:从“轮询”到“中断”的思维转变
中断是51单片机里最核心的概念之一,也是期末考试必考的内容。很多初学者不理解中断的意义,觉得用轮询(while循环里不断检测)也能实现同样的功能。但轮询的问题是:CPU会被死死占住,没法同时处理其他事情。中断的好处是,主程序该干嘛干嘛,等事件发生了再跳过去处理,处理完再回来。
51单片机有5个中断源:外部中断0、定时器0中断、外部中断1、定时器1中断、串口中断。每个中断都有对应的中断向量地址,比如外部中断0的中断向量是0003H,定时器0是000BH。考试里常考的是中断的配置流程:
- 设置中断允许位(EA=1,以及对应的EX0/ET0等)
- 设置中断触发方式(对于外部中断,IT0=1是下降沿触发,IT0=0是低电平触发)
- 编写中断服务函数,用
interrupt关键字指定中断号
中断服务函数的写法有个容易错的地方:函数名后面要跟interrupt 0这样的中断号,而且函数不能有返回值,也不能有参数。我见过有人写成void int0_isr() interrupt 0,这是对的;但有人写成void int0_isr(void) interrupt 0,多写了个void,编译也能过,但风格上不推荐。
还有一个高频考点是中断嵌套。51单片机默认不支持中断嵌套,也就是说,如果一个中断正在执行,另一个中断来了,CPU不会理它,等当前中断处理完再说。如果要支持嵌套,需要在中断服务函数里手动开启EA。这个知识点在简答题里出现的频率很高。
2.3 定时器/计数器:从“延时函数”到“精准定时”
延时函数是51单片机编程里最常用的东西,但也是最不精准的东西。for(i=0;i<1000;i++);这种延时,实际延时时间受晶振频率、编译器优化、甚至温度影响。所以真正靠谱的定时,要用定时器。
51单片机有两个定时器/计数器:T0和T1。它们既可以做定时器(对内部机器周期计数),也可以做计数器(对外部脉冲计数)。考试里常考的是定时器的工作方式:
- 方式0:13位定时器,用得少
- 方式1:16位定时器,最常用
- 方式2:8位自动重装,适合做波特率发生器
- 方式3:只适用于T0,拆成两个8位定时器
定时器的初值计算是必考内容。公式是:初值 = 65536 - (定时时间 / 机器周期)。假设晶振是12MHz,机器周期是1微秒,要定时50毫秒,那么初值就是65536 - 50000 = 15536,转换成十六进制是0x3CB0,所以TH0=0x3C,TL0=0xB0。
这个计算过程考试里一定要写出来,不能只写结果。我见过有人直接写TH0 = 0x3C;,老师给了零分,因为没展示计算过程。另外要注意,定时器方式1需要手动重装初值,也就是在中断服务函数里重新给TH0和TL0赋值。方式2是自动重装的,不需要手动赋值,这也是方式2常用于波特率发生器的原因。
2.4 串口通信:从“看不懂”到“能写出来”
串口通信是很多人的噩梦,因为涉及到波特率、SCON寄存器、PCON寄存器、以及一堆看起来像乱码的配置。但其实串口通信的配置是有固定套路的:
- 设置串口工作方式(SCON的SM0和SM1位),通常用方式1(8位UART,波特率可变)
- 设置波特率(通过定时器1的方式2来产生)
- 开启串口中断(如果需要接收)或者直接查询发送
- 写发送函数和接收函数
波特率的计算公式是:波特率 = (2^SMOD / 32) × (定时器1溢出率)。定时器1的溢出率又和初值有关。这个公式看起来复杂,但实际配置的时候,通常直接用STC-ISP软件里的波特率计算器,选好晶振和波特率,它会自动告诉你TH1和TL1填多少。
考试里串口通信的考点主要是:波特率计算、SCON寄存器的配置、发送和接收的代码框架。我建议把方式1的发送和接收代码背下来,考试的时候直接默写。发送一个字节的代码大概是:
void UART_SendByte(unsigned char dat) { SBUF = dat; while (!TI); TI = 0; }接收的话,如果是中断方式,就在中断服务函数里读SBUF,然后清RI标志。
3. 从点亮LED到交通灯:实操项目全流程
3.1 点亮一个LED:最基础但最容易翻车
点亮一个LED看起来简单,但里面有几个坑。第一个坑是驱动方式。51单片机的P0口是开漏输出,不能直接输出高电平驱动LED,需要外接上拉电阻。P1、P2、P3口内部有上拉电阻,可以直接驱动LED,但驱动能力有限,通常采用灌电流方式,也就是LED的正极接VCC,负极接单片机引脚,引脚输出低电平时LED亮。
为什么不能采用输出高电平的驱动方式?因为51单片机的引脚输出高电平时,驱动能力很弱(通常只有几十微安),不足以点亮LED。而输出低电平时,引脚可以吸收几毫安的电流,足够点亮LED。这个知识点在选择题里经常考。
第二个坑是限流电阻。LED必须串联限流电阻,否则可能烧坏LED或者单片机引脚。电阻值一般是220欧姆到1K欧姆之间。我一般用470欧姆,亮度适中,电流大概在5毫安左右,比较安全。
第三个坑是晶振频率和延时。如果你用12MHz晶振,一个机器周期是1微秒,那么for(i=0;i<1000;i++);大概延时1毫秒左右(实际受编译器影响)。但如果你换成11.0592MHz晶振,延时时间会略有不同。考试里如果让你写延时函数,通常会给晶振频率,你要根据频率来估算循环次数。
3.2 流水灯:位操作的实战演练
流水灯是51单片机编程的“Hello World”,但也是位操作的最佳练习。最简单的流水灯代码是:
#include <reg52.h> #include <intrins.h> void delay(unsigned int ms) { unsigned int i, j; for (i = 0; i < ms; i++) for (j = 0; j < 120; j++); } void main() { unsigned char led = 0xFE; // 1111 1110 while (1) { P1 = led; delay(500); led = _crol_(led, 1); // 循环左移 } }这里用了_crol_函数,它在intrins.h头文件里。如果不让用库函数,也可以手动实现循环左移:
led = (led << 1) | (led >> 7);这个表达式的意思是:左移一位,然后把最高位移到最低位。考试里如果让你写循环移位,这个写法是标准答案。
流水灯还有一个变种是两边向中间跑或者中间向两边跑,本质上还是位操作,只是移位的方向和初始值不同。我建议把几种常见的流水灯模式都写一遍,考试的时候不管出哪种,你都能快速反应。
3.3 数码管动态扫描:定时器中断的经典应用
数码管动态扫描是51单片机里最能体现“定时器中断价值”的项目。静态显示一个数码管很简单,但多个数码管如果都用静态显示,需要太多IO口。动态扫描的思路是:利用人眼的视觉暂留效应,快速轮流点亮各个数码管,看起来就像同时亮一样。
动态扫描的核心是定时器中断。通常用定时器0,每2毫秒中断一次,在中断服务函数里切换当前显示的数码管位。主程序只需要把要显示的数字放到一个数组里,中断服务函数负责刷新。
代码框架大概是:
unsigned char code seg[] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F}; unsigned char disp[4] = {1, 2, 3, 4}; unsigned char pos = 0; void Timer0_ISR() interrupt 1 { TH0 = (65536 - 2000) / 256; TL0 = (65536 - 2000) % 256; P2 = 0xFF; // 消影 P0 = seg[disp[pos]]; P2 = ~(1 << pos); // 位选 pos = (pos + 1) % 4; }这里有几个关键点:消影是必须的,否则数码管会显示乱码;位选和段选的顺序要注意,一般是先送段选数据,再开位选;中断频率不能太低,否则会闪烁,也不能太高,否则亮度不够。2毫秒是一个比较合适的值。
我当初调动态扫描的时候,数码管一直闪烁,后来发现是中断频率设成了20毫秒,太慢了。改成2毫秒之后就很稳定。这个参数考试里如果让你算,你要知道刷新频率要大于50Hz,也就是说每个数码管至少每20毫秒刷新一次,4个数码管的话,中断周期要小于5毫秒。
3.4 按键检测与消抖:软件消抖的两种写法
按键检测看起来简单,但抖动是个大问题。机械按键在按下和松开的瞬间,电平会抖动几次,如果不处理,单片机会误判为多次按下。消抖有两种方式:硬件消抖(加电容)和软件消抖(延时确认)。
软件消抖的经典写法是:
if (KEY == 0) { delay(10); // 延时10毫秒 if (KEY == 0) { // 确认按下 while (KEY == 0); // 等待松开 return 1; } } return 0;这种写法的问题是阻塞,在等待按键松开的时候,CPU什么都干不了。如果系统里还有数码管要刷新,就会闪烁。所以更高级的写法是用状态机,把按键检测放到定时器中断里,每次中断检测一次,连续几次都是按下状态才确认。
状态机消抖的代码稍微复杂一点,但考试里如果考“如何在不阻塞CPU的情况下实现按键消抖”,你就得写状态机。基本思路是:定义一个状态变量,每次中断根据当前状态和按键电平决定下一个状态,只有连续多次检测到按下才触发按键事件。
3.5 交通灯综合项目:把零散知识串起来
交通灯是期末综合题的最爱,因为它能把LED控制、定时器中断、状态机、按键检测全部串起来。一个典型的交通灯题目会要求:东西方向和南北方向轮流放行,每个方向有红黄绿三盏灯,红灯30秒,绿灯25秒,黄灯5秒,并且能用按键紧急切换。
做这种题的第一步是画状态转移图。交通灯本质上是一个状态机,有四个状态:东西绿南北红、东西黄南北红、东西红南北绿、东西红南北黄。每个状态持续的时间不同,用定时器中断来计时。
第二步是定义数据结构。可以用一个数组来存储每个状态的灯亮情况和持续时间:
unsigned char code state_light[4] = {0x1E, 0x1D, 0x33, 0x2B}; unsigned char code state_time[4] = {25, 5, 25, 5};第三步是写中断服务函数。定时器每50毫秒中断一次,在中断里递减当前状态的剩余时间,减到0就切换到下一个状态。
第四步是处理按键。按键按下时,直接切换到紧急状态(比如全部红灯),或者切换到下一个状态。
这个项目我做过不下五遍,每次都有新的收获。第一次做的时候没考虑按键消抖,结果一按就跳好几个状态;第二次做的时候没考虑数码管刷新,结果倒计时显示闪烁;第三次做的时候把状态切换逻辑写得太复杂,自己都看不懂了。后来总结出一个经验:状态机的状态越少越好,每个状态的逻辑越简单越好。
4. 常见问题与排查技巧实录
4.1 编译通过了但硬件没反应
这是最让人抓狂的情况。代码编译没报错,烧录也成功了,但LED就是不亮。排查思路是这样的:
| 排查步骤 | 检查内容 | 常见问题 |
|---|---|---|
| 1 | 电源是否接通 | 单片机VCC和GND是否接对 |
| 2 | 晶振是否起振 | 用示波器看晶振引脚是否有波形 |
| 3 | 复位电路是否正常 | 复位引脚电压是否正常 |
| 4 | 烧录是否成功 | 下载软件是否提示成功 |
| 5 | 引脚连接是否正确 | LED正负极是否接反 |
| 6 | 程序逻辑是否正确 | 是否进入了死循环 |
我遇到最多的问题是LED正负极接反和晶振没起振。晶振没起振的原因通常是晶振引脚接错了,或者晶振坏了。可以用万用表测晶振两端的电压,正常应该是电源电压的一半左右。
4.2 中断进不去
中断进不去的原因通常有三个:中断允许位没开、中断触发方式不对、中断向量写错了。排查的时候先检查EA和对应的EX/ET位是否置1,然后检查IT0/IT1是否设置正确,最后检查中断服务函数的中断号是否对应。
还有一个容易忽略的点是中断标志位没清。比如定时器中断,进入中断服务函数后,硬件会自动清TF0标志,但如果是外部中断,需要手动清IE0标志。如果没清,中断会一直触发。
4.3 数码管显示乱码
数码管乱码的原因通常是段选码表写错了或者位选和段选搞反了。共阳数码管和共阴数码管的段选码是相反的,用之前一定要确认你的数码管是共阳还是共阴。另外,动态扫描的时候如果没消影,也会出现乱码。
我建议在代码里加一个测试模式,让所有数码管显示同一个数字,这样可以快速判断是硬件问题还是软件问题。
4.4 串口通信收不到数据
串口通信的问题排查起来比较麻烦,因为涉及到硬件和软件两方面。软件方面,检查波特率是否匹配、SCON配置是否正确、TI和RI标志是否正确处理。硬件方面,检查TX和RX是否交叉连接(单片机的TX接电脑的RX,RX接电脑的TX)、电平是否匹配(51单片机是TTL电平,电脑串口是RS232电平,需要转换芯片)。
我刚开始学串口的时候,一直收不到数据,后来发现是TX和RX接反了。这个坑很低级,但确实很常见。
4.5 定时器定时不准
定时器定时不准的原因通常是初值计算错误或者晶振频率不对。计算初值的时候要注意,方式1是16位定时器,最大计数值是65536,不是65535。另外,如果晶振是11.0592MHz,机器周期不是1微秒,而是12/11.0592≈1.085微秒。这个差异在短时间定时里不明显,但长时间累积就会出问题。
还有一个原因是中断服务函数执行时间太长。如果中断服务函数里做了太多事情,会导致下一次中断来的时候还没处理完,定时就不准了。所以中断服务函数要尽量短,只做最核心的事情。
提示:如果定时要求很精确,可以考虑用方式2(8位自动重装),避免手动重装初值带来的误差。
5. 复习资料和工具的选择
5.1 教材和笔记怎么用
教材的作用是查漏补缺,不是从头读到尾。我建议先把目录看一遍,知道自己哪些章节是薄弱的,然后针对性地看。江科大的51单片机笔记在网上流传很广,它的优点是条理清晰、代码规范,适合快速过一遍知识点。但笔记毕竟是别人整理的,有些细节可能和你们老师讲的不一样,所以还是要以老师的PPT和作业为准。
5.2 Keil和烧录软件的基本操作
Keil是51单片机开发的标准工具,复习的时候至少要熟练这几个操作:新建工程、添加源文件、设置晶振频率、编译生成HEX文件。烧录软件通常用STC-ISP,操作很简单:选单片机型号、选串口号、加载HEX文件、点击下载。
考试一般不考软件操作,但实验报告里可能会让你写步骤,所以至少要知道流程。另外,Keil的软件仿真功能很有用,可以在没有硬件的情况下调试代码。比如你可以用仿真看定时器的计数过程、看中断的触发情况,这对理解原理很有帮助。
5.3 仿真软件Proteus要不要学
Proteus可以仿真51单片机的外围电路,比如LED、数码管、按键、串口等。如果你手头没有硬件,用Proteus做仿真是个不错的选择。但Proteus的仿真速度和真实硬件有差异,有些在仿真里能跑的程序,在硬件上可能跑不起来(比如时序要求严格的串口通信)。所以我的建议是:Proteus可以用来验证逻辑,但最终还是要上硬件调试。
考试里不会考Proteus操作,但如果你在实验报告里用了Proteus仿真,老师可能会加分。学有余力的话,花半个小时了解一下基本操作就够了。
5.4 代码模板和常用函数整理
复习到最后,我建议整理一份自己的代码模板库,把常用的函数都放进去,比如:
- 延时函数(不同晶振频率的版本)
- 数码管段选码表(共阳和共阴)
- 定时器初始化函数(不同定时时间的版本)
- 串口初始化函数(不同波特率的版本)
- 按键检测函数(阻塞版和状态机版)
这样考试的时候,如果让你写代码,你可以直接套模板,只需要改几个参数就行。我当年考试的时候,就在草稿纸上先默写了几个常用函数,然后编程题直接往上套,省了很多时间。
6. 考场上的实战技巧
6.1 选择题和填空题的快速作答
选择题和填空题考的是记忆的准确性,不是理解深度。所以复习的时候要把关键数字和寄存器名称背熟。比如:
- 51单片机有5个中断源,中断向量地址分别是0003H、000BH、0013H、001BH、0023H
- TMOD寄存器的低4位控制T0,高4位控制T1
- SCON的SM0和SM1位决定串口工作方式
- 复位后SP=07H,P0-P3=FFH
这些数字没有规律,只能死记。我建议用联想记忆法,比如中断向量地址都是8的倍数加3,0003H、000BH、0013H、001BH、0023H,这样记起来快一些。
6.2 简答题的答题框架
简答题通常考的是流程和原理,比如“简述51单片机中断响应的过程”。答题的时候要按步骤写,不要跳步。中断响应的过程可以这样写:
- 当前指令执行完毕后,CPU检查中断请求
- 如果有中断请求且中断允许,CPU保护断点(PC入栈)
- CPU跳转到中断向量地址
- 执行中断服务函数
- 中断服务函数执行完毕后,恢复断点(PC出栈)
- 返回主程序继续执行
这个流程考试里反复考,背下来就行。类似的还有“简述定时器的工作方式”“简述串口通信的帧格式”等,都是固定答案。
6.3 编程题的得分策略
编程题是拉分的关键,但也是很多人放弃的题。其实编程题的评分标准通常是看思路和关键代码,不是看你能不能编译通过。所以即使你写不出完整代码,也要把框架写出来,把关键寄存器配置写出来。
比如让你写一个定时器中断的程序,你至少要写出:
void Timer0_Init() { TMOD &= 0xF0; TMOD |= 0x01; // 方式1 TH0 = 0x3C; TL0 = 0xB0; EA = 1; ET0 = 1; TR0 = 1; } void Timer0_ISR() interrupt 1 { TH0 = 0x3C; TL0 = 0xB0; // 你的处理代码 }即使后面的处理代码写不出来,前面的初始化代码也能拿一半的分。我见过有人编程题直接空着,这是最亏的。哪怕只写个#include <reg52.h>和void main(){},也比空着强。
6.4 时间分配和检查重点
考试时间通常是两个小时,我的建议是:选择题和填空题控制在30分钟内,简答题控制在30分钟内,编程题留50分钟,最后10分钟检查。检查的时候重点看:
- 寄存器的位有没有写错(比如TMOD的M1和M0顺序)
- 中断号有没有写错(定时器0是1,外部中断0是0)
- 初值计算有没有算错(65536减去定时时间除以机器周期)
- 有没有忘记开总中断(EA=1)
这些低级错误丢分最可惜,但也是最容易避免的。
7. 从期末复习到实际项目的延伸
7.1 期末考完之后还能做什么
期末复习只是入门,51单片机真正好玩的地方在于用它做实际项目。考完试之后,你可以尝试做一些小项目,比如:
- 电子时钟:用DS1302时钟芯片加数码管,做一个能显示年月日时分秒的时钟
- 温度报警器:用DS18B20温度传感器加蜂鸣器,温度超过阈值就报警
- 密码锁:用矩阵键盘加LCD1602,做一个简单的密码锁
- 蓝牙小车:用51单片机加蓝牙模块和电机驱动,做一个能遥控的小车
这些项目在网上都有很多教程,但不要直接抄代码,要自己理解每一行代码的作用。我当初做蓝牙小车的时候,直接抄了一份代码,结果电机不转,后来发现是电机驱动的使能引脚没接对。自己排查问题的过程,才是真正学到东西的时候。
7.2 51单片机之后学什么
51单片机是入门级的单片机,学完之后可以进阶到STM32或者Arduino。STM32的性能比51强很多,但复杂度也高很多。如果你打算走嵌入式方向,STM32是必学的。如果只是想做些小玩意,Arduino可能更适合,它的库函数更丰富,开发门槛更低。
但不管学什么,51单片机打下的基础都是有用的。中断、定时器、串口、状态机这些概念,在任何一个嵌入式平台上都通用。所以不要觉得51单片机过时了,它只是你学习路上的第一块垫脚石。
7.3 我踩过的那些坑
最后分享几个我复习和做项目时踩过的坑,希望能帮你省点时间:
第一个坑是只看不写。我复习的时候把课本上的代码都看了一遍,觉得都懂了,结果考试的时候让写一个数码管动态扫描,我写了半天没写出来。后来我才明白,看懂代码和写出代码是两回事。所以复习的时候一定要动手敲代码,哪怕只是照着抄一遍,也比只看强。
第二个坑是忽略硬件细节。我刚开始学的时候,觉得软件最重要,硬件随便接接就行。结果有一次做流水灯,LED一直不亮,查了半天代码没问题,最后发现是LED的正负极接反了。从那以后,我每次接线都会先确认硬件的连接。
第三个坑是不重视消抖。按键消抖看起来是个小问题,但在实际项目里,如果不消抖,按键会误触发,整个系统都不稳定。我做的第一个交通灯项目,就是因为没消抖,按一次键跳了好几个状态。后来加了状态机消抖,才稳定下来。
第四个坑是中断服务函数写太长。我一开始喜欢在中断服务函数里做很多事情,比如刷新数码管、检测按键、处理串口数据。结果发现系统响应越来越慢,有时候还会死机。后来我把中断服务函数精简到只做最核心的事情,其他事情放到主循环里做,系统就稳定了。
这些坑看起来都是小问题,但每一个都让我花了不少时间。如果你能提前知道这些,复习和做项目的效率会高很多。