基础入门
第 6 课:点亮 LED 模块
第一次用代码指挥硬件干活。从这节起,板子听你的了
我是吴老师。从这节课开始,板子听你的了。
前面五节课,你干的事都是"认识"和"测量"——认元件、量电压、验线。板子该怎么样还怎么样,你只是旁观。
这一节不一样。 你要写几行代码,然后亲眼看着一个东西按你说的做。
而且我先告诉你一件事:学会点灯,你就学会了一半的输出设备。 因为 LED 模块和蜂鸣器模块的用法一模一样——都是给高电平就动作、给低电平就停。你今天把 LED 玩明白,下下节课的蜂鸣器就是顺手的事。
一、数字输出:只有两种状态
先说清楚这节课的知识点:数字输出。
什么叫"数字"?就是只有两个值——高,或者低。没有中间。
这跟你家里的电灯开关是一样的:要么开,要么关,没有"开一半"这一说。("开一半"是另一回事,叫 PWM,第 18 课讲。)
那"高"和"低"到底是什么?是电压。
| 代码里写的 | 引脚上的电压 | LED 模块 |
|---|---|---|
HIGH |
3.3V | 亮 |
LOW |
0V | 灭 |
这一点非常重要,我要重复一遍:HIGH 和 LOW 不是"开"和"关"这两个字,它们背后是实实在在的电压。
你写 HIGH,板子就在那根引脚上输出 3.3 伏。LED 模块收到 3.3 伏,它就亮。你写 LOW,引脚变成 0 伏,灯就灭。
这就是"代码控制硬件"的全部秘密——代码改电压,电压驱动设备。没有别的魔法。
二、三步走:怎么让灯亮起来
代码其实只有三步。我先给你看全景,再一步步说。
void setup() {
pinMode(3, OUTPUT); // 第 1 步:给 GPIO3 分配岗位
}
void loop() {
digitalWrite(3, HIGH); // 第 2 步:让它输出高电平
delay(500); // 第 3 步:等一会儿再往下
digitalWrite(3, LOW); // 再输出低电平
delay(500);
}第 1 步:pinMode(3, OUTPUT) —— 分配岗位
先说个事:板子上的引脚,是可以"扮演不同角色"的。
同一根 GPIO3,它既可以往外输出信号(指挥别人),也可以往里读信号(听别人说话)。它自己不知道自己要干哪个——得你告诉它。
pinMode(3, OUTPUT) 就是在说:"GPIO3,从今天起你是输出岗。"
打个比方:一个员工到岗,得先分配他干什么。你先告诉他"你负责发货",他之后才知道该干什么。 你不说,他站在那儿发懵。
注意:这件事只需要做一次。 所以它放在 setup() 里——那个只跑一次的块。
第 2 步:digitalWrite(3, HIGH) —— 真的下命令
岗位分配完了,现在可以指挥了。
digitalWrite(3, HIGH); // GPIO3,输出高电平(3.3V)→ 灯亮
digitalWrite(3, LOW); // GPIO3,输出低电平(0V)→ 灯灭digitalWrite 这个词拆开看就是"digital write"——写一个数字值出去。写什么?写 HIGH 或者 LOW。
这是真正干活的那一步。 前面 pinMode 只是准备,这里才动手。
第 3 步:delay(500) —— 等一会儿
delay(500) 是"停 500 毫秒"(也就是半秒)。
为什么要有它? 没有它,程序会以极快的速度不停地亮、灭、亮、灭——快到你的眼睛完全看不出来,只会觉得灯是全亮的(或者微微发暗)。
板子一秒钟能执行几十万次循环。你不拦它一下,它一秒钟能开关灯几千次。
所以
delay是给"人眼"用的,不是给板子用的。 它让节奏慢下来,慢到你能看见。
三、为什么分成 setup 和 loop 两块
这是学生第一次见到这个结构,我专门讲一下。
setup() —— 开机准备,只跑一次。
像早上到岗:开电脑、登录账号、把工具摆好。这些事做一遍就够了,不需要反复做。
所以引脚的"岗位分配"(pinMode)放这里——分配一次就行。
loop() —— 正式干活,一圈接一圈。
准备工作做完了,开始干活。干完一圈,自动回到开头再来一遍,永远不停。
所以"亮 → 等 → 灭 → 等"放这里,它就会一直闪下去。
为什么板子要这样设计? 因为嵌入式设备干的活,绝大多数都是"反复做同一件事"——一直检测温度、一直看有没有人经过、一直刷新屏幕。所以干脆给你一个专门用来循环的地方。
你想让它停?拔电源。(真要做"跑一次就停"的程序,也能做,但那是后话。)
四、动手:从最简单开始
别一上来就写闪烁。 按下面的顺序来,每步都先看到现象,再加东西。
第一步:先让它一直亮
接线(跟第 2 课一样):
| LED 模块 | 接到 |
|---|---|
| VCC | 3.3V |
| GND | GND |
Signal |
GPIO3 |
代码先写最丑的版本——就让它亮,不闪:
void setup() {
pinMode(3, OUTPUT);
}
void loop() {
digitalWrite(3, HIGH); // 一直输出高电平
}烧进去。灯亮了吗?
亮了就对了。 你刚刚用代码控制了一个物理设备。
如果没亮,别改代码——按第 5 课那个顺序查:电 → 信号 → 代码。
- 先量
VCC上有没有 3.3V- 再量
Signal那根线通不通- 最后才怀疑代码
九成的"没反应"都在前两步。你现在有工具了,别再靠猜。
第二步:让它闪起来
现在加两行,把"灭"和"等待"补上:
void setup() {
pinMode(3, OUTPUT);
}
void loop() {
digitalWrite(3, HIGH);
delay(500);
digitalWrite(3, LOW);
delay(500);
}烧进去——灯开始一闪一闪了。
注意这里有个细节:loop 里没有"回到开头"这句话。 它自己会回去。这就是为什么叫"循环"。
第三步:用万用表验证一下
这一步别跳过。 它花你两分钟,但能让你真正"看见"代码在硬件上干了什么。
把程序停下来,改成一直亮那个版本(输出 HIGH)。然后:
- 万用表拨到直流电压档
- 黑表笔搭 GND
- 红表笔点在
GPIO3上
你应该看到 3.3V 左右。
再改成 LOW 烧进去,重新量——这次是 0V。
看到没有? 代码里那个
HIGH,就是这么变成引脚上真实的 3.3 伏的。你不是在"相信"它输出了 3.3V,你是量出来的。 这两件事的区别,就是前面几节课一直在讲的东西。
第四步:自己改一个数
这是这一节最重要的练习。
把 delay(500) 改成 delay(100),重新烧——
灯闪得快多了,对不对?
再改成 delay(2000),烧进去——灯变得慢悠悠的。
恭喜,你在调参数了。 这是写程序里最常见的一件事:逻辑不动,改数值看效果。你后面每节课都会干这个。
自测
digitalWrite(3, HIGH),这根引脚上实际发生了什么?答案与解析
HIGH / LOW 背后是实实在在的电压。写 HIGH,引脚输出 3.3V;写 LOW,输出 0V。LED 模块认的是电压,不是"开/关"这两个字。理解了这一层,你就理解了"代码控制硬件"的全部秘密。
pinMode(3, OUTPUT) 这句话的作用是什么?答案与解析
引脚可以扮演不同角色(输出信号 / 读取信号),它自己不知道要干哪个。pinMode 是分配岗位,digitalWrite 才是下命令。这两件事必须分开,而且 pinMode 只需要在 setup() 里做一次。
答案与解析
电 → 信号 → 代码。 这不是背口诀,是因为硬件故障和代码故障的表现长得一模一样,都是"没反应"。你不先排除硬件,就是在拿改代码的精力去赌硬件的运气。而九成的"没反应",在前两步就找到了。
拓展为什么几乎所有单片机程序都分成"初始化"和"主循环"两块?别的写法不行吗?
这个问题课上不讲,留给你自己找答案——**问 AI 是最好的办法**。
提示:搜"嵌入式 主循环 结构"、"Arduino setup loop 为什么"。想一想:如果只让你写一个死循环,你能实现同样的功能吗?那为什么还要分成两块?
拓展引脚输出只有 3.3V,它能直接驱动一个马达、或者一圈 LED 灯带吗?
这个问题课上不讲,留给你自己找答案——**问 AI 是最好的办法**。
提示:搜"单片机 IO 驱动能力"、"三极管 驱动 电机"。想一想:3.3V 是电压,但驱动一个马达还需要什么?为什么很多模块上要额外加驱动芯片?
本节你要动手做的事
- [ ] 接好 LED 模块:
VCC→3.3V,GND→GND,Signal→GPIO3(接之前先断电) - [ ] 先让它一直亮——跑通最丑的版本,再往上加东西
- [ ] 让它闪起来,然后自己改
delay的数值,看快慢变化 - [ ] 用万用表量一次
GPIO3:输出HIGH时是不是 3.3V?输出LOW时是不是 0V?这一步别跳过 - [ ] 想一个"不闪但也不常亮"的效果,试着实现它
这节课你做的东西很小——就是让一颗灯闪。
但我想让你意识到你实际做成了什么:你写的那几行字,变成了一根引脚上真实的电压,然后驱动了一个真实的物理设备。
这个链条,就是所有智能硬件的底层逻辑。你家的智能灯泡、扫地机器人、电梯里的按钮,到底层都是这件事:代码 → 电压 → 动作。
只不过它们比你这颗灯复杂几百倍而已。但方向是一样的,而你已经走通了第一步。
下一节我们让板子开口说话——把程序内部在想什么,直接打在屏幕上给你看。那是个特别有用的本事。