Калибровка датчика влажности почвы на ESP8266: простая программа без EEPROM
При создании системы автоматического полива или любого другого проекта, использующего аналоговый датчик влажности почвы, одна из важнейших задач – правильная калибровка. Датчики имеют разброс параметров, а показания зависят от типа почвы, напряжения питания и даже температуры. Если не откалибровать датчик, вы рискуете либо переливать растения, либо оставлять их без воды.
В этой статье мы разберём простую программу для калибровки, которая работает через последовательный порт (Serial). Она не использует EEPROM – все значения просто выводятся на экран, чтобы вы могли скопировать их в свой основной код. Это идеальный вариант для быстрой настройки перед запуском проекта.
Зачем калибровать датчик?
Аналоговый датчик влажности (например, популярный FC-28 или ёмкостной) выдаёт напряжение, которое ESP8266 преобразует в цифровое значение от 0 до 1023 (10-битный АЦП). В сухой почве значение будет высоким (ближе к 1023), во влажной – низким (ближе к 0). Но точные числа зависят от конкретного датчика и среды. Калибровка позволяет определить:
- значение в воздухе (максимальное, соответствует 0% влажности),
- значение в воде (минимальное, соответствует 100% влажности),
- а также значения в сухой и влажной почве (для более точной настройки).
Полученные числа затем используются в основном коде для пересчёта сырых показаний в проценты влажности.
Как работает программа
Код предельно прост: в setup() выводится меню, а в loop() ожидается ввод команд с клавиатуры. Пользователь может:
- нажать 1 – измерить значение в воздухе,
- 2 – измерить в воде,
- 3 – измерить в сухой почве,
- 4 – измерить во влажной почве,
- s – показать текущие калибровочные значения,
- r – сбросить все значения.
При измерении программа делает 5 последовательных чтений АЦП, усредняет их и сохраняет в соответствующую переменную. Все значения хранятся в оперативной памяти и теряются при перезагрузке – это сделано намеренно, чтобы вы могли легко экспериментировать и записывать нужные цифры в блокнот.
Подготовка к калибровке
- Подключите датчик влажности к пину A0 ESP8266 (или к любому другому аналоговому входу, при необходимости измените
SOIL_PIN). - Загрузите скетч в ESP8266.
- Откройте монитор последовательного порта (115200 бод).
- Убедитесь, что датчик находится в стабильном состоянии перед каждым измерением.
Пошаговая инструкция по калибровке
1. Измерение в воздухе
Нажмите клавишу 1. Программа предложит подготовить датчик (например, подержать его на воздухе, не касаясь почвы и воды) и нажать любую клавишу. После этого будет выполнено 5 измерений, и вы увидите среднее значение. Запишите его как «сухое максимальное».
2. Измерение в воде
Нажмите 2. Погрузите датчик в стакан с чистой водой (до уровня, который он будет находиться в почве) и нажмите любую клавишу. Получите среднее значение – это будет «влажное минимальное».
3. (Опционально) Измерение в сухой и влажной почве
Если вы хотите использовать более точные границы для вашего конкретного типа почвы, нажмите 3 для сухой почвы и 4 для влажной. Для этого подготовьте образцы: полностью сухую землю и хорошо увлажнённую. Поместите датчик в каждый образец, дождитесь стабилизации показаний и выполните измерение.
4. Просмотр результатов
Нажмите s (или S), чтобы увидеть все сохранённые значения. Программа выведет их в удобном формате и подскажет, какие строки #define нужно вставить в ваш основной код:
ДЛЯ ВАШЕГО КОДА ИСПОЛЬЗУЙТЕ:
#define SOIL_DRY 823
#define SOIL_WET 285
Если вы измеряли значения в почве, то в подсказке будут использованы они (при наличии), иначе – значения воздуха и воды.
Интерпретация результатов
В основном коде умного полива вы обычно видите такие строки:
#define SOIL_DRY 820
#define SOIL_WET 300
И затем функцию преобразования:
int readSoil() {
int raw = analogRead(SOIL_PIN);
raw = constrain(raw, SOIL_WET, SOIL_DRY);
return map(raw, SOIL_DRY, SOIL_WET, 0, 100);
}
Подставьте свои числа: SOIL_DRY – значение в сухой среде (обычно воздух), SOIL_WET – значение во влажной среде (вода). После этого readSoil() будет возвращать проценты влажности, где 0% – сухо, 100% – влажно.
Если вы использовали измерения в сухой и влажной почве, подставьте их – это даст более реалистичные проценты именно для вашей почвы.
Почему не используется EEPROM?
В этом скетче мы сознательно отказались от сохранения в EEPROM, чтобы упростить код и не перезаписывать память случайно. Калибровка обычно делается один раз, а результаты просто копируются в основной проект. Такой подход исключает риск «забыть» калибровку при перепрошивке.
Если же вы хотите, чтобы ESP8266 запоминала калибровку после перезагрузки, можно добавить сохранение в EEPROM (например, в отдельном скетче калибровки), но для большинства случаев достаточно записать значения в код.
Возможные сложности
- Датчик выдаёт хаотичные значения – возможно, плохой контакт или питание. Проверьте соединения.
- Значения в воде и воздухе слишком близки – датчик мог выйти из строя или неправильно погружён. Попробуйте другой датчик.
- После погружения в воду датчик долго возвращается к воздушным показаниям – это нормально, нужно дать ему высохнуть или протереть.
- ESP8266 выдаёт 0 или 1023 постоянно – возможно, не подключён датчик или выбран не тот пин.
Заключение
Представленная программа – простой и надёжный инструмент для калибровки аналоговых датчиков влажности. Она позволяет быстро получить числовые значения для сухой и влажной среды, которые затем используются в основном проекте. Отсутствие EEPROM делает код безопасным и лёгким для понимания.
После калибровки вы сможете настроить порог срабатывания полива (например, 40%) и быть уверенными, что система работает корректно. Не забывайте, что со временем датчик может засаливаться или менять характеристики, поэтому рекомендуется проводить калибровку раз в несколько месяцев.
/************************************************************
* ПРОСТАЯ ПРОГРАММА ДЛЯ КАЛИБРОВКИ ДАТЧИКА
* Без использования EEPROM
************************************************************/
#define SOIL_PIN A0
// Глобальные переменные для хранения калибровки
int airValue = 0;
int waterValue = 0;
int drySoilValue = 0;
int wetSoilValue = 0;
void setup() {
Serial.begin(115200);
Serial.println();
Serial.println("========================================");
Serial.println(" ПРОСТАЯ КАЛИБРОВКА ДАТЧИКА");
Serial.println("========================================");
Serial.println();
Serial.println("Нажмите:");
Serial.println("[1] - Измерить в ВОЗДУХЕ");
Serial.println("[2] - Измерить в ВОДЕ");
Serial.println("[3] - Измерить в СУХОЙ почве");
Serial.println("[4] - Измерить во ВЛАЖНОЙ почве");
Serial.println("[s] - Показать текущую калибровку");
Serial.println("[r] - Сбросить все значения");
Serial.println("========================================");
}
void measureAndSave(String state, int* target) {
Serial.println();
Serial.println("Измерение: " + state);
Serial.println("Подготовьте датчик и нажмите любую клавишу...");
while(!Serial.available());
Serial.read();
int measurements[5];
int sum = 0;
for(int i = 0; i < 5; i++) {
measurements[i] = analogRead(SOIL_PIN);
sum += measurements[i];
delay(200);
}
*target = sum / 5;
Serial.println("Среднее значение: " + String(*target));
Serial.println("✓ Сохранено в памяти программы");
}
void showCalibration() {
Serial.println();
Serial.println("=== ТЕКУЩАЯ КАЛИБРОВКА ===");
Serial.println("ВОЗДУХ (0%): " + String(airValue));
Serial.println("ВОДА (100%): " + String(waterValue));
Serial.println("СУХАЯ почва: " + String(drySoilValue));
Serial.println("ВЛАЖНАЯ почва: " + String(wetSoilValue));
Serial.println();
if(airValue > 0 && waterValue > 0) {
Serial.println("ДЛЯ ВАШЕГО КОДА ИСПОЛЬЗУЙТЕ:");
Serial.println("#define SOIL_DRY " + String(airValue));
Serial.println("#define SOIL_WET " + String(waterValue));
Serial.println();
Serial.println("Или для почвы:");
Serial.println("#define SOIL_DRY " + String(drySoilValue > 0 ? drySoilValue : airValue));
Serial.println("#define SOIL_WET " + String(wetSoilValue > 0 ? wetSoilValue : waterValue));
}
Serial.println("==========================");
}
void resetCalibration() {
airValue = 0;
waterValue = 0;
drySoilValue = 0;
wetSoilValue = 0;
Serial.println("Калибровка сброшена");
}
void loop() {
if(Serial.available()) {
char command = Serial.read();
switch(command) {
case '1':
measureAndSave("ВОЗДУХ", &airValue);
break;
case '2':
measureAndSave("ВОДА", &waterValue);
break;
case '3':
measureAndSave("СУХАЯ ПОЧВА", &drySoilValue);
break;
case '4':
measureAndSave("ВЛАЖНАЯ ПОЧВА", &wetSoilValue);
break;
case 's':
case 'S':
showCalibration();
break;
case 'r':
case 'R':
resetCalibration();
break;
default:
Serial.println("Неизвестная команда");
}
Serial.println();
Serial.println("Выберите действие: [1]Воздух [2]Вода [3]Сухая [4]Влажная [s]Показать [r]Сброс");
}
delay(50);
}