Мокрые ботинки после лужи — та бытовая мелочь, из которой я собрал первый по-настоящему полезный прибор. Готовые сушилки с таймером мне долго не нравились одной деталью: они гонят тэн отведённые три часа, даже когда обувь высохла за сорок минут. Сушка по часам — как полив по будильнику: работает, пока не спросишь, а что на самом деле в коробке. Датчик DHT11 внутри закрытой коробки отвечает на этот вопрос точно, и реле с ним включает тэн не по расписанию, а по факту: высохло — тэн замолчал, не высохло — работает дальше.
Первую версию я обжёг в первый же день: контакт датчика отошёл, чтение сорвалось, а реле осталось включённым до утра. Коробка и тэн тогда выдержали, но осадок остался — с тех пор в моих сушилках три обязательных слоя: гистерезис по влажности, лимит непрерывной работы на millis() и тумблер-мастер, который обесточивает логику одним щелчком. Логику гистерезиса мы разбирали в уроке про термостат, силовую часть с сетью — в уроке про релейный модуль; здесь я собираю из них бытовой прибор и добавляю два предохранителя, которых в комнатном термостате не было.
Окно 65/55: почему десять процентов
Правило сушилки звучит так: влажность в коробке выше 65 % — тэн работает, ниже 55 % — выключается, а в коридоре между ними реле держит последнее решение. Порог 65 % выбран не с потолка: в закрытой коробке ниже 60 % обувь почти не сохнет, а за 75 % влага уже не выходит наружу, а оседает на стенках. Окно в десять процентов — вдвое шире термостатного окна в один градус, и на то три причины: погрешность DHT11 по влажности — ±5 %, и коридор меньше этой цифры заставил бы реле щёлкать на шуме показаний; обувь отдаёт влагу десятками минут, сушка инерционна, и частые переключения ей ничего не дают; тэн осушает воздух у себя за минуту, а датчик за перегородкой замечает это позже — узкое окно ловило бы обе точки в разное время.
Проверено на своей коробке: с окном в пять процентов реле щёлкало каждые четыре-семь минут и за вечер накручивало сотню переключений, с окном в десять — раз в полчаса, и счётчик щелчков из урока про реле и гистерезис перестал расти на глазах. Механика та же, что у термостата, только шире: чем грубее датчик и инертнее система, тем шире коридор. Для кожаной обуви я вообще подгибаю пороги вниз до 60/50 — кожа пересушку переносит хуже резины, и сапоги лучше вынимать чуть недосушенными.
| Управление сушкой | Как ведёт себя тэн | Слабое место |
|---|---|---|
| Таймер на три часа | греет ровно отведённое время | сушит всухую уже сухую обувь: кожа трескается, электричество уходит в пол |
| Влажность без страховки | выключается по факту, тэн не работает зря | датчик отошёл — реле греет бесконечно; мой первый день с этим прибором |
| Влажность плюс лимит два часа | работает по факту, но не дольше двух часов подряд | на десять строк кода больше — самая дешёвая страховка в проекте |
Страховка на два часа и тумблер-мастер
Лимит непрерывной работы — два часа, и это не случайная цифра: кеды после лужи просыхают при тэне 30-50 Вт в закрытой коробке за полтора-два часа. Если за два часа влажность не упала ниже порога — что-то сломалось: отошёл провод датчика, перегорел тэн, дверцу забыли прикрыть. Греть дальше бессмысленно, а с сетевыми контактами ещё и опасно, поэтому скетч не просто выключает реле, а ставит флаг blocked: повторный пуск теперь возможен только через человека, который передёрнет тумблер. Тот же приём со счётчиком застрявшего нагревателя мы видели в инкубаторе — разница в том, что там счёт шёл чтениями, здесь считает millis() в миллисекундах, и лимит наступает честно через 7200000 мс.
Тумблер на пине D3 — мастер-выключатель, и его роль шире, чем «включить-выключить»: это единственный выход из блокировки. Реле щёлкнуло по лимиту — щёлкните тумблером вниз и вверх, скетч сбросит флаг и начнёт заново. Это и не кнопка, требующая антидребезга: тумблер держит положение сам, и опрашивать его можно каждый проход loop() без обработки фронта — ровно по той причине, по которой delay() выкорчёвывался в уроке про millis: пока скетч спит, ни тумблер, ни датчик для него не существуют.
#include "DHT.h"// DHT11 на пине 2, реле тэна на пине 7, тумблер на пине 3DHT dht(2, DHT11); #define RELAY 7#define TOG 3#define H_ON 65.0#define H_OFF 55.0const unsigned long LIMIT_ON = 7200000UL; // два часа непрерывно bool heat = false;bool blocked = false;unsigned long tOn = 0;unsigned long lastRead = 0; void setup() { Serial.begin(9600); pinMode(RELAY, OUTPUT); pinMode(TOG, INPUT); digitalWrite(RELAY, LOW); dht.begin(); Serial.println("sushilka: on>65 off<55 limit=2h");} void loop() { unsigned long now = millis(); if (now - lastRead >= 1000UL) { // DHT11 отвечает раз в секунду lastRead = now; bool on = digitalRead(TOG) == HIGH; if (!on) { // тумблер вниз: мастер-выключатель if (blocked) Serial.println("reset: gotova k rabote"); blocked = false; heat = false; } else if (!blocked) { // после лимита ждём человека float h = dht.readHumidity(); if (h < 0.0 || h > 100.0) { Serial.println("err: sensor"); // сорванное чтение — решение не меняем } else { if (!heat && h > H_ON) { heat = true; tOn = now; Serial.println("start: sushka"); } else if (heat && h < H_OFF) { heat = false; Serial.println("stop: suho"); } else if (heat && now - tOn >= LIMIT_ON) { heat = false; blocked = true; Serial.println("limit: off, perekluchi tumbler"); } Serial.print("h="); Serial.print(h, 0); Serial.print(" heat="); Serial.println(heat ? 1 : 0); } } } digitalWrite(RELAY, heat ? HIGH : LOW);}Пройдём по трём решениям, на которых держится прибор. Первое — «сорванное чтение не меняет ничего»: если h вышло за физические границы 0-100 %, скетч печатает err и не трогает реле. Один сбой не выключит сушку и не включит её заново — решение принимает только подтверждённое показание. Второе — лимит сравнивает не «время с запуска», а «время с момента включения реле»: tOn записывается в момент старта, и два часа считаются только для непрерывного нагрева; выключился-включился — счёт начался заново. Третье — blocked сильнее любых показаний датчика: даже при влажности за 90 тэн останется выключенным до передёргивания тумблера, потому что лимит — это диагноз аварии, а не режим работы.
И заметьте, где нет delay(): опрос раз в секунду держится на паре переменных lastRead и millis(), тумблер живой между чтениями, реле переключается в тот же проход loop(). Интервал именно в секунду выбран не для экономии — у DHT11 период преобразования около секунды, и чаще его спрашивать значит читать пустую линию, что подробно разобрано в уроке про интервал опроса. Хотите добавить пищалку «сушка окончена» или счётчик минут нагрева — loop свободен и примет их без переделки.
В реальной коробке разница с симулятором одна: ползунок влажности двигает ваша обувь. Датчик ставьте у входа коробки, а тэн — в дальний угол за жестяной перегородкой. Причина измеряется документацией: DHT11 рассчитан до 50 °C, а коридор вокруг нагревателя локально прогревается до 60-70 — датчик там сначала наврёт, потом поплывёт по показаниям, а через сезон просто умрёт; его распиновка и характер описаны в уроке про подключение. Жесть между тэном и сенсором стоит копейки, и датчик за ней живёт годами.
Второй нюанс — герметичность. Парадокс сушилки: в полностью закрытом ящике воздух быстро насытится влагой, сушка упрётся в 75-80 % и застынет — влага перестанет выходить из обуви. Достаточно двух-трёх отверстий по 5-7 мм на противоположных стенках: тёплый влажный воздух уходит вверх, датчик видит честную картину, и порог выключения наступает сам, а не по лимиту.
- Гистерезис 65/55 % — окно вдвое шире термостатного: погрешность DHT11 ±5 % и инерция обуви требуют коридора, а не линии
- Лимит 7200000UL (два часа) на millis(): непрерывный нагрев дольше двух часов — признак аварии, а не режима сушки
- Флаг blocked после лимита: повторный пуск только передёргиванием тумблера — выход из аварии всегда через человека
- Сорванное чтение (h вне 0-100) не меняет состояние реле — решение принимает только подтверждённое показание
- Тэн за жестяной перегородкой от датчика: DHT11 документирован до 50 °C, у нагревателя локально 60-70
- 1. Почему окно гистерезиса сушилки сделано в 10 %, а не в 2 %?
- 2. Что произойдёт после срабатывания лимита в два часа?
- 3. Провод датчика оторвался посреди сушки. Что выключит тэн на реальной плате?
- 4. Почему опрос датчика стоит раз в секунду, а не в каждом проходе loop()?
- 5. Влажность в коробке 62 %. Что делает скетч?
Частые вопросы по теме урока
- Почему окно гистерезиса сушилки сделано в 10 %, а не в 2 %?
- Окно должно быть шире погрешности датчика и инерции сушки: при ±5 % у DHT11 коридор в 2 % означал бы щелчки реле на шуме — у меня так и было с окном в 5 %. погрешность DHT11 по влажности ±5 %: узкое окно ловит шум показаний, а не обувь
- Что произойдёт после срабатывания лимита в два часа?
- Флаг blocked запрещает автоматический пуск: лимит означает аварию, и выход из неё — действие человека. Тумблер вниз-вверх снимает блокировку. реле выключится, а повторный пуск заблокируется до передёргивания тумблера
- Провод датчика оторвался посреди сушки. Что выключит тэн на реальной плате?
- Сорванное чтение состояние реле не меняет: тэн греет дальше, и единственная автоматическая страховка — лимит непрерывной работы. Отсюда и правило «уходя — выключай». миллисекундный лимит — максимум через два часа непрерывной работы
- Почему опрос датчика стоит раз в секунду, а не в каждом проходе loop()?
- У DHT11 период преобразования около секунды: чаще спрашивать — значит ловить пустую линию и nan. Интервал опроса разобран в отдельном уроке раздела. DHT11 не успевает измерять чаще раза в секунду — чтения срываются
- Влажность в коробке 62 %. Что делает скетч?
- 62 % лежит в мёртвой зоне между порогами: если реле было включено, оно продолжает работать, если выключено — ждёт. Коридор и есть гистерезис. держит последнее решение: 62 внутри коридора 55-65