超声波雾化片做 DIY 加湿器:干烧、供电与继电器控制

Cartoon of a large ultrasonic mist maker disc with a bright sky-blue ceramic ring and dark grey mesh centre set in a translucent white silicone gasket, red and black leads running to a small white two-pin plug, a white mist plume rising from its centre above a shallow bowl of pale teal water with a white cotton wick leaning up to touch it, and the small green driver board at the lower right

超声波雾化片是一片布满微孔的金属片,由压电陶瓷带动;而它雾化掉的那些水,同时也是它唯一的散热介质——所以一片干烧的雾化片,几秒到几分钟之内就会退化报废。这一个事实决定了整套做法:给模块自己一路 5 V 电源,用继电器或 MOSFET 去开关那一路电,而不是从单片机引脚直接出,再让水位传感器在水见底之前先把它切掉。

这篇里所有东西都是 USB 充电器出来的 5 V 直流。全程不碰市电。

超声波雾化片到底是怎么出雾的?

市面上它叫超声波雾化片、超声波雾化模块、雾化器模块,也有人叫 fogger module 或 mist generator,但拆开来永远是同样两件东西:一块驱动板,加一片换能器。这套超声波雾化模块里的换能器不是实心圆片:天蓝色陶瓷环中间那颗深灰色的圆点,是一片很薄的金属片,上面打了大约 740 个锥形微孔,进水那一面孔口大,出雾那一面只有几微米。

蓝色那一圈才是压电的部分。给它 108 kHz 的交流电压,它就在自己所在的平面内一伸一缩;因为它被夹在那片更硬的微孔金属片边缘上,这种面内的形变只能转成面外的弯曲,于是金属片的中心像活塞一样来回走动不到一微米的距离,每秒 108,000 次。每个锥形孔在回程时从湿的那一面吸满水,在去程时把这一小柱水从窄口挤出去,碎成大约 5 µm 的液滴。这是一个泵,不是实心圆片式水箱雾化器所用的空化作用——而这么小的液滴还来不及落下就已经蒸发,所以那道雾看起来是干的。关于振动微孔片雾化器的公开研究里,这一类金属片的固定驱动频率横跨 100–300 kHz 这一段。

那块绿色的小驱动板负责电的那一半:一个固定频率的振荡器,开环地朝雾化片打出大约 108 kHz,完全不从雾化片取任何反馈,所以根本没有什么波形要你去生成——而且只要 5 V 一到,它自己就开始跑。整个控制方案就架在这一点上:板上那颗黑色按键是在通电的状态下切换雾化模式的,但把 5 V 断掉再送上,板子会回到上电时的预设状态,所以在供电线上串一个继电器,那就是一个完整的开关,而不是半个。动手接线之前先做一件事:把棉芯沾湿,把模块插到手机充电器上,确认它不必按键就会出雾。

这一类雾化驱动板的实机拆解,连原理图都画了出来:

可选:换一种开关、换一颗大脑、加一条烧录线

ItemPriceQty
IRF520 MOSFET Driver Module PWM Output Power Control for Arduino Raspberry Pi DC Motor ControlIRF520 MOSFET Driver Module PWM Output Power Control for Arduino Raspberry Pi DC Motor ControlIR520AMRM4.95缺货
NodeMCU ESP32 Wi-Fi + Bluetooth Development Board CH340/CP2012 - For IOT Project - ESP-32 (CH340)NodeMCU ESP32 Wi-Fi + Bluetooth Development Board CH340/CP2012 - For IOT Project - ESP-32 (CH340)E32CH34RM29.90
Data Cable Type-A Type-C MicroUSB Type-B 0.5m 1m 30cm 0.3m 100cm Data Transfer Upload Code - TYPE-A TO TYPE-B (1.0M)Data Cable Type-A Type-C MicroUSB Type-B 0.5m 1m 30cm 0.3m 100cm Data Transfer Upload Code - TYPE-A TO TYPE-B (1.0M)ATBC100RM4.90

IRF520 MOSFET 模块切换时完全无声,也没有触点会磨损,但它断的是负极那一条而不是正极,而且它的栅极并非逻辑电平——换上去之前先看我们那篇 IRF520 教程。ESP32 板则是想做定时或网页控制、而不只是一个固定阈值时的升级选择;同一颗继电器在低电平触发跳线位置下,用它的 3.3 V 引脚也带得动——但低电平触发会把静止状态反过来,所以要挑一支上电时不会被拉低的 GPIO,并在 setup() 第一行就把它拉高。A 转 B 的数据线配的是 Uno 那个方口 Type-B 接口。

雾化模块盒子里装的是四件东西,不是一块光板:绿色驱动 PCB、一片 20 mm 换能器(引线已经焊好,末端是白色 JST 插头)、一根棉芯,以及黑色外壳的上下两半。棉芯塞进下半壳的管子里,圆片正面朝上放进上盖,所以把上盖压下去的时候,圆片的底面刚好压在棉芯上——这一处接触就是全部的水路。插头再插进驱动板上那个白色插座,方向只有一种插得进去。

干烧为什么几秒钟就能把雾化片弄坏?

雾化片上的那层水同时在做三件事:它是被雾化的工作介质,它是机械负载,它也是那圈陶瓷唯一的散热片。

水一没了,这三件事一起没。每一颗被甩出去的液滴都带走一份能量,而表面那层水膜又在给金属片的运动做阻尼;一旦空载,同样的驱动会让它摆得大得多,而这些能量却没有地方可去。于是它变成热,堆在一圈只有零点几毫米厚的陶瓷里,而这圈陶瓷的散热通道,正是那些已经不在了的水。

这种损坏是永久的,不是一个复位就能清掉的故障。压电陶瓷之所以能工作,是因为它内部的电畴曾经在出厂时被强电场一次性排列整齐;高温会把这个排列打乱,材料退极化,而且冷下来之后也不会自己排回去。一片被烤过的雾化片可以看起来完好如初,通电也照样有电流——只是雾变少了,或者干脆不出了。

驱动板上没有任何东西在盯着这件事。它的振荡器是开环跑的,完全不从雾化片取反馈,所以它分不出一片泡在水里的圆片和一片干透的圆片——两种它都照样驱动。这一类驱动板的官方资料里写到的唯一一项防干烧措施,是四小时或八小时之后的定时自动关机,而一个计时器不是水位传感器。真正麻烦的是半湿的情况:棉芯已经够不着水,于是一部分孔上还盖着水膜、另一部分什么都没有,雾就变薄但始终不停,干掉的那一块在烤,板子却继续跑。

卡通对比图,从中间一分为二:左边一片超声波雾化片,一根白色棉芯从装满淡青色清水的碗里伸上来贴住它,圆片中心升起一道白色雾柱;右边同一片圆片下面的碗几乎见底,棉芯远远够不着,完全没有雾,四周散着橙红色的热线,天蓝色陶瓷环上还有一块暗褐色的烤焦痕迹
左边:棉芯够得着水,水膜把驱动能量以雾的形式带走。右边:棉芯已经够不着,同样这些能量除了钻进陶瓷里没有别的去处。

这个模块到底吃多少电流,引脚为什么带不动?

在同一份资料里,雾化模块标的是 5 V、300 mA、2 W,而这三个数字彼此并不完全对得上:5 V 下的 300 mA 是 1.5 W,而 2 W ÷ 5 V = 0.4 A。按两者中大的那个来设计,两边都不会出事,所以电流预算就取 0.4 A。

一块 Arduino Uno 的 I/O 引脚,官方给出的建议值是 20 mA。四百毫安是它的二十倍,所以这根本不是一个在边缘上的判断——你等于要求引脚里的输出管当一段导线用,而它的下场是短路或断路,通常还是永久的。

Uno 自己那条 5 V 电源轨也不是答案。USB 2.0 口给整块板的就是 500 mA,而单片机、USB 串口芯片和继电器线圈已经在花这笔钱,所以再挂一个 0.4 A 的负载,剩给其他所有东西的就只有一百毫安出头。再往上顶,USB 口自己的过流保护会把这条轨切掉——那就是雾停的同时 Uno 也一起倒下,你的防干烧保护也跟着一起没了。

负载 它要多少电流 可以从哪里供电
雾化模块 标称 300 mA;按 0.4 A 预算(2 W ÷ 5 V) 自己一个 1 A 或以上的 5 V USB 充电器,受继电器控制
继电器线圈(Songle SRD-05VDC-SL-C) 0.36 W ÷ 5 V ≈ 72 mA Uno 的 5 V 轨,经模块自己的三极管
继电器光耦输入端 几个 mA Arduino 数字引脚
HW-038 水位传感器 20 mA 以内 Arduino 数字引脚,只在读数那一瞬间通电

怎么去开关模块自己那一路电?

那块 1 路继电器模块存在的意义,就是把这个问题一分为二。它的 IN 端点亮的是光耦里面的一颗 LED;光穿过封装照到对面的光敏三极管,再由另一侧的三极管从板子自己的 DC+ 轨上把线圈拉起来。所以 Arduino 引脚只出那几毫安的 LED 电流,而 72 mA 的线圈(0.36 W ÷ 5 V)是从 5 V 轨上取电的——而且触点与线圈之间是电气隔离的,这一点这套做法非常需要,因为雾化模块的地属于充电器,不属于 Uno。

那对触点要串进模块的供电里,而最好下手的地方就是那条线。把这条 microUSB 数据线当成消耗品:在中段把外皮划开,找出红色那一根——那就是 +5 V——只剪它一根。两头都剥好皮,充电器那一端拧进 COM,模块那一端拧进 NO。黑线和那对数据线保持连通,继电器一吸合就把 +5 V 这条路接通。这里每一个端子都是螺丝端子,所以整套做下来不用焊一处。

线另一头那个充电器只有一项要求:5 V、1 A 或以上。这块驱动板资料上写明的工作范围是 2.8–6 V,所以 9 V 或 12 V 的适配器并不是同一样东西的加强版——那是直接冲过上限,会把驱动 IC 打死。这个范围在下限那一头同样咬人:电压塌下去板子还是照跑,但驱动幅度跟着电源走,所以一条又细又长的线把模块拉到 4 V 附近,出来的就是一道又弱又断续的雾。先查这个,再去怪那片圆片。

要用 NO,不要用 NC,这样静止状态——Arduino 拔了、程序死了、断电了——就是不出雾。H/L 跳线也拨到 H:Uno 复位时每一支引脚都是高阻输入,所以在高电平触发的设定下,整个启动过程中都没有电流流进光耦 LED,继电器一直保持断开。触点的额定值可以看我们那篇继电器模块教程;蓝色方块上印的 10 A 250 VAC,对一个 0.4 A 的直流活来说是余量,不是邀请。

用什么线
1 A 以上的 USB 充电器,接剪断的红色 +5 V 线 继电器 COM 螺丝端子 数据线自己那根导线
红色 +5 V 线剪口的模块那一端 继电器 NO 螺丝端子 数据线自己那根导线
Uno D8 继电器 IN 螺丝端子 公对公杜邦线,公头针夹进端子里
Uno 5V 继电器 DC+ 螺丝端子 公对公杜邦线
Uno GND 继电器 DC- 螺丝端子 公对公杜邦线
Uno A0 HW-038 的 S 脚 公对母杜邦线
Uno D7 HW-038 的 + 脚 公对母杜邦线
Uno GND HW-038 的 – 脚 公对母杜邦线
换能器 JST 插头 驱动板 CN1 插座 随附引线,方向只有一种

这套东西由两路电源在跑,而它们从头到尾不碰面:雾化模块经那条剪开的线从自己的充电器取电,Uno 则继续用它自己那条 USB 线接电脑或另一个充电器口。上面没有任何一行把充电器的负极接到 Uno 的 GND,这个缺口是故意留的——你选光耦继电器买到的就是这份隔离。

卡通供电路径图:一个白色 USB 充电器,一条黑色数据线的红色导线被剪断并拧进红色继电器板上的蓝色端子,板上有一颗蓝色继电器方块,线继续接到一块绿色驱动板,旁边一块蓝色小 Arduino 接到继电器另一侧的端子排
继电器触点串在充电器与模块之间、数据线红色 +5 V 那根导线里;Arduino 从头到尾只碰隔离开的控制侧。

用 MOSFET 也行,只是它断的是负极那一条——细节看常见问题和我们那篇 IRF520 模块教程

怎样才能让雾化片永远不干烧?

HW-038 水位传感器不是浮球开关。它那十根裸露的银色手指是两把交错的梳子,水把它们桥接起来,本质上就是一个电阻:探片插得越深,并联的导电路径越多,这个电阻就越低。一颗三极管把这个变化转成电压,于是 A0 读到的是一个随深度上升的数值,量程就是探片那 40 mm 的感应区——这是一个相对读数,不是毫米,所以必须在你自己的容器里校准。

因为它是靠往水里灌电流来感应的,长期通电会把自己的电极电解掉,裸露的走线几天之内就会腐蚀。改成用数字引脚给它供电:20 mA 以内刚好落在 Uno 每脚的建议值上——没有余量,但也没有超——而程序每次读数只把那支引脚拉高十毫秒。

探片摆在哪里,决定了前面这一切是否真的有用。它最下面那根手指必须高于棉芯够不着水的那个水位,这样切断发生的时候雾化片还是湿的。把阈值设在“杯子空了”那个位置,跟没装传感器是一样的。

先校准:把探片放在空气里打印一次数值,再放到你会用到的最低水位打印一次,然后把 TOO_DRY 设在略低于后者,把 WET_ENOUGH 设得明显高一些。这个间隔是刻意留的——没有它,雾就会在同一个临界值附近来回抖。我们那篇水位监测教程自动浇花系统用的是同一个套路。

程序还多做了一件事,而这一件正是“大多数时候有用的保护”和“你敢依赖的保护”之间的分界:它在相信传感器之前,先检查传感器还在不在。一根信号线松掉,会不声不响地把整套设计废掉,因为一支断开的 A0 读到的并不是低值——它是一支悬空输入,还留着上一次转换的电荷,所以它完全可能停在湿的阈值之上,让雾在空水杯上继续跑。用引脚给传感器供电,顺手就买到了一个免费的自检:在给 D7 通电之前先读一次 A0。接好的传感器只可能把这条线往下拉,所以读数只要明显高于一点残留,就说明它不在,程序就拒绝出雾。

/*
  带防干烧断电的雾化片控制 - Arduino Uno
  Uno 从来不给雾化模块供电。它只是闭合一对继电器触点,
  而这对触点串在模块自己那条充电线的 +5V 导线里。

  D8  -> 继电器 IN  (H/L 跳线放 H,所以 HIGH = 触点闭合 = 出雾)
  D7  -> HW-038 的 "+"(传感器只在读数那一瞬间通电)
  A0  <- HW-038 的 "S"
  GND -> HW-038 的 "-" 和继电器 DC-,5V -> 继电器 DC+
*/

const uint8_t RELAY_PIN  = 8;
const uint8_t SENSOR_PWR = 7;
const uint8_t SENSOR_SIG = A0;

// 这两个值要在“你自己的”容器上校准:先在手指全干时打印原始读数,
// 再把水放到雾化片还能安全工作的最低水位打印一次。
const int TOO_DRY     = 260;  // 低于这个值,立刻切掉雾
const int WET_ENOUGH  = 320;  // 高于这个值,才可以重新开始

// SENSOR_PWR 为低电平时,接好的传感器只可能把 A0 往下拉。传感器没通电
// 却读到高于这个值,说明 S 线掉了、输入正在悬空 -
// 读数不可信的时候,绝不出雾。
const int UNPOWERED_MAX = 100;

const unsigned long MIN_OFF_MS  = 60000UL;  // 干切之后的静置时间
const unsigned long READ_EVERY  = 1000UL;

bool misting = false;
unsigned long lastOff = 0;
unsigned long lastRead = 0;

int readLevel() {
  analogRead(SENSOR_SIG);           // 先把上一次的残留样本冲掉
  if (analogRead(SENSOR_SIG) > UNPOWERED_MAX) {
    return -1;                      // 传感器没接上或接错了
  }
  digitalWrite(SENSOR_PWR, HIGH);   // 给电极通电
  delay(10);                        // 等分压稳定下来
  analogRead(SENSOR_SIG);           // 第一次转换丢掉不要
  int value = analogRead(SENSOR_SIG);
  digitalWrite(SENSOR_PWR, LOW);    // 再把电极断电
  return value;
}

void setup() {
  pinMode(RELAY_PIN, OUTPUT);
  digitalWrite(RELAY_PIN, LOW);     // 任何事情发生之前,先确保雾是关的
  pinMode(SENSOR_PWR, OUTPUT);
  digitalWrite(SENSOR_PWR, LOW);
  Serial.begin(9600);
  Serial.println(F("mist guard ready"));
  lastOff = millis();
}

void loop() {
  if (millis() - lastRead < READ_EVERY) {
    return;
  }
  lastRead = millis();

  int level = readLevel();
  if (level < 0) {
    Serial.println(F("sensor not answering - mist stays OFF"));
  } else {
    Serial.print(F("level = "));
    Serial.println(level);
  }

  if (misting && level < TOO_DRY) {
    digitalWrite(RELAY_PIN, LOW);
    misting = false;
    lastOff = millis();
    Serial.println(F("water low - mist OFF"));
  } else if (!misting && level > WET_ENOUGH &&
             millis() - lastOff > MIN_OFF_MS) {
    digitalWrite(RELAY_PIN, HIGH);
    misting = true;
    Serial.println(F("water back - mist ON"));
  }
}

这段编译出来是 2,694 字节,占 Uno flash 的百分之八。注意 setup() 第一件事做的是什么:它把继电器引脚拉低,所以在传感器被读过一次之前,雾根本起不来。MIN_OFF_MS 接着让它在任何一次干切之后先停一分钟,这样一个波纹或者一次溅水,就不会在水刚碰到阈值的那一刻把一片还烫着的圆片重新点着——而且因为 setup() 也把这个计时器一起启动了,所以上电后的第一分钟同样是安静的。开头那一段停顿是设计出来的,不是故障。

卡通图:一只装水的玻璃杯,杯里立着一片红色的 HW-038 传感器探片,杯口架着一个黑色外壳,里面是雾化片和一根白色棉芯,雾正在往上升,旁边接着一块蓝色小 Arduino、一块红色继电器板和一块绿色驱动板
装好之后的样子:棉芯垂进水里,圆片架在杯口,传感器探片的位置要保证它在雾化片还湿着的时候就把电切掉。

我们常看到的错误做法

把圆片的红黑两根线直接接到 5 V 直流上。换能器不是直流负载——它要的是 108 kHz 的交流驱动,而这正是驱动板存在的全部意义。接直流它什么也不会做,然后就被当成一片坏掉的圆片。

“就试几秒看它会不会动”地干烧一下。这种测试没有一个安全的简版。先把棉芯沾湿,或者把圆片浮在一个小碟子上,再通电。

让棉芯的下端停在水面之上。棉芯只有在下端泡在水里的时候才吸得上水,所以在水箱看起来还远没空的时候,它就已经干了。

为了“确保它一直是湿的”而把圆片整片沉进水里。这一类是从湿的那一面往开放空气里雾化的——水在下面,雾从上面出。把它沉下去,得到的是气泡和一阵闷响,而不是雾柱;棉芯存在的意义,正是让圆片留在水面之上,而让水自己爬上来找它。

把电路板摆在敞开的雾柱旁边。飘不走的雾会凝在最近的东西上,而继电器板或传感器排针上那一层水膜,就是一套第一天好好的装置到了第二个星期开始读数发怪的原因。

常见问题

可以直接用 Arduino 引脚控制超声波雾化模块吗?

不行。模块标的是 5 V、300 mA、2 W,而设计时要按这些标称推出来的较大那个值走:2 W ÷ 5 V = 0.4 A,大约是 Uno 引脚建议值 20 mA 的二十倍。要做的是去开关它的供电:把继电器触点或 MOSFET 串进它自己充电器的 5 V 线里,引脚只负责驱动继电器的光耦输入端。

为什么我的雾化片跑了几分钟就不出雾了?

最有可能是干烧过。水既是工作介质,又是机械负载,还是那圈陶瓷唯一的散热途径,所以水一没,驱动能量就变成热,而压电材料热到一定程度就会退极化,冷下来也不会恢复。通常不是水箱真的空了,而是水位下降之后棉芯先失去了接触。

水位传感器一定要装吗,还是模块自己会停?

要装。这一类驱动板拆开来看到的是一个开环振荡器,完全不从雾化片取反馈,所以板子分不出干湿;它资料里写的唯一一项措施是四小时或八小时后的定时自动关机,那是一个计时器,不是水位传感器。真正危险的是半湿的情况:雾变薄但不会停,干掉的那一块在过热。像 HW-038 这样的电阻式传感器给出的答案不含糊。

一片模块能出多少雾,够不够给一个房间加湿?

这一类雾化片的标称大约是每小时 50 ml 水——全开一天约 1.2 公升。这个量属于桌面、雨林缸、摆件和柜子的范围,不是卧室的范围;一台房间加湿器的出雾量是它的好几倍。想做一台真正有输出的定制加湿器,就要并几片,而且每一片都要配自己的驱动板——驱动板的振荡器和输出级带的是 2 W、300 mA 这个刚好够一片换能器的预算,所以在同一个输出上再挂一片,只会把驱动分成两半,两片都雾不好。

DIY 超声波加湿器可以用自来水吗?

能用,但代价是雾化片的寿命,还有落在家具上的一层灰。水里溶的所有东西,会在每一颗液滴蒸发之后留下来:在几微米宽的孔里,那叫水垢;在房间里,那叫细细的白色粉尘。用蒸馏水两样都能避掉,另外精油也别加——油不会从雾化片上蒸发掉,它只会把孔堵死。

可以用 MOSFET 代替继电器来开关雾化模块吗?

可以,而且更安静、没有触点会磨损,但有两件事会变。低边 MOSFET 模块断的是负极那一条而不是正极,所以那条消耗品数据线你要剪的是黑线,不是红线。另外 IRF520 不是逻辑电平管:5 V 栅极只能让它半开,3.3 V 栅极几乎开不了,表现出来就是发热,而不是一次干净的开关。

最后更新:2026 年 8 月。有问题?WhatsApp 联系我们

Leave a Reply

Your email address will not be published. Required fields are marked *