Компоненты · 11 мин чтения

Датчик уровня воды для Arduino: калибровка, сигнализация перелива и насос

Как подключить датчик уровня воды к Arduino: калибровка «пусто/половина/полно», питание от пина против коррозии, сигнализация перелива с зуммером, управление насосом и код для ESP32/Pico.

Датчик уровня воды — самый дешёвый и простой способ узнать с помощью Arduino, насколько высоко поднялась вода в стакане, аквариуме, поддоне цветочного горшка или небольшом баке. Когда открытые токопроводящие дорожки на плате погружаются в воду, напряжение на аналоговом выходе растёт; Arduino считывает это напряжение через analogRead() и решает, где вода: «пусто», «половина» или «полно». Датчик подключается тремя проводами, работает с несколькими строками кода и служит основой для многих проектов — от сигнализации перелива до автоматического управления насосом.

В этом руководстве разберёмся, что внутри модуля, почему показание никогда не доходит до 1023, как провести калибровку «пусто/половина/полно» и как предотвратить коррозию, которая съедает датчик за несколько недель. Затем соберём сигнализацию перелива с зуммером и управление насосом, которое автоматически доливает бак, коротко сравним датчик с поплавковым датчиком уровня и бесконтактным XKC-Y25 и, наконец, посмотрим, как сделать то же самое на ESP32 и Raspberry Pi Pico.

Модуль датчика уровня воды для Arduino
Модуль датчика уровня воды: переплетённые токопроводящие дорожки внизу опускаются в воду, а пины S, + и − вверху подключаются к Arduino; электроника всегда должна оставаться сухой.

Что такое датчик уровня воды и как он работает?

На нижней части модуля расположены десять токопроводящих дорожек, которые не касаются друг друга и входят одна в другую, как зубья двух гребёнок. Пять из них — силовые дорожки, соединённые с питанием +; остальные пять — измерительные, они идут к базе 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 UnoESP32Raspberry Pi Pico
S (сигнал)A0GPIO 34 (ADC1)GP26 (ADC0)
+ (VCC)D7 (питание только во время измерения)GPIO 25GP15
− (GND)GNDGNDGND
Не подключай пин + датчика к 5V постоянно. Когда через мокрые дорожки всё время течёт постоянный ток, начинается электролиз: покрытие дорожек, соединённых с +, растворяется, дорожки темнеют, и через несколько недель показания начинают уплывать. Кроме того, в воду можно опускать только нижнюю часть платы с токопроводящими дорожками; если намокнет верхняя часть с транзистором, светодиодом и пинами, будет короткое замыкание.

Проще всего предотвратить коррозию, питая датчик от цифрового пина, как показано в таблице: код подаёт на пин HIGH прямо перед измерением, ждёт 10 мс, считывает значение и снова переводит пин в LOW. В системе, которая измеряет раз в секунду, дорожки находятся под напряжением всего 1% времени, а это замедляет износ примерно в сто раз. Полностью мокрый модуль потребляет не больше примерно 20 mA. Рекомендуемый предел для пина Arduino Uno — 20 mA, абсолютный максимум — 40 mA, а пин включён всего несколько миллисекунд, так что такое подключение безопасно; пины ESP32 тоже легко отдают этот ток. А вот пины Pico по умолчанию работают с меньшей нагрузочной способностью, поэтому при полностью мокром датчике напряжение на пине немного проседает и показания становятся меньше. Если калибровка сделана с тем же подключением, это не проблема; если нужны более стабильные значения, + датчика можно коммутировать небольшим PNP-транзистором вроде BC557: эмиттер — к пину 3V3 платы, коллектор — к + датчика, база — к пину GPIO через резистор 1 kΩ; тогда датчик включается, когда на пине LOW. Подобрать подходящий транзистор поможет утилита распиновки транзисторов.

Шаг за шагом: первое измерение с Arduino

  1. Подключи пин S датчика к A0, пин + к D7, а пин − к GND. Держи плату вертикально, дорожками вниз.
  2. Открой код ниже в Arduino IDE, выбери плату Arduino Uno и правильный порт, затем загрузи код.
  3. Открой монитор порта и выставь скорость 9600 бод. Убедись, что у сухого датчика значение близко к 0.
  4. Медленно опускай датчик в стакан с водой: сначала только кончик, потом наполовину, потом до линии, где заканчиваются дорожки. На каждом шаге подожди несколько секунд и запиши значение.
C++ (Arduino IDE)
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 по возрастанию.

C++ (Arduino IDE)
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}
Когда датчик вынимают из воды, значение не падает до 0 сразу: тонкая плёнка воды и капли между дорожками ещё какое-то время держат показания заметно выше нуля. Поэтому порог «пусто» держи немного выше 0, а для решений «вкл/выкл», например для сигнализации, используй два отдельных порога: один для включения, другой для выключения. Этот приём называется гистерезис, и он не даёт реле или зуммеру щёлкать каждую секунду, пока уровень колеблется у самого порога.

Сигнализация перелива с зуммером

Одна из самых полезных задач для датчика уровня воды — предупреждать о переливе: если положить датчик под стиральную машину или котёл, в поддон цветочного горшка, в поддон для конденсата кондиционера или на край наполняющегося ведра, сигнализация срабатывает, как только вода коснётся его кончика. Для этого достаточно даже уровня «мало» из таблицы калибровки. Код ниже использует активный зуммер и встроенный светодиод Uno; когда значение превышает ALARM_ON, зуммер пищит каждые четверть секунды, а когда значение опускается ниже ALARM_OFF, замолкает. Поскольку для отсчёта времени используется millis(), а не delay(), измерение и зуммер не блокируют друг друга. О видах зуммеров — в статье Что такое зуммер?, а об идее millis() — в статье millis() и delay().

C++ (Arduino IDE)
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 см.

Мини-погружной насос 6 V
Мини-погружной насос на 3–6 V: работает под водой и потребляет около 100–250 mA, поэтому им управляют через реле или MOSFET, а не напрямую с пина Arduino.

Насос потребляет гораздо больше тока, чем может дать пин Arduino, поэтому управляй им через модуль реле или через MOSFET с логическим уровнем управления и обратным (защитным) диодом, питай насос от отдельного источника и соедини GND обоих источников. Подробности — в статьях Что такое модуль реле?, о работе с MOSFET и о мини-насосе для воды. Самая важная часть кода — мера безопасности: если насос проработал весь период MAX_RUN_MS, а уровень так и не дошёл до цели, система блокирует насос и предупреждает короткими прерывистыми сигналами. Мог выскочить шланг, опустеть запасное ведро или сдвинуться датчик; без такой блокировки насос может часами работать всухую или залить всё вокруг.

C++ (Arduino IDE)
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}
Вода и электричество в одном проекте: размещай Arduino, реле и источник питания выше ёмкостей с водой и подальше от них, а места соединения проводов изолируй термоусадочной трубкой или термоклеем. Если нужен насос или электромагнитный клапан на сетевое напряжение 220 V, подключение к сети должен выполнять квалифицированный специалист, а работать нужно на линии с устройством защитного отключения (УЗО). Маленькие погружные насосы быстро перегреваются и выходят из строя, если работают всухую; поплавковый датчик уровня в запасном ведре — хороший второй уровень защиты.

Датчик уровня воды, поплавковый датчик или 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, поэтому насосом управляй через реле, а не напрямую. Как работает геркон, читай в статье Геркон.

Поплавковый датчик уровня воды
Поплавковый датчик: магнитный поплавок поднимается вместе с водой и размыкает или замыкает геркон в стержне.
C++ (Arduino IDE)
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.

Бесконтактный датчик уровня жидкости XKC-Y25
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 и у верхней границы диапазона, но здесь важна разница между уровнями, а не абсолютное напряжение, так что это не проблема. Код ниже делает измерение каждые две секунды и отдаёт небольшую веб-страницу, которая обновляется каждые пять секунд; её можно открыть с телефона в той же сети.

C++ (Arduino IDE)
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. Как и в первом скетче, пороги задай по своим измерениям.

MicroPython
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, установленные в крышке бака, а чтобы следить лишь за несколькими критическими точками, на разной высоте ставят поплавковые датчики.

Все проекты
Работа с зуммером
#13Новичок

Работа с зуммером

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

4.7(89)
161
Измерение освещённости с LDR
#11Новичок

Измерение освещённости с LDR

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

4.6(81)
139
Измерение освещённости модулем LDR на ESP32
#113Новичок

Измерение освещённости модулем LDR на ESP32

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

4.6(36)
55
Умная станция полива
#83Продвинутый
Premium

Умная станция полива

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

5.0(42)
57
Чтение геркона
#37Новичок

Чтение геркона

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

4.4(21)
27
Асинхронный веб-сервер на ESP32 (с выводом IP на LCD)
#129Продвинутый

Асинхронный веб-сервер на ESP32 (с выводом IP на LCD)

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

4.8(16)
26
Сигнализация движения на ESP32 (PIR + зуммер + светодиод + Telegram)
#145Продвинутый
Premium

Сигнализация движения на ESP32 (PIR + зуммер + светодиод + Telegram)

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

0.0(0)
9