Датчик уровня воды для Arduino: калибровка, сигнализация перелива и насос
Как подключить датчик уровня воды к Arduino: калибровка «пусто/половина/полно», питание от пина против коррозии, сигнализация перелива с зуммером, управление насосом и код для ESP32/Pico.
Датчик уровня воды — самый дешёвый и простой способ узнать с помощью Arduino, насколько высоко поднялась вода в стакане, аквариуме, поддоне цветочного горшка или небольшом баке. Когда открытые токопроводящие дорожки на плате погружаются в воду, напряжение на аналоговом выходе растёт; Arduino считывает это напряжение через analogRead() и решает, где вода: «пусто», «половина» или «полно». Датчик подключается тремя проводами, работает с несколькими строками кода и служит основой для многих проектов — от сигнализации перелива до автоматического управления насосом.
В этом руководстве разберёмся, что внутри модуля, почему показание никогда не доходит до 1023, как провести калибровку «пусто/половина/полно» и как предотвратить коррозию, которая съедает датчик за несколько недель. Затем соберём сигнализацию перелива с зуммером и управление насосом, которое автоматически доливает бак, коротко сравним датчик с поплавковым датчиком уровня и бесконтактным XKC-Y25 и, наконец, посмотрим, как сделать то же самое на ESP32 и Raspberry Pi Pico.

Что такое датчик уровня воды и как он работает?
На нижней части модуля расположены десять токопроводящих дорожек, которые не касаются друг друга и входят одна в другую, как зубья двух гребёнок. Пять из них — силовые дорожки, соединённые с питанием +; остальные пять — измерительные, они идут к базе NPN-транзистора S8050 в верхней части платы. Пока плата сухая, между дорожками только воздух, транзистор закрыт, и на пине S около 0 V. Как только плата попадает в воду, вода соединяет силовые и измерительные дорожки; в базу транзистора течёт небольшой ток, транзистор начинает открываться, и напряжение на выходе S, снимаемое с эмиттера, растёт. Чем выше вода, тем длиннее смоченный участок дорожек, тем меньше сопротивление между ними и тем выше выходное напряжение.
У такого принципа работы три важных следствия. Во-первых, датчик на самом деле измеряет не воду, а проводимость воды: растворённые в водопроводной воде минералы повышают показания, а чистая (дистиллированная) вода почти ничего не даёт. Во-вторых, поскольку выход снимается с транзистора, работающего как эмиттерный повторитель, напряжение никогда не достигает напряжения питания; полностью мокрый датчик с питанием 5 V на Arduino Uno обычно показывает около 500–650 и даже не приближается к 1023. В-третьих, зависимость нелинейная: на первых нескольких миллиметрах значение быстро растёт, а затем замедляется всё сильнее. Поэтому этот датчик — не линейка с миллиметровой точностью, а практичный индикатор, который надёжно различает несколько уровней.
| Параметр | Значение |
|---|---|
| Рабочее напряжение | 3,3–5 V DC |
| Рабочий ток | Меньше 20 mA (максимум — когда датчик полностью мокрый) |
| Выход | Аналоговое напряжение (пин S), растёт вместе с уровнем воды |
| Зона измерения | Примерно 40 × 16 мм, то есть не больше примерно 4 см высоты воды |
| Размер платы | Примерно 62 × 20 мм |
| Рабочая температура | 10–30 °C (данные производителя) |
| Пины | S (сигнал), + (VCC), − (GND) |
Подключение датчика уровня воды: Arduino Uno, ESP32 и Pico
| Пин датчика | Arduino Uno | ESP32 | Raspberry Pi Pico |
|---|---|---|---|
| S (сигнал) | A0 | GPIO 34 (ADC1) | GP26 (ADC0) |
| + (VCC) | D7 (питание только во время измерения) | GPIO 25 | GP15 |
| − (GND) | GND | GND | GND |
Проще всего предотвратить коррозию, питая датчик от цифрового пина, как показано в таблице: код подаёт на пин HIGH прямо перед измерением, ждёт 10 мс, считывает значение и снова переводит пин в LOW. В системе, которая измеряет раз в секунду, дорожки находятся под напряжением всего 1% времени, а это замедляет износ примерно в сто раз. Полностью мокрый модуль потребляет не больше примерно 20 mA. Рекомендуемый предел для пина Arduino Uno — 20 mA, абсолютный максимум — 40 mA, а пин включён всего несколько миллисекунд, так что такое подключение безопасно; пины ESP32 тоже легко отдают этот ток. А вот пины Pico по умолчанию работают с меньшей нагрузочной способностью, поэтому при полностью мокром датчике напряжение на пине немного проседает и показания становятся меньше. Если калибровка сделана с тем же подключением, это не проблема; если нужны более стабильные значения, + датчика можно коммутировать небольшим PNP-транзистором вроде BC557: эмиттер — к пину 3V3 платы, коллектор — к + датчика, база — к пину GPIO через резистор 1 kΩ; тогда датчик включается, когда на пине LOW. Подобрать подходящий транзистор поможет утилита распиновки транзисторов.
Шаг за шагом: первое измерение с Arduino
- Подключи пин S датчика к A0, пин + к D7, а пин − к GND. Держи плату вертикально, дорожками вниз.
- Открой код ниже в Arduino IDE, выбери плату Arduino Uno и правильный порт, затем загрузи код.
- Открой монитор порта и выставь скорость 9600 бод. Убедись, что у сухого датчика значение близко к 0.
- Медленно опускай датчик в стакан с водой: сначала только кончик, потом наполовину, потом до линии, где заканчиваются дорожки. На каждом шаге подожди несколько секунд и запиши значение.
1const int SENSOR_PIN = A0; // S → A0
2const int POWER_PIN = 7; // + → D7 (yalnızca ölçerken besle / power only while measuring)
3
4int readSensor() {
5 digitalWrite(POWER_PIN, HIGH); // sensörü aç / power the sensor
6 delay(10); // değerin oturmasını bekle / let the reading settle
7 long sum = 0;
8 for (int i = 0; i < 8; i++) { // 8 ölçümün ortalaması / average of 8 readings
9 sum += analogRead(SENSOR_PIN);
10 }
11 digitalWrite(POWER_PIN, LOW); // sensörü kapat / power off
12 return sum / 8;
13}
14
15void setup() {
16 pinMode(POWER_PIN, OUTPUT);
17 digitalWrite(POWER_PIN, LOW); // kapalı başla / start powered off
18 Serial.begin(9600);
19}
20
21void loop() {
22 int raw = readSensor();
23 Serial.print("Ham deger / Raw value: ");
24 Serial.println(raw);
25 delay(1000); // saniyede bir ölç / measure once a second
26}Функция readSensor() держит датчик включённым всего около 11 мс на одно измерение. Ожидание 10 мс даёт транзистору и воде между дорожками выйти на стабильное значение; затем среднее из 8 измерений сглаживает мелкие колебания отдельных отсчётов. На Uno каждый вызов analogRead() занимает около 0,1 мс, так что 8 измерений укладываются меньше чем в 1 мс. Если помешать воду или покачать стакан, значения в мониторе порта начнут прыгать; это нормально, потому что колеблющаяся поверхность всё время меняет смоченную длину дорожек.
Пусто, половина, полно: как откалибровать
Не бери пороги из найденного в интернете кода как есть: у каждого датчика, каждой воды и каждого напряжения питания свои значения. Калибруй в той ёмкости, где датчик действительно будет работать, и с той же водой: для аквариума — аквариумной, для бака полива с удобрениями — водой с удобрениями. Нанеси маркером на датчик линии на 0, 10, 20, 30 и 40 мм, погружай плату до каждой линии, жди 3–4 секунды, пока значение установится, и записывай число из монитора порта. В таблице ниже типичные диапазоны для водопроводной воды и питания 5 V; запиши свои значения рядом.
| Уровень | Глубина погружения | Типичное значение на Uno (5 V, водопроводная вода) |
|---|---|---|
| Пусто | 0 мм (датчик сухой) | 0–20 |
| Мало | Примерно 5–10 мм | 250–400 |
| Половина | Примерно 20 мм | 400–480 |
| Полно | Примерно 40 мм (линия, где заканчиваются дорожки) | 480–650 |
В таблице бросается в глаза, как быстро значения растут на первом сантиметре, а потом сжимаются: между 0 и 10 мм разница может составлять несколько сотен единиц, а между 20 и 40 мм — лишь несколько десятков. Поэтому вместо одной прямой через map() гораздо точнее работает кусочно-линейная интерполяция, где между каждой парой точек измерения используется своя пропорция. Код ниже хранит пять точек твоих измерений в двух массивах, переводит сырое значение в миллиметры и выводит уровень словом. Нужно лишь записать свои показания в массив RAW по возрастанию.
1const int SENSOR_PIN = A0;
2const int POWER_PIN = 7;
3
4// Kendi kalibrasyon ölçümlerin / your own calibration readings
5const int N = 5;
6const int RAW[N] = {0, 330, 440, 490, 520}; // ham değer, küçükten büyüğe / raw value, ascending
7const int MM[N] = {0, 10, 20, 30, 40}; // batma derinliği (mm) / immersion depth (mm)
8
9int readSensor() {
10 digitalWrite(POWER_PIN, HIGH);
11 delay(10);
12 long sum = 0;
13 for (int i = 0; i < 8; i++) sum += analogRead(SENSOR_PIN);
14 digitalWrite(POWER_PIN, LOW);
15 return sum / 8;
16}
17
18int rawToMm(int raw) {
19 if (raw <= RAW[0]) return MM[0];
20 for (int i = 1; i < N; i++) {
21 if (raw <= RAW[i]) { // iki nokta arasında oran kur / interpolate between two points
22 return map(raw, RAW[i - 1], RAW[i], MM[i - 1], MM[i]);
23 }
24 }
25 return MM[N - 1]; // en üst noktanın üstü / above the top point
26}
27
28const char* levelName(int mm) {
29 if (mm < 3) return "Bos / Empty";
30 if (mm < 15) return "Az / Low";
31 if (mm < 30) return "Yarim / Half";
32 return "Dolu / Full";
33}
34
35void setup() {
36 pinMode(POWER_PIN, OUTPUT);
37 digitalWrite(POWER_PIN, LOW);
38 Serial.begin(9600);
39}
40
41void loop() {
42 int raw = readSensor();
43 int mm = rawToMm(raw);
44 Serial.print(raw);
45 Serial.print(" -> ");
46 Serial.print(mm);
47 Serial.print(" mm, ");
48 Serial.println(levelName(mm));
49 delay(1000);
50}Сигнализация перелива с зуммером
Одна из самых полезных задач для датчика уровня воды — предупреждать о переливе: если положить датчик под стиральную машину или котёл, в поддон цветочного горшка, в поддон для конденсата кондиционера или на край наполняющегося ведра, сигнализация срабатывает, как только вода коснётся его кончика. Для этого достаточно даже уровня «мало» из таблицы калибровки. Код ниже использует активный зуммер и встроенный светодиод Uno; когда значение превышает ALARM_ON, зуммер пищит каждые четверть секунды, а когда значение опускается ниже ALARM_OFF, замолкает. Поскольку для отсчёта времени используется millis(), а не delay(), измерение и зуммер не блокируют друг друга. О видах зуммеров — в статье Что такое зуммер?, а об идее millis() — в статье millis() и delay().
1const int SENSOR_PIN = A0; // S → A0
2const int POWER_PIN = 7; // + → D7
3const int BUZZER_PIN = 8; // aktif buzzer + ucu / active buzzer +
4const int LED_PIN = 13; // Uno'nun dahili LED'i / Uno's built-in LED
5
6const int ALARM_ON = 200; // bu değer ve üstü taşma / at or above: overflow (kendin ölç / measure yours)
7const int ALARM_OFF = 100; // bunun altına inince alarm biter / alarm clears below this
8
9bool alarmActive = false;
10bool buzzerOn = false;
11unsigned long lastRead = 0;
12unsigned long lastBeep = 0;
13
14int readSensor() {
15 digitalWrite(POWER_PIN, HIGH);
16 delay(10);
17 long sum = 0;
18 for (int i = 0; i < 8; i++) sum += analogRead(SENSOR_PIN);
19 digitalWrite(POWER_PIN, LOW);
20 return sum / 8;
21}
22
23void setup() {
24 pinMode(POWER_PIN, OUTPUT);
25 pinMode(BUZZER_PIN, OUTPUT);
26 pinMode(LED_PIN, OUTPUT);
27 digitalWrite(POWER_PIN, LOW);
28 Serial.begin(9600);
29}
30
31void loop() {
32 unsigned long now = millis();
33
34 if (now - lastRead >= 1000) { // saniyede bir ölç / measure once a second
35 lastRead = now;
36 int level = readSensor();
37 if (!alarmActive && level >= ALARM_ON) alarmActive = true; // taşma başladı / overflow started
38 if (alarmActive && level < ALARM_OFF) alarmActive = false; // su çekildi / water receded
39 Serial.print("Seviye / Level: ");
40 Serial.println(level);
41 }
42
43 if (alarmActive) {
44 if (now - lastBeep >= 250) { // 250 ms öt, 250 ms sus / 250 ms on, 250 ms off
45 lastBeep = now;
46 buzzerOn = !buzzerOn;
47 digitalWrite(BUZZER_PIN, buzzerOn ? HIGH : LOW);
48 }
49 } else if (buzzerOn) {
50 buzzerOn = false;
51 digitalWrite(BUZZER_PIN, LOW);
52 }
53 digitalWrite(LED_PIN, alarmActive ? HIGH : LOW);
54}Управление насосом: бак доливается автоматически
Второе классическое применение — автоматический долив, который держит уровень в заданной полосе. Например, можно доливать испаряющуюся из аквариума воду из запасного ведра, держать полной миску с водой для питомца или подпитывать бак теплицы. Логика простая: когда уровень падает ниже START_BELOW, насос включается, а когда доходит до STOP_ABOVE — выключается. Промежуток между этими двумя порогами — это гистерезис, который не даёт насосу постоянно включаться и выключаться. Помни, что зона измерения у датчика всего около 4 см; закрепи плату на такой высоте, чтобы нужная полоса уровня воды попадала в эти 4 см.

Насос потребляет гораздо больше тока, чем может дать пин Arduino, поэтому управляй им через модуль реле или через MOSFET с логическим уровнем управления и обратным (защитным) диодом, питай насос от отдельного источника и соедини GND обоих источников. Подробности — в статьях Что такое модуль реле?, о работе с MOSFET и о мини-насосе для воды. Самая важная часть кода — мера безопасности: если насос проработал весь период MAX_RUN_MS, а уровень так и не дошёл до цели, система блокирует насос и предупреждает короткими прерывистыми сигналами. Мог выскочить шланг, опустеть запасное ведро или сдвинуться датчик; без такой блокировки насос может часами работать всухую или залить всё вокруг.
1const int SENSOR_PIN = A0;
2const int POWER_PIN = 7;
3const int PUMP_PIN = 8; // röle IN / relay IN
4const int BUZZER_PIN = 9; // aktif buzzer / active buzzer
5const bool RELAY_ACTIVE_LOW = true; // çoğu röle modülü LOW ile çeker / most relay modules switch on LOW
6
7const int START_BELOW = 300; // bunun altında doldur / start filling below this (kendin ölç / measure yours)
8const int STOP_ABOVE = 480; // bu değerde dur / stop at this value
9const unsigned long MAX_RUN_MS = 30000; // en uzun çalışma 30 sn / max run time 30 s
10
11bool pumpOn = false;
12bool fault = false;
13unsigned long pumpStart = 0;
14
15int readSensor() {
16 digitalWrite(POWER_PIN, HIGH);
17 delay(10);
18 long sum = 0;
19 for (int i = 0; i < 8; i++) sum += analogRead(SENSOR_PIN);
20 digitalWrite(POWER_PIN, LOW);
21 return sum / 8;
22}
23
24void setPump(bool on) {
25 pumpOn = on;
26 bool pinHigh = RELAY_ACTIVE_LOW ? !on : on;
27 digitalWrite(PUMP_PIN, pinHigh ? HIGH : LOW);
28}
29
30void setup() {
31 setPump(false); // pin çıkış olmadan önce kapalı konuma al / set off before the pin becomes an output
32 pinMode(PUMP_PIN, OUTPUT);
33 pinMode(POWER_PIN, OUTPUT);
34 pinMode(BUZZER_PIN, OUTPUT);
35 digitalWrite(POWER_PIN, LOW);
36 Serial.begin(9600);
37}
38
39void loop() {
40 if (fault) { // arıza: pompa kilitli, kesik kesik öt / fault: pump locked out, beep
41 digitalWrite(BUZZER_PIN, HIGH);
42 delay(200);
43 digitalWrite(BUZZER_PIN, LOW);
44 delay(1800);
45 return; // yeniden başlatmak için reset / press reset to restart
46 }
47
48 int level = readSensor();
49
50 if (!pumpOn && level < START_BELOW) {
51 setPump(true); // seviye düştü, doldur / level low, start filling
52 pumpStart = millis();
53 } else if (pumpOn && level >= STOP_ABOVE) {
54 setPump(false); // istenen seviyeye ulaşıldı / target level reached
55 } else if (pumpOn && millis() - pumpStart > MAX_RUN_MS) {
56 setPump(false); // süre doldu, seviye yükselmedi / timed out, level did not rise
57 fault = true;
58 }
59
60 Serial.print("Seviye / Level: ");
61 Serial.print(level);
62 Serial.println(pumpOn ? " pompa / pump ON" : " pompa / pump OFF");
63 delay(500);
64}Датчик уровня воды, поплавковый датчик или XKC-Y25
| Параметр | Датчик уровня воды (токопроводящие дорожки) | Поплавковый датчик уровня | XKC-Y25 (бесконтактный) |
|---|---|---|---|
| Принцип измерения | Проводимость воды | Плавающий магнит и геркон | Изменение ёмкости за стенкой резервуара |
| Выход | Аналоговый (несколько уровней) | Разомкнутый или замкнутый контакт | Цифровой (жидкость есть или нет) |
| Диапазон измерения | Примерно 0–4 см | Одна точка (высота установки) | Одна точка (высота установки) |
| Контакт с водой | Да, дорожки в воде | Да, корпус в воде | Нет, крепится снаружи резервуара |
| Коррозия | Есть; питание от пина обязательно | Практически нет | Нет |
| Питание | 3,3–5 V | Не нужно (пассивный контакт) | 5–24 V, около 5 mA |
| Лучше всего подходит для | Опытов, сигнализации перелива, небольших ёмкостей | Постоянных баков, защиты насоса | Закрытых пластиковых или стеклянных баков, агрессивных жидкостей |
| Цена | Самый дешёвый | Дешёвый | Дороже остальных |
Поплавковый датчик уровня состоит из стержня с герконом внутри и поплавка с магнитом, который скользит по стержню. Когда вода поднимается, поплавок всплывает, магнит оказывается напротив геркона, и контакт замыкается или размыкается. Если надеть поплавок на стержень наоборот, можно переключаться между нормально разомкнутым (NO) и нормально замкнутым (NC) режимом. Чтобы подключить его к Arduino, соедини один вывод с цифровым пином, другой — с GND и настрой пин как INPUT_PULLUP; поскольку износа от электролиза нет, в постоянных установках он служит гораздо дольше. Контакты небольших моделей обычно рассчитаны примерно на 0,5 A и 10 W, поэтому насосом управляй через реле, а не напрямую. Как работает геркон, читай в статье Геркон.

1const int FLOAT_PIN = 2; // bir kablo D2'ye, diğeri GND'ye / one wire to D2, the other to GND
2
3void setup() {
4 pinMode(FLOAT_PIN, INPUT_PULLUP); // dahili pull-up direnci / internal pull-up resistor
5 Serial.begin(9600);
6}
7
8void loop() {
9 // Kontak kapalıyken pin LOW okunur / the pin reads LOW when the contact is closed
10 if (digitalRead(FLOAT_PIN) == LOW) {
11 Serial.println("Kontak kapali / Contact closed");
12 } else {
13 Serial.println("Kontak acik / Contact open");
14 }
15 delay(500);
16}XKC-Y25 же — ёмкостный датчик, который вообще не касается воды: его приклеивают снаружи пластикового или стеклянного бака, и он определяет, есть ли за стенкой жидкость. По данным производителя он работает от 5–24 V, потребляет около 5 mA, чувствует жидкость сквозь неметаллические стенки толщиной до 13 мм и реагирует примерно за 500 мс. Высокий уровень на его выходе равен напряжению питания, поэтому при подключении XKC-Y25 с питанием 5 V к ESP32 или Pico нужен делитель напряжения (подходящие резисторы рассчитает утилита делителя напряжения). Регулировку чувствительности и модели с разными выходами мы подробно разбираем в статье Бесконтактный датчик уровня XKC-Y25.

Контроль уровня воды с телефона на ESP32
С ESP32 измерение можно вывести на телефон по Wi-Fi. Пин S датчика всегда подключай к пину ADC1 (GPIO 32–39): пины ADC2 нельзя читать, пока включён Wi-Fi. АЦП у ESP32 12-битный, поэтому значения лежат в диапазоне 0–4095, а так как датчик питается от 3,3 V, числа нельзя сравнивать с показаниями Uno; калибровку придётся провести заново. АЦП ESP32 не вполне линеен около 0 V и у верхней границы диапазона, но здесь важна разница между уровнями, а не абсолютное напряжение, так что это не проблема. Код ниже делает измерение каждые две секунды и отдаёт небольшую веб-страницу, которая обновляется каждые пять секунд; её можно открыть с телефона в той же сети.
1#include <WiFi.h>
2#include <WebServer.h>
3
4const char* WIFI_SSID = "WIFI_ADIN"; // ağ adın / your network name
5const char* WIFI_PASS = "WIFI_SIFREN"; // ağ şifren / your network password
6
7const int SENSOR_PIN = 34; // S → GPIO 34 (ADC1, Wi-Fi ile çalışır / works with Wi-Fi)
8const int POWER_PIN = 25; // + → GPIO 25
9const int HALF = 1500; // yarım eşiği / half threshold (kendin ölç / measure yours)
10const int FULL = 2000; // dolu eşiği / full threshold (kendin ölç / measure yours)
11
12WebServer server(80);
13int lastRaw = 0;
14unsigned long lastRead = 0;
15
16int readSensor() {
17 digitalWrite(POWER_PIN, HIGH);
18 delay(10);
19 long sum = 0;
20 for (int i = 0; i < 16; i++) sum += analogRead(SENSOR_PIN); // 0–4095
21 digitalWrite(POWER_PIN, LOW);
22 return sum / 16;
23}
24
25const char* levelName(int raw) {
26 if (raw < 100) return "Bos / Empty";
27 if (raw < HALF) return "Az / Low";
28 if (raw < FULL) return "Yarim / Half";
29 return "Dolu / Full";
30}
31
32void handleRoot() {
33 String html = "<!DOCTYPE html><html><head><meta charset='utf-8'>"
34 "<meta name='viewport' content='width=device-width'>"
35 "<meta http-equiv='refresh' content='5'></head><body>"
36 "<h1>Su seviyesi / Water level</h1><h2>";
37 html += levelName(lastRaw);
38 html += "</h2><p>Ham deger / Raw: ";
39 html += lastRaw;
40 html += "</p></body></html>";
41 server.send(200, "text/html", html);
42}
43
44void setup() {
45 Serial.begin(115200);
46 pinMode(POWER_PIN, OUTPUT);
47 digitalWrite(POWER_PIN, LOW);
48 WiFi.begin(WIFI_SSID, WIFI_PASS);
49 while (WiFi.status() != WL_CONNECTED) { // bağlanana kadar bekle / wait until connected
50 delay(500);
51 Serial.print(".");
52 }
53 Serial.println();
54 Serial.print("Adres / Address: http://");
55 Serial.println(WiFi.localIP());
56 server.on("/", handleRoot);
57 server.begin();
58}
59
60void loop() {
61 server.handleClient();
62 if (millis() - lastRead >= 2000) { // 2 sn'de bir ölç / measure every 2 s
63 lastRead = millis();
64 lastRaw = readSensor();
65 }
66}Перед загрузкой замени WIFI_SSID и WIFI_PASS данными своей сети; ESP32 подключается только к сетям 2,4 GHz. Открой монитор порта на скорости 115200 бод и просто введи показанный адрес в браузер телефона. Если хочется получать уведомление на телефон, когда уровень «полно», то же измерение можно превратить в сообщение способом из статьи Telegram-бот на ESP32.
Сигнализация перелива на Raspberry Pi Pico и MicroPython
На Raspberry Pi Pico для аналоговых измерений используются пины GP26, GP27 и GP28. Функция read_u16() в MicroPython масштабирует 12-битное измерение Pico в диапазон 0–65535, поэтому пороги будут гораздо большими числами, чем на Uno. Код ниже питает датчик от GP15, читает выход S на GP26 и предупреждает о переливе тремя короткими сигналами активного зуммера на GP14. Как и в первом скетче, пороги задай по своим измерениям.
1from machine import ADC, Pin
2import time
3
4sensor = ADC(26) # GP26 (ADC0) → S
5power = Pin(15, Pin.OUT, value=0) # GP15 → sensör + / sensor +
6buzzer = Pin(14, Pin.OUT, value=0) # GP14 → aktif buzzer / active buzzer
7
8ALARM_ON = 20000 # bu değer ve üstü taşma / at or above: overflow (kendin ölç / measure yours)
9ALARM_OFF = 10000 # bunun altında alarm biter / alarm clears below this
10
11def read_level(samples=8):
12 power.value(1)
13 time.sleep_ms(10) # değerin oturmasını bekle / let the reading settle
14 total = 0
15 for _ in range(samples):
16 total += sensor.read_u16() # 0–65535
17 power.value(0)
18 return total // samples
19
20alarm = False
21while True:
22 level = read_level()
23 if not alarm and level >= ALARM_ON:
24 alarm = True
25 elif alarm and level < ALARM_OFF:
26 alarm = False
27 print("Seviye / Level:", level, "ALARM" if alarm else "")
28 if alarm:
29 for _ in range(3): # üç kısa bip / three short beeps
30 buzzer.value(1)
31 time.sleep_ms(150)
32 buzzer.value(0)
33 time.sleep_ms(150)
34 else:
35 time.sleep(1)Идеи проектов с датчиком уровня воды
- Предупреждение о переливе в поддоне горшка: зуммер, который пищит, когда после полива в поддоне скапливается вода; вместе с датчиком влажности почвы получается полноценная система полива.
- Автодолив аквариума: система долива с ограничением по времени, которая восполняет испарившуюся воду из запасного ведра мини-насосом.
- Поилка для питомца: напоминалка, которая зажигает светодиод или через ESP32 отправляет уведомление на телефон, когда воды в миске становится мало.
- Датчик протечки: сигнализация протечки с датчиком, уложенным плашмя на пол под стиральной машиной или котлом либо в подвале.
- Бак умной теплицы: защита, которая следит за уровнем в баке для полива и блокирует насос, когда бак пустеет; легко встраивается в проект умной теплицы.
- Индикатор бочки для дождевой воды: панель, которая показывает уровень «пусто», «половина» или «полно» на LCD-дисплее с I2C; можно добавить и датчик дождя, чтобы поймать момент, когда начинается дождь.
Частые ошибки и как их исправить
| Симптом | Вероятная причина | Решение |
|---|---|---|
| Значение всегда 0, даже в воде | На пин + не подаётся питание (POWER_PIN не переводится в HIGH) или S подключён не к тому пину | Проверь строки pinMode и digitalWrite и то, что S подключён к аналоговому пину |
| Значение случайно скачет даже у сухого датчика | Пин S «висит в воздухе» или не подключён GND | Проверь все три провода; GND должен быть общим |
| Даже при полном погружении не доходит до 1023 | Это нормально: выход снимается с эмиттерного повторителя | Задай пороги по самому высокому значению из своих измерений |
| В чистой воде показаний нет совсем | У дистиллированной или очищенной воды очень низкая проводимость | С такой водой используй XKC-Y25 или поплавковый датчик |
| Значения за несколько недель падают или уплывают | Электролиз и отложения на дорожках | Питай датчик от пина, очищай дорожки мягкой щёткой и при необходимости замени датчик |
| Насос или зуммер постоянно переключается у порога | Используется один порог; колеблющаяся поверхность раскачивает значение | Используй два отдельных порога для включения и выключения (гистерезис) и усредняй показания |
| На ESP32 значение перестаёт читаться после подключения Wi-Fi | Датчик подключён к пину ADC2 | Перенеси S на пин ADC1 в диапазоне GPIO 32–39 |
Датчик уровня воды на одном дешёвом модуле учит аналоговым измерениям, калибровке, гистерезису и реальным проблемам вроде коррозии. Если нужно измерять уровень большого бака сантиметр за сантиметром, можно перейти на ультразвуковое решение, например датчик расстояния HC-SR04. В приложении BlueGrays есть проекты «Умная станция полива» и сигнализации с зуммером с пошаговыми схемами и кодом, и в них легко добавить датчик уровня воды.
Частые вопросы
Как работает датчик уровня воды?
Когда переплетённые токопроводящие дорожки на плате погружаются в воду, вода соединяет их, и в базу транзистора S8050 на плате течёт ток. Чем сильнее открыт транзистор, тем выше напряжение на пине S; Arduino считывает это напряжение через analogRead() и по нему определяет, насколько высоко вода.
Почему датчик уровня воды ржавеет?
Когда через мокрые дорожки всё время течёт постоянный ток, начинается электролиз, и покрытие дорожек, соединённых с +, растворяется. Если питать датчик не от 5V, а от цифрового пина и включать его всего на несколько миллисекунд на каждое измерение, износ резко замедляется, и датчик служит месяцами.
Работает ли датчик уровня воды в дистиллированной воде?
Почти нет. Датчик измеряет проводимость воды, поэтому дистиллированная или очищенная вода без растворённых минералов даёт очень низкие показания. Для такой воды лучше подходят датчики, не зависящие от проводимости, например бесконтактный XKC-Y25 или поплавковый датчик.
Почему показание датчика уровня воды не доходит до 1023?
Выход S снимается с эмиттера транзистора, поэтому напряжение остаётся ниже напряжения питания, а ток базы ограничен сопротивлением воды. На Arduino Uno с питанием 5 V полностью мокрый датчик обычно показывает около 500–650, поэтому задавай пороги по этому максимуму.
Можно ли полностью погружать датчик уровня воды?
Нет. В воду должна погружаться только нижняя часть с токопроводящими дорожками; если намокнет верхняя часть с транзистором, светодиодом и пинами, будет короткое замыкание, и датчик начнёт показывать неверно или выйдет из строя. Если защитить электронику термоклеем или лаком, датчик прослужит дольше.
Как измерить уровень в большом баке с водой?
Этот датчик охватывает лишь диапазон около 4 см, поэтому для больших баков не подходит. Для непрерывного измерения уровня используют водонепроницаемые ультразвуковые датчики вроде JSN-SR04T, установленные в крышке бака, а чтобы следить лишь за несколькими критическими точками, на разной высоте ставят поплавковые датчики.
Что собрать после прочтения
Все проекты
Работа с зуммером
Интересно, как дверной звонок или сигнализация издают звук? Arduino заставляет маленький зуммер пищать через короткие промежутки: пик, пауза, пик, пауза. Ты видишь, как электричество превращается в зв

Измерение освещённости с LDR
Хочешь увидеть яркость своей комнаты в виде числа? LDR — маленькая деталь, реагирующая на свет, — измеряет освещённость вокруг, а Arduino каждые полсекунды выводит значение на экран компьютера. Закрой

Измерение освещённости модулем LDR на ESP32
Наблюдение в мониторе порта в реальном времени за сырым значением ADC модуля LDR и относительным процентом освещённости, вычисленным по опорным значениям темноты и света. Этот процент — не измерение в люксах. Учит логике калибровки модуля. Идеально выполнить его перед проектом 10, потому что он нужен для определения порога.

Умная станция полива
Садовник, который сам поливает растения, чтобы они не засохли, пока ты в отпуске. Датчик влажности почвы измеряет, насколько влажная земля; когда она сохнет, Arduino на несколько секунд включает водян

Чтение геркона
Интересно, что за магнитный выключатель стоит в сигнализации на дверях и окнах? Когда к модулю геркона подносят магнит, крошечный контакт внутри замыкается; Arduino читает его раз в секунду и выводит

Асинхронный веб-сервер на ESP32 (с выводом IP на LCD)
В этом проекте ESP32 превращается в асинхронный веб-сервер, которым можно управлять с телефона или компьютера в той же сети Wi-Fi. Благодаря библиотеке ESPAsyncWebServer сервер может обрабатывать несколько запросов одновременно (в отличие от классического WebServer.h, который блокируется на одном запросе). Открыв IP-адрес ESP32 в браузере, ты нажимаешь кнопки ON/OFF (маршруты /on и /off) и включаешь и выключаешь светодиод на GPIO 5.

Сигнализация движения на ESP32 (PIR + зуммер + светодиод + Telegram)
Умная охранная сигнализация, которая при обнаружении движения PIR-датчиком включает зуммер и светодиод и одновременно сразу отправляет владельцу уведомление в Telegram. В ней есть 30-секундная пауза, ограничивающая частоту повторных тревог; этот механизм не проверяет срабатывания PIR и не устраняет ложные тревоги. Подходит для дома, гаража, склада или мастерской. С ESP32-CAM можно добавить уведомления с фото, а с обычной ESP32 DevKit V1 приходят текстовые.
Другие статьи
Приложение BlueGrays
Собери эту схему шаг за шагом в телефоне
Схема подключения, код и список деталей на одном экране. 200+ проектов на Arduino, ESP32 и Pico готовы к сборке.
Наведи камеру телефона
Наведи камеру на код — откроется магазин приложений на телефоне.
или открыть магазин

