Фонарь у моего крыльца включался тумблером в прихожей: щёлкнуть, выйти, зажечь, вернуться в тепло. Каждую зиму я обещал себе автомат — темнеет, значит горит; рассветает, значит гаснет. Голова для автомата уже была готова: ночник на фоторезисторе из урока про ночной светильник включал светодиод, когда освещённость падала ниже порога. Не хватало рук: пяти-вольтовый пин ATmega отдаёт двадцать миллиампер, а лампа накаливания в шестьдесят ватт при 220 вольтах тянет 270 миллиампер, катушка даже маленького реле — 70–90. Пин слабее катушки вчетверо и слабее лампы в тринадцать: прямое подключение не «не рекомендуется», а физически невозможно, и попытка кончается мёртвым портом. Между пином и нагрузкой нужен усилитель, и самый доходчивый усилитель для первого знакомства с сетью — электромагнитное реле на готовом модуле.
Что внутри реле и модуля
Реле — выключатель, который щёлкает электромагнитом. На катушку подают ток — сердечник тянет якорь, контакт перекидывается с одной клеммы на другую; ток исчезает — пружина возвращает якорь обратно. Клеммников три, и их расшифровка экономит вечер с мультиметром: COM — общий провод нагрузки, NO (normally open) — нормально разомкнутый контакт, NC (normally closed) — нормально замкнутый. Без напряжения на катушке лампа, заведённая на NC, горит; заведённая на NO — молчит и зажигается только со сработавшей катушкой. Фонарь я веду на NO: в «нормальном» состоянии, когда Arduino спит или отключён, света нет. Цифра, которую полезно помнить: механический ресурс контактов — порядка ста тысяч переключений. Раз в сутки — это двести семьдесят лет; раз в минуту — семьдесят дней. Отсюда правило: реле щёлкают редко, а «помигать» яркостью им не дают вообще — реле на ШИМ 490 герц из урока про яркость умирает за считаные минуты: якорь не успевает сесть, катушка живёт на пусковом токе.
Транзисторный ключ для реле можно собрать и вручную — резистор к базе, диод против выброса катушки, — но готовый модуль за те же деньги уже содержит всё: транзистор, разгружающий пин, защитный диод и оптопару PC817, отделяющую логику от силовой части. Схема модуля — маленький кроссворд из четырёх элементов, такие схемы мы учились читать в уроке про чтение схем. Подключение выглядит примитивно: VCC — пять вольт, GND — земля, IN — сигнальный пин. Паспорт такого модуля обещает десять ампер на 250 вольт: шестидесятиваттная лампа и близко не подходит к потолку, а вот чайник на два киловатта вешать не стоит — контакты варятся, и для мощностей больше лампы реле ставят на катушку пускателя.
Две грабли модуля: инверсия и ночной щелчок
На инверсии меня поймало само наречие «включить»: я подал на IN HIGH — как учил первый урок со светодиодом, — и реле щёлкнуло выключением. Большинство модулей LOW-активные: катушка срабатывает от нуля, потому что вход втягивает ток через светодиод оптопары, а не отдаёт его, — светодиод оптопары горит, когда пин прижат к земле. Это не брак, а схемотехника, и спорить с ней бессмысленно: логику инвертируют один раз, в константе. Вторая грабля материализовалась ночью: сетевой блок питания моргнул, Arduino перезагрузился, и модуль издал одиночный щелчок — я проснулся. При загрузке пины Uno висят в Hi-Z, вход модуля плавает в воздухе, оптопара приоткрыта, и катушка успевает притянуть якорь, пока скетч добирается до pinMode. Лечение — порядок строк в setup(): сначала pinMode(RELE, OUTPUT), следом digitalWrite(RELE, неактивный уровень), и только потом всё остальное; между этими строками микросекунды, щелчка не будет. И примечание про зоопарк модулей: попадаются и HIGH-активные экземпляры — у моего второго, от другого поставщика, всё было наоборот; константы в таком случае просто меняются местами, скетч не меняется вовсе.
const int RELE = 7; void setup() { Serial.begin(9600); pinMode(RELE, OUTPUT); // digitalWrite здесь нет: пин после pinMode молчит в LOW, // а на LOW-активном модуле это «включено» — лампа горит до первой команды} void loop() { if (Serial.available() > 0) { String cmd = Serial.readStringUntil(10); cmd.trim(); if (cmd == "on") { digitalWrite(RELE, HIGH); // интуиция: HIGH = включено Serial.println("cmd=on lamp=1"); // на моём модуле лампа как раз погасла } else if (cmd == "off") { digitalWrite(RELE, LOW); // и наоборот: лампа загорелась Serial.println("cmd=off lamp=0"); } }}В этом скетче две беды, и обе — про знание, размазанное не там. Инверсия живёт в голове автора, а не в скетче: через месяц я, сам же, «чинил» парктроник с этим модулем и снова писал digitalWrite(RELE, HIGH) со словом «включить». Рабочая версия выносит знание в константы UROVEN_VKL и UROVEN_VYKL — единственное место, где LOW-активность моей железки существует: они прямой родственник kodKomandy() из командного парсера, где сравнение строк собрано в одном месте. А чтение команд из порта — та же механика readStringUntil: строка, trim, сравнение. Прижимка неактивного уровня в setup() первой парой строк закрывает ночной щелчок.
И то, о чём я скажу серьёзно, без юмора. На клеммниках COM/NO/NC живёт сетевое напряжение 220 вольт, и это единственная часть наших уроков, где ошибка стоит здоровья, а не вечера. Монтаж — только при выключенном автомате, проверенном индикаторной отвёрткой. Провода в клеммах — с усилием, без оголённых миллиметров за клеммой. Клеммник — под штатным колпачком модуля или в закрытом корпусе. Оптопара на модуле развязывает управление от катушки, но не отменяет ни колпачок, ни правила: контактная группа остаётся сетевой стороной. Логику фонаря я отрабатываю на двенадцативольтовой ленте через те же клеммы — скетч не меняется ни на символ, а цена ошибки падает с ожога до предохранителя.
const int RELE = 7;const int FOTO = A0;const int UROVEN_VKL = LOW; // мой модуль LOW-активныйconst int UROVEN_VYKL = HIGH;const int POROG = 300; // темнее этого — включаем int lamp = 0;unsigned long lastSmena = 0; void releVkl() { digitalWrite(RELE, UROVEN_VKL); lamp = 1;} void releVykl() { digitalWrite(RELE, UROVEN_VYKL); lamp = 0;} void setup() { pinMode(RELE, OUTPUT); digitalWrite(RELE, UROVEN_VYKL); // щелчка при загрузке не будет Serial.begin(9600); Serial.println("Fonar: POROG=300, gisteresis 5s");} void loop() { int svet = analogRead(FOTO); if (svet < POROG && lamp == 0 && millis() - lastSmena >= 5000) { releVkl(); lastSmena = millis(); } if (svet >= POROG + 50 && lamp == 1 && millis() - lastSmena >= 5000) { releVykl(); lastSmena = millis(); } Serial.print("svet="); Serial.print(svet); Serial.print(" lamp="); Serial.println(lamp); delay(200);}| Нагрузка | Ключ | Почему именно он |
|---|---|---|
| Светодиод, до 20 мА | пин напрямую | хватает пина: резистор 220 Ом и вперёд, это и есть первые уроки |
| Мотор или лента 12 В, пара ампер | MOSFET-модуль | ШИМ работает, щелчков нет, механический ресурс не тратится |
| Лампа 220 В, редкие включения | модуль реле | наш случай: оптопара, винтовые клеммы, колпачок и закрытый корпус |
| 220 В, диммирование и частые переключения | симистор с радиатором | реле не диммирует и рассчитано на сто тысяч циклов |
| Катушка реле прямо от пина | никак | 70–90 мА против двадцати у пина — прямой путь к сгоревшему порту |
Практика: ручное управление в симуляторе
Симулятор выше — та же логика, что у фонаря на крыльце, только команды приходят из монитора вместо фоторезистора. На каждом реле-модуле я прогоняю три опыта до монтажа в корпус. Первый: отправьте on с лишним пробелом в конце — trim() срежет хвост, команда сработает; затем уберите trim() из скетча и отправьте её снова — сравнение с on провалится молча, лампа не дрогнет, и журнал не объяснит почему. Второй: уберите digitalWrite(RELE, LOW) из setup() и перезапустите скетч — на LOW-активном модуле лампа успеет загореться до первой команды: тот самый ночной щелчок, теперь у вас на глазах, а не в моём рассказе. Третий: верните прижимку и поменяйте UROVEN_VKL и UROVEN_VYKL местами — логика перевернётся, тёмное станет гасить фонарь; цена LOW-активности — одна строка против правки каждого digitalWrite по скетчу.
Про гистерезис из полной версии — отдельно, это самый недооценённый приём у новичков. Порог включения 300, выключения 350: зазор в пятьдесят единиц — примерно десятая часть шкалы фоторезистора, и именно столько ходит освещённость вокруг заката, гуляя от облаков. Без зазора реле в сумерках щёлкает каждые пару минут: освещённость пересекает порог туда-сюда, и сто тысяч циклов механического ресурса выгорают за пару осенних недель. Тот же приём — два порога вместо одного — держите в голове для любого порогового переключателя: термостат, поплавок в бочке, датчик влажности почвы.
- Пин Arduino не тянет катушку: двадцать миллиампер против семидесяти-девяноста. Между пином и нагрузкой — модуль реле: транзистор, диод и оптопара PC817 уже на плате.
- Клеммы: COM — общий, NO замыкается при сработавшей катушке, NC размыкается. Для фонаря — NO: без питания и без команды света нет.
- Большинство модулей LOW-активные: реле щёлкает от нуля. Инверсия живёт в константах UROVEN_VKL и UROVEN_VYKL — в единственном месте скетча.
- pinMode(RELE, OUTPUT) и следом неактивный уровень — первыми строками setup(): иначе при каждой загрузке пин висит в Hi-Z и реле щёлкает.
- Реле не диммирует: сто тысяч переключений, минуты на ШИМ 490 Гц. Часто и плавно — MOSFET или симистор; сетевую сторону держим под колпачком и в корпусе.
- 1. Пин отдаёт 20 мА, катушка реле ест 70–90 мА. Что будет при прямом подключении катушки к пину?
- 2. Модуль реле LOW-активный. Какой уровень на входе IN включает реле?
- 3. Зачем digitalWrite(RELE, UROVEN_VYKL) сразу после pinMode в setup()?
- 4. Почему реле не годится для диммирования лампы ШИМ-ом на 490 Гц?
Катушка, COM/NO/NC и лампа: переключи логику LOW/HIGH и поймай, почему реле работает наоборот.
Подгружаем интерактив…
Частые вопросы по теме урока
- Пин отдаёт 20 мА, катушка реле ест 70–90 мА. Что будет при прямом подключении катушки к пину?
- Двадцать миллиампер — паспорт пина, сорок — абсолютный максимум ATmega. Катушка требует втрое-вчетверо больше: выходной каскад перегревается и умирает, иногда унося соседние пины. Роль усилителя — транзистор на модуле. Пин просадит напряжение, и выходной транзистор порта, скорее всего, сгорит
- Модуль реле LOW-активный. Какой уровень на входе IN включает реле?
- Светодиод оптопары модуля горит, когда ток втягивается в пин, — это происходит при LOW. Инверсию фиксируют константой в одном месте скетча, а не правкой каждого вызова digitalWrite. LOW: вход втягивает ток через светодиод оптопары при нуле на пине
- Зачем digitalWrite(RELE, UROVEN_VYKL) сразу после pinMode в setup()?
- После подачи питания пины Uno висят в Hi-Z, оптопара приоткрыта, и катушка успевает щёлкнуть до первой команды скетча. Прижимка неактивного уровня первыми строками setup() убирает ночной щелчок. Чтобы пин не висел в Hi-Z при загрузке и реле не щёлкало на каждой перезагрузке
- Почему реле не годится для диммирования лампы ШИМ-ом на 490 Гц?
- Механика не успевает за сотнями герц: ресурс сто тысяч переключений выгорает за считаные минуты. Для частых и плавных переключений берут MOSFET или симистор, а реле щёлкают редко. Контакты не успевают за частотой: якорь не садится, катушка живёт на пусковом токе — реле умирает за минуты