实战课题

第 37 课:智能温室模型(结课)

五个模块、三条闭环、一片纸皮房子——把这门课学的东西,攒成一个能拿给爸妈看的东西

我是吴老师。这是最后一课。 先别急着接线,你在脑子里看一个画面。桌上摆着一个巴掌大的纸皮小房子,屋顶是两片斜纸皮搭的,靠右边那片上开着一个方口——天窗。屋里侧墙上贴着一块指甲盖大的小屏幕,亮着两行字:26.5CRH 61%。左墙外面贴着一片蓝色小片(光敏),屋檐下挂着两个小圆筒(超声波)。你把手往光敏上一捂——屋里的灯亮了,光从门缝漏出来;你把手凑到那两个圆筒前面——屏幕上跳出一行字:"有人来了",灯也亮了;你放一杯热水进屋、关上门,等两分钟——屋顶"吱"的一声,天窗自己掀起来了,是屋里那个小舵机用一根冰棒棍顶开的。

这个东西不是买来的。是你做的。 第 37 课,我们做它。

一、为什么结课作品是"温室"

种菜的大棚里,菜一年四季都能长,因为温度、湿度、光照是有人在管的——太热就开窗通风,太黑就补光。我们这个纸皮小房子,就是那套系统的缩小模型。它一次性把五样东西全用上了:

智能温室模型做完以后的样子:纸皮小房子的屋顶有一个舵机顶开的天窗,屋里放着温湿度传感器和一盏灯,正面墙上贴着显示温湿度的 OLED 屏,门外挂着光敏和超声波

温湿度、光敏、超声波、OLED、舵机——这是整套课里模块最多的一个作品。 前面那些课你每次只对付一个模块,接三根线、跑段代码、看到现象就收工;这一次五个模块同时插在一块板子上、同时工作,还得互不打架。

这就是"实验"和"作品"的分界线。 做实验时世界很简单,只有你和那一个模块;做作品时你要考虑的是:这么多东西挤在一起,怎么才能都正常。

二、【闭环】这个作品里,转着好几条闭环

第 9 课我说过:作品必须走完 传感器(看)→ 主控(想)→ 执行器(做),缺一环就只能算演示。这一次,三条闭环同时在转。

多闭环共存:光敏、温湿度、超声波三个传感器共用一块主控,分别驱动灯、舵机和显示屏,三条闭环同时运行

# 传感器(看) 主控(想) 执行器(做)
光敏:现在多亮? 比阈值小吗? LED:天黑了就亮
DHT11:屋里几度? 超过 30 度吗? 舵机:顶开天窗散热
超声波:前面多远? 有人在 40 厘米内吗? OLED:跳出"有人来了",灯也亮
三个传感器 每 200 毫秒整理一次 OLED:一直显示屋里的情况

看最后一行——那个屏幕不在任何一条闭环的"回路"上,它不改变世界,它只告诉你世界现在什么样。 别小看它:你爸妈不会趴在板子上看串口监视器,但他们会看那块小屏幕。

难点一:引脚规划

五个模块十几根线,插哪儿?先数一遍,每个模块的信号到底是什么性质:

模块 信号是 必须接在哪
DHT11 数字(一问一答) 随便一个数字脚
光敏 模拟(连续变化的电压) 只能是 GPIO0 ~ GPIO5
超声波 数字两根(Trig 出、Echo 入) 两个数字脚
OLED I²C 两根 两个能做 I²C 的脚
舵机 数字(PWM) 一个数字脚

数出来了吗?真正"挑脚"的只有光敏一个。 第 4 课说 C3 只有六个模拟脚,当时听着挺紧张;真做系统你就会发现,模拟输入通常只有一两个,剩下五个空着。而且 C3 的 I²C 和 PWM 能挪到任意 GPIO 上(代码里指定就行,第 19 课那句 Wire.begin(8, 9) 干的就是这个),真正被"焊死"的只有模拟输入那六个。那引脚规划还规划什么?三件事:避开 GPIO2GPIO8GPIO9(strapping 脚,第 4 课讲过);别让两根线抢同一个脚(先列在纸上,比插完再找快十倍);给组装留余地(哪个模块装哪面墙、线从哪边走,想清楚再插)。

难点二:谁也别卡住谁

这是这个作品真正的难点,也是你第一次遇到。 回头看你写过的程序,几乎每个 loop() 里都躺着一个 delay(2000)——只有一个模块时这没问题,反正也没别的事干;现在有五件事要同时干,它就是灾难。

delay(2000) 的意思是"我在这儿站两秒钟,什么都不干"。这两秒里:天窗该开开不了,有人走过屏幕不反应,超声波一次都没量。你做饭时会站在锅前面盯着水烧开吗? 不会——点上火,转头去切菜,看一眼表,水开了再回来。

板子也得学会这个:不是"站着等",而是"看一眼表,没到点就先去干别的"。 这块"表"叫 millis(),第 4 步会用到。

三、材料清单

套件里的 家里要准备的
ESP32-C3 主控 + 拓展板、五个模块 纸皮(快递箱最好,别挑太软的)
LED 模块、杜邦线、电池盒(4 节 5 号) 美工刀 + 尺子 + 铅笔热熔胶枪 + 胶棒
USB 线 / 充电宝 美纹纸胶带、冰棒棍 1~2 根、一块垫刀用的废纸皮

美工刀那句话我必须说刀刃朝外推,别朝自己拉,左手别放在刀要经过的路线上。这不是唠叨,每年都有人因为这个去缝针。

四、接线

接之前先断电,接完检查一遍再上电——第 8 课就立下的规矩。

模块 针脚(看丝印/线色) 接到
DHT11 + / OUT / 3.3V / GPIO4 / GND
光敏 VCC / GND / AO 3.3V / GND / GPIO0
超声波 VCC / Trig / Echo / GND 3.3V / GPIO5 / GPIO6 / GND
OLED VDD / GND / SCK / SDA 3.3V / GND / GPIO9 / GPIO8
舵机 / / GPIO7 / 独立 5V 正极 / GND(共地)
LED 模块 VCC / GND / Signal 3.3V / GND / GPIO3

三件事单独拎出来说。① 光敏接 AO,不是 DO——第 11 课讲过,DO 只有"比某个亮度高还是低",我们要的是"到底多亮"。② OLED 那两根别接反——SCK 是时钟、SDA 是数据,接反了屏幕不亮(不会烧,换回来就行)。③ 舵机的电,绝对不能从板子上取。

舵机的电源要从独立 5V 来,并且负极必须和板子的 GND 连在一起共地

第 18 课你亲手踩过这个坑:舵机启动就是几百毫安、堵转能到 1 安培,而板子的 3.3V 只有几十毫安的命——等于拿台灯的电线去带空调,欠压保护一动作,板子直接重启。所以:红线 → 电池盒正极(4 节 5 号 = 6V,MG90S 标称 4.8~6V,正好);棕线 → 电池盒负极并且用一根线把电池盒负极和板子 GND 连起来,这就是共地

共地那根线,是这个作品里最容易被忘、后果最诡异的一根。 忘了它,舵机不会"完全不转",而是乱转、发抖、或者一动不动——线看起来全接对了,就是不对。 第 18 课讲过为什么:电压是"相对于地"的,两边没有共同的零点,板子说的 3.3V,舵机根本听不懂。

五、分步实现:四步,每步都有现象

别想着一次写完。 按第 9 课的规矩:先跑通最丑的版本,再往上加东西。

第 1 步:先把三个"读"跑通

传感器全接上,什么判断都不做,只往串口里打印。

C++
#include "DHT.h"
#define PIN_DHT 4
#define PIN_TRIG 5
#define PIN_ECHO 6
#define PIN_LIGHT 0
DHT dht(PIN_DHT, DHT11);

// 量一次距离(厘米);没听到回声返回 -1
float readDistance() {
  digitalWrite(PIN_TRIG, LOW);   delayMicroseconds(2);
  digitalWrite(PIN_TRIG, HIGH);  delayMicroseconds(10);
  digitalWrite(PIN_TRIG, LOW);
  long d = pulseIn(PIN_ECHO, HIGH, 25000);   // 最多等 25 毫秒
  if (d == 0) return -1;                     // 没听见回声
  return d * 0.034 / 2;                      // 那个 ÷2 别忘了
}

void setup() {
  Serial.begin(115200);
  dht.begin();
  pinMode(PIN_TRIG, OUTPUT);   pinMode(PIN_ECHO, INPUT);
}

void loop() {
  float temp  = dht.readTemperature();
  float hum   = dht.readHumidity();
  int   light = analogRead(PIN_LIGHT);
  float cm    = readDistance();
  Serial.print(temp);  Serial.print(" C   ");
  Serial.print(hum);   Serial.print(" %   ");
  Serial.print(light); Serial.print("   ");
  Serial.println(cm);
  delay(2000);     // 最丑的版本,第 4 步会改掉
}

现象:串口里每两秒刷出一行数。手一捂光敏,第三个数字就变;手往超声波前面一凑,最后一个数就变小。

注意 pulseIn 里多了个 25000 第 15 课讲过,pulseIn 等不到回声会傻等一整秒——在这个作品里不能忍,它一卡,整个系统跟着卡一秒。 第三个参数是超时(微秒),超过 25 毫秒就当没听见,返回 0。那个 -1 的意思是"这次没测到",后面判断时必须把它排除掉,不然一个野数据就能让屏幕乱跳。

第 2 步:把数显示到屏幕上

C++
// 顶部加上:
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
Adafruit_SSD1306 oled(128, 64, &Wire, -1);

// setup() 里加上:
  Wire.begin(8, 9);                        // 先 SDA 后 SCL
  oled.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // 0x3C 是它的地址
  oled.setTextColor(SSD1306_WHITE);

// loop() 里、delay 之前加上:
  oled.clearDisplay();                     // ① 擦干净
  oled.setTextSize(1);   oled.setCursor(0, 0);
  oled.print(temp); oled.print("C  RH "); oled.print(hum);
  oled.setCursor(0, 16);
  oled.print("LIGHT "); oled.print(light); oled.print("  DIST "); oled.print(cm);
  oled.display();                          // ② 推上屏,忘了这句前面全白画

现象:屏幕上出现四行信息,跟着你的手在变。 屏幕不亮就按第 19 课那套查:先量 VDD 电压,再通断档量四根线,然后跑一个 I²C 扫描程序看地址对不对。

第 3 步:加上判断和动作

读到了得会判断,判断完得有动作。

C++
#include <ESP32Servo.h>
Servo windowServo;

#define PIN_LED    3
#define PIN_SERVO  7
#define TEMP_OPEN  30     // 高于它 → 开窗
#define TEMP_CLOSE 28     // 低于它 → 关窗
#define LIGHT_DARK 1500   // 光敏读数小于它算天黑
#define NEAR_CM    40     // 有人凑到这么近

bool windowOpen = false;  // 记住天窗现在开着还是关着

// setup() 里加上:
  windowServo.attach(PIN_SERVO);
  windowServo.write(0);          // 先归位:天窗关着
  pinMode(PIN_LED, OUTPUT);

void controlAll(float temp, float cm, int light) {
  // 闭环②:热了开窗,凉了关窗
  if (temp > TEMP_OPEN && windowOpen == false) {
    windowServo.write(60);       // 60 度是"刚好顶开",你要自己标
    windowOpen = true;
  }
  if (temp < TEMP_CLOSE && windowOpen == true) {
    windowServo.write(0);   windowOpen = false;
  }
  // 闭环①+③:天黑了 或者 有人靠近,灯都亮
  bool someone = (cm > 0 && cm < NEAR_CM);
  if (light < LIGHT_DARK || someone) digitalWrite(PIN_LED, HIGH);
  else                               digitalWrite(PIN_LED, LOW);
}

现象:捂住光敏,灯亮;拿开手,灯灭。把手凑到超声波前面,灯又亮了。

两个地方停下来看看。① windowOpen 是干嘛的? 它是为了只在需要的时候才给舵机下命令。如果不判断、每圈都 write(60) 一遍,舵机一秒钟收到几百条命令——表现就是持续地抖、嗡嗡响、发热。 记住第 18 课那句:write() 是"告诉它去哪儿",不是"把它掰过去",同一句话不用反复喊。

|| 是"或者"。 这里用"或者"——天黑了或者有人来,灯都亮。为什么白天有人来也要亮? 因为灯在这儿干的不是照明的活,是提示的活:有人走到门口,灯亮一下,他才感觉得到"这房子注意到我了"。同一个 LED,在两个闭环里承担了两个角色——这种事在真实产品里到处都是。

第 4 步:把 delay 换成 millis,让大家各走各的

上面那个程序,loop() 一圈要花 2 秒:屏幕 2 秒才刷一次(你捂光敏,要等两秒灯才亮),超声波 2 秒才量一次(手都缩回来了,它还没看见)。更要命的是,你想让屏幕刷快点,一改 delay,DHT11 就被读得太频繁,直接给你一堆 nan(第 16 课那个坑)。几件事的节奏本来就不一样,凭什么用一个 delay 管?

任务 多久干一次 为什么是这个数
超声波量距离 100 毫秒 它快,多量几次没坏处
DHT11 读温湿度 2000 毫秒 这是它要求的,不是我们随便定的
OLED 刷新 200 毫秒 再快人眼也看不出来

把第 2 步那几行显示代码抽成一个 drawOLED() 函数,再给每件事各配一块"表":

C++
unsigned long tSonar = 0, tDht = 0, tOled = 0;
float temp = 0, hum = 0, cm = -1;
int   light = 0;

void loop() {
  unsigned long now = millis();          // ① 看一眼表

  if (now - tSonar >= 100) {             // ② 算算离上次过了多久
    tSonar = now;                        // ③ 到点了,干完把表拨到当前
    cm = readDistance();
  }
  if (now - tDht >= 2000) {
    tDht = now;
    temp  = dht.readTemperature();
    hum   = dht.readHumidity();
    light = analogRead(PIN_LIGHT);
    controlAll(temp, cm, light);         // 读完立刻判断
  }
  if (now - tOled >= 200) {
    tOled = now;
    drawOLED(temp, hum, cm, light);
  }
}

void drawOLED(float temp, float hum, float dist, int light) {
  oled.clearDisplay();
  oled.setTextSize(2);  oled.setCursor(0, 0);
  oled.print(temp, 1);  oled.print("C");
  oled.setTextSize(1);  oled.setCursor(0, 26);
  oled.print("RH "); oled.print(hum, 0); oled.print(" %  LIGHT "); oled.print(light);
  oled.setCursor(0, 44);
  if (dist > 0 && dist < NEAR_CM) oled.print(">>> 有人来了 <<<");
  else if (dist > 0) { oled.print("DIST "); oled.print(dist, 0); oled.print(" cm"); }
  else               oled.print("DIST --");   // 别把 -1 显示出去
  oled.display();
}

loop() 一圈现在"唰"一下就转完了,谁也不用等谁。

这就是"非阻塞"(以后查资料会遇到这个词)。它的反面就是 delay——delay 不是"暂停一下",是"整个系统停摆一下"。一个人干活的房间里,一个人睡着了没关系;五个人的房间里,一个人睡两秒,另外四个人就得等他两秒。

现象:手往超声波前面一放,屏幕上"有人来了"几乎立刻跳出来,不是等两秒;天窗开合那一下屏幕照样在刷新;DHT11 再也没有 nan 了。到这儿,代码就写完了。

六、组装:把纸皮房子做出来

先接好线、跑通全部功能,再动手做外壳。 顺序反了,你会一边粘纸皮一边查线,特别痛苦。尺寸按这个来,第一次做别自己改:底板 20 × 16 厘米一块;前后墙 20 × 12 两片;左右墙 15 × 12 两片;屋顶 14 × 13 两片;再加一根 8 厘米左右的冰棒棍

第 1 步:画线、裁。 用尺子和铅笔把这些方块画在纸皮上,垫一块废纸皮,刀刃朝外推。尺寸不完美没关系——纸皮是软的,差两三毫米,热熔胶一盖就过去了。

第 2 步:先在天窗那片屋顶上开孔。 一定要在粘屋顶之前做。离下沿 3 厘米、离左边 3 厘米处画一个 6 × 6 厘米的方框,四条边全裁断,把方块拿出来——这块方块就是窗盖,别扔。

第 3 步:做一个"合页"。 裁一条 5 厘米长的美纹纸胶带(刷墙用的那种,比透明胶好撕好粘),一头粘在窗盖的上边,另一头粘在方孔的上边现在窗盖就像一扇小门,能掀开、能合上了。 试两下,合上时能盖住孔就行。

第 4 步:装舵机、做连杆。 舵机立着放在屋脊内侧、方孔斜下方(离合页最远的那条边),舵盘朝上正对窗盖,先别粘死,用橡皮筋临时固定。然后在舵盘上粘一根冰棒棍,棍子另一头顶在窗盖背面。原理特别土,但特别管用:棍子缩回来,窗盖落下;棍子顶出去,窗盖掀开。

角度要自己标定(这就是第 11 课那句"先测,再定",只不过标的不是阈值,是角度):先跑一段最简单的舵机代码,write(0) 停两秒、write(30) 停两秒……一路试到 120,看哪个角度刚好把窗盖顶到全开,把那个数写进代码。

听到"嗡嗡"声就说明角度太大了。 那个声音的意思是"我转不动了"——这是堵转,电流会一下子冲到 1 安培,舵机还会很快发热。听到就赶紧往回退 5 度。这个声音你以后会经常听到,学会认它。

第 5 步:贴模块。 OLED 贴正面墙上,开一个比屏幕略小的方孔,屏幕从里面贴上去,先接上线试亮、确认方向没反再上胶;光敏贴左墙外侧靠上,小圆片朝外;超声波贴屋檐下面正对门口,前面别挡东西;DHT11 放屋子里面,用小块纸皮做个托架起来、离墙 1 厘米以上;LED 吊在屋顶内侧或放门口,光要能漏出来;板子粘房子外面的背面——别粘屋里,你要经常插拔 USB 线。

DHT11 那条"离墙 1 厘米"不是矫情。 它测的是贴着它的那团空气;紧贴在纸皮上,它测到的是纸皮的温度——太阳一晒,那个数能比屋里高好几度。(这跟第 12 课热敏那句"热量传进去要时间"是同一件事。)

第 6 步:走线。 在房子背面开一个 1 厘米的小孔,所有的线从这一个孔穿出去,孔开在板子旁边。线出来后用胶带稍微固定,别让它们绷着——绷着的线,你搬房子时一拽就把模块扯下来了。第 7 步:最后通一次电。 捂光敏 → 灯亮;凑近超声波 → 屏幕提示;放杯热水进去 → 天窗开。都没问题,就可以拍照了。

七、【排查】装完之后,如果它"抽风"

这一节请你认真看,这是这个课题埋的坑。 先看现象,你会遇到下面两种中的一种。症状 A:舵机一动,板子就重启——天窗开合那一下,串口里又打印一遍启动信息,屏幕黑一下又亮。症状 B:舵机一转,屏幕上的数就乱跳——超声波一会儿 12 厘米、一会儿 300 厘米,光敏读数也跟着抽。

先记住一句话:这两种现象,八成都不是代码的问题。 代码你上面已经跑通过了——如果代码有错,它会一直错,不会专挑舵机动作的那一瞬间错。挑时机出错,说明是"电"或"地"的事。第一步先观察"什么时候出问题"——听着像废话,其实最重要:你只要确认了"每次都是舵机动作时才出问题",就已经排除掉一半的可能了。

第二步:电压档,量舵机的电源——但要在它"动"的时候量。 写个小程序让天窗反复开合,你就有时间慢慢量了:

C++
void loop() {
  windowServo.write(0);   delay(1000);
  windowServo.write(60);  delay(1000);
}

黑笔搭电池盒负极,红笔点舵机的红线:

你量到 说明什么
静止时 6V 左右,动作瞬间掉到 3V 以下 舵机的电不够——电池没电了,或者用的电池太小
静止、动作都稳在 6V 左右 电没问题,往下查地
一动不动就是 0V 电源根本没接上,回头看接线

"静止的时候是 6V"这句话是个陷阱。 静止时舵机几乎不耗电,你量到的永远是漂亮的 6V。一定要在它动的那一瞬间看——这就是第 18 课那句"舵机一转,电压会掉一点,那就是电流大的证据"。

第三步:通断档,量两个"地"之间通不通。 黑笔搭电池盒负极,红笔搭板子(或拓展板)的 GND:响了就是通的,往下走;不响,就找到了——共地线没接,或者断了。

这儿还有个小细节(第 5 课教过):如果线看着是插着的,但不响——把这根线从两头都拔下来,单独量它两个头。 还不响,就是线内部断了;响了,那是插头没插到底。这两种情况的处理方式完全不同,只有拔下来单独量才能分开。

第四步:用手轻轻推一下窗盖。 如果它本来就转不动——恭喜,你找到另一种原因:舵机被卡住了。 天窗粘歪了、冰棒棍顶得太死、窗盖蹭到屋顶——舵机转不动就是堵转,电流直接冲到 1 安培,这个电流什么电池都扛不住,板子照样重启。处理办法:角度往回退 5 度,或者把冰棒棍改短一点。

现在说清楚这个坑:它是我故意留在第 37 课里的。 接线表上我把舵机的独立供电和共地都写全了——但你回头看组装那一节的第 6 步:你要把所有线从一个孔里穿出去,再固定一遍。这个过程里最容易掉的,就是那根灰色的共地线(它通常最短、最不起眼,一拽就松),还有一种更常见的情况:你嫌麻烦,顺手把舵机的红线插回了板子的 5V 脚。 然后现象就来了:不是"舵机不转",而是"板子老是重启"。症状离原因隔了十万八千里——这正是这个坑的价值。你要是不懂电,你会去改一晚上代码,而代码一个字都没错。

为什么结课作品要埋这个坑?因为它把第 5 课和第 18 课的能力全用上了:第 5 课的万用表、通断档、电压档、"电 → 信号 → 代码"的排查顺序,第 18 课的"舵机为什么要独立供电、共地那根线为什么不能省"。这两样东西,才是这门课最值钱的部分——模块的用法你迟早会忘,库的名字你随时能搜,但"出了问题知道往哪儿看"这个本事,搜不到。

自测

单选题这个作品里,为什么不能到处用 delay(2000)
单选题装完之后,天窗每次一开合板子就重启。你会做哪件事?
单选题你的温室显示 27.5°C,家里温度计是 26°C,差了 1.5 度。怎么办?
问答题这个作品里转着好几条闭环。请指出其中两条,分别说出它们的"传感器 → 判断 → 执行器";再想一想:"湿度超过 75% 就开窗"这条闭环该怎么加进代码里?
拓展让板子"同时做几件事"这件事,到底难在哪?有没有更正规的做法?

这个问题课上不讲,留给你自己找答案——**问 AI 是最好的办法**。

提示:搜"Arduino millis 非阻塞 多任务"、"FreeRTOS 任务 优先级 ESP32"。想一想:millis 这套办法在事情少的时候够用,那要是有二十件事呢?如果某件事必须"立刻"响应(比如紧急刹车),排队还来得及吗?

拓展真实的温室是怎么控温的?为什么它们不用"到 30 度就全开"这种开关式判断?

这个问题课上不讲,留给你自己找答案——**问 AI 是最好的办法**。

提示:搜"温室 环境控制 湿帘 风机"、"PID 控制 温控 原理"。想一想:如果温度刚过 30 度就全开天窗、降到 29 度又全关上,会发生什么?真实系统为什么更愿意"开一点点"?

本节你要动手做的事

  • [ ] 先跑通三个"读":DHT11、光敏、超声波,全部打印到串口
  • [ ] 加上 OLED:擦 → 画 → display(),三步别漏
  • [ ] 标定天窗的角度:先不粘,试出"刚好顶开"和"完全关严"那两个数,写进代码
  • [ ] 标定阈值TEMP_OPENLIGHT_DARKNEAR_CM 都别抄我的——按第 11 课那套,先测你自己的环境,再定线
  • [ ] delay 全换成 millis:改完感受一下"反应变快了"是什么样
  • [ ] 做纸皮房子:四面墙 + 屋顶 + 天窗,裁纸皮时刀刃朝外推
  • [ ] 固定五个模块:DHT11 离墙 1 厘米,超声波正对门口,板子粘房子外面
  • [ ] 走线:背面开一个孔,线束固定好,别让线绷着
  • [ ] 把共地线单独检查一遍:通断档量电池盒负极和板子 GND——这是最容易掉的一根
  • [ ] 给它拍张照,再录一段视频:捂光敏、凑近超声波、放杯热水进去

这门课,到这儿就结束了

你把最后这个东西做出来了。 我们回头看一眼这条路。

你拿到了什么
6 让一颗灯亮起来——你第一次让板子动了手
9 第一条闭环——"看 → 想 → 做"
11 标定——先测,再定
15、16 跟模块"按规矩说话":超声波要除以 2,DHT11 会给你 nan
18 让板子输出"37 度",还有独立供电和共地
19 把数字变成人能看懂的信息
20 ~ 25 让板子上网、自己当服务器、两块板子隔空喊话
26 ~ 36 十一个能拿回家的东西
37 把它们攒成一个系统

我不打算在这儿说很多煽情的话,就说三个事实。第一,你把环境装上了——第 1 课和第 2 课那两节是这门课弃坑率最高的地方,最枯燥、最容易报错、一点都不好玩,你过了。第二,你手上现在有一个会自己判断的东西:温度高了它开窗,天黑了它开灯,有人来了它有反应——这不是"照着图接完就亮"的实验,这是一个系统,五个模块、三条闭环,共用一块板子还得互不打扰。第三,你踩过坑,而且是靠万用表爬出来的——从第 26 课到现在,每个课题我都埋了一个故障;你要是做过一半以上,你手里的万用表已经不是摆设了,你知道先量什么、后量什么,知道"线插着"和"线通着"是两回事。

这三条,没有一条是靠聪明做到的,是靠你一片纸皮一片纸皮粘、一根线一根线量、一个数一个数试出来的。

这个作品本身还没做完,至少还有三个方向能接着改:让它上网(第 20 ~ 23 课),把温湿度发到手机上,人在学校也能看见家里那盆花的环境;让它出声,套件里那个蜂鸣器还没用上,温度超了、湿度太低就让它叫;让它更聪明,现在是"到 30 度就全开",能不能改成"越热开得越大"?(搜"PID",你会发现一个全新的世界。)

想再学深一点,可以往这几个方向摸:编程——millis 那套在事情多了以后就不够用了,该看 FreeRTOS(ESP32 自带)和中断电路——从"用模块搭"走到"自己画一块板子",PCB 打样现在很便宜;外壳——3D 打印,这个门槛现在对你来说不存在了,你已经知道"做一个东西"是怎么回事,剩下的只是学一个软件。

还有两个方向值得试试。一个是参加比赛——各地都有面向中小学生的科创类比赛和实践活动,你这个温室模型就是一个很成型的作品,有传感器、有执行器、有外壳、有明确要解决的问题,你只要再补上"我想解决什么"的说明,它就是一份完整的作品,搜一搜你们省、市今年的相关活动看看要求。另一个,可能是我最想推荐的:去教别人。 你班上肯定有同学看着你桌上这些东西发愣,你把这个温室的做法讲给他一遍——讲到"为什么舵机不能从板子上取电"的时候,你会发现,你自己才真的懂了。教是最好的学,这句话听着像口号,但你试一次就知道它是真的。


这门课到这儿结束了。但你这块板子,才刚开始。 以后你遇到一个"要是能自动……就好了"的念头时,别只是想想——你手上有工具,你知道从哪儿下手。去做点你自己的东西吧。

吴老师,下课。