Лампа в кладовке у меня включается брелком от радиорозетки: клавиша, эфир, щелчок реле внутри корпуса розетки. Магазинная связка работала годами, но брелок жил своей жизнью — дважды падал за шкаф, один раз уехал в кармане куртки в стиральную машину. Когда я захотел, чтобы свет зажигался сам при открытии двери, брелок оказался бесполезен: ему нечего сказать скетчу, у него нет ни пина, ни протокола, ни кнопки «выполни». Вечер с передатчиком FS1000A за полтораста рублей всё изменил: теперь код кнопки шлёт Uno, а брелок лежит в коробке как запасной.
Управление светом по кабелю мы уже собирали в уроке про светодиод и монитор, а по воздуху через Bluetooth — в уроке про HC-05. У обоих есть границы: кабель дотягивается ровно на свою длину, Bluetooth живёт метров десять и просит телефон-собеседника. 433 МГц — третий путь: пара модулей стоит дешевле пачки резисторов, сквозь стену проходит и телефон не нужен. Плата за ту же цену — приватность со знаком минус: эфир общий, и ваш код увидит любой, кто захочет слушать, — об этом ниже отдельной строкой.
План урока: собираем пару «передатчик FS1000A плюс приёмник», ставим библиотеку RCSwitch, выкрадываем код у родного пульта сниффером и шлём его из скетча вызовом send(код, 24). Отдельно — честная таблица «вольты в метры»: от питания передатчика зависит больше, чем от любого скетча, и именно на этом я потерял первый вечер.
Пара за копейки: кто есть кто на 433,92 МГц
Передатчик FS1000A — три ноги: VCC, DATA, GND, и отверстие под антенну на боку. Приёмник XY-MK-5V — четыре ноги, из них DATA продублирована. Оба живут на свободной частоте 433,92 МГц — там же, где пульты радиорозеток, уличные термометры и дверные звонки. Следствие для приёмника важное: он слышит всех подряд, чужие пакеты в эфире — норма, а не сбой. Разделять адреса — задача не радио, а протокола, и до неё мы дойдём в третьем уроке этого кластера.
Всю модуляцию берёт на себя библиотека RCSwitch: вы говорите ей «шлите вот это число двадцатью четырьмя битами», а она сама дёргает пин с правильными паузами между импульсами. Ставится из менеджера библиотек — порядок действий тот же, что в уроке про библиотеки в IDE. При приёме она делает обратное: превращает кашу импульсов с DATA приёмника обратно в число. enableReceive, available, getReceivedValue — три вызова, и сниффер готов.
Почему именно двадцать четыре бита? Пульты радиорозеток шлют короткие посылки, обычно до 24 бит: в них зашиты адрес семейства, номер кнопки и команда вкл-выкл. У моего брелка коды ON и OFF в двоичном виде соседствуют и различаются тремя младшими разрядами — так экономили место в древних схемах с дип-переключателями. RCSwitch умеет шлить и длиннее, но розетка ждёт свою длину, и чужой формат она просто не узнает.
| Питание FS1000A | В квартире, через стену | На открытом воздухе | Мой вердикт |
|---|---|---|---|
| 5 В от платы | 5-10 м, одну стену проходит | до 20 м | рабочий минимум: брелок тоже не богатырь |
| 9 В (крона) | 10-15 м, две стены на пределе | 30-40 м | компромисс для комнаты-двух |
| 12 В (блок питания) | 20-30 м, панелька ловит | 50 м и больше | то, что ставят в готовые проекты |
| 12 В плюс антенна 17,3 см | 30-40 м, соседний этаж | за сотню метров | когда розетка за двумя стенами |
Схема: DATA на пин 10, питание и антенна отдельно
Подключение передатчика: DATA — в пин 10, GND — в землю платы, VCC — по таблице выше. Пин 10 я выбираю не по вкусу, а по границам платы: он далеко от пинов 0 и 1, которые держат аппаратный Serial и загрузку скетча, — та же логика, что в уроке про SoftwareSerial. mySwitch.enableTransmit(10) — и библиотека знает, куда дёргать. Аналоговые пины трогать не стоит: АЦП нужен датчикам, а свободных цифровых на Uno хватает.
Антенна — обычный провод 17,3 см в отверстие ANT. Откуда цифра: длина волны на 433,92 МГц — 300 разделить на 433,92, примерно 69 сантиметров, четверть волны — 17,3 см. Без антенны модуль слышно втрое хуже, и никакие вольты этого не компенсируют. Питание 12 В я беру с отдельного блока, землю соединяю с платой; с VIN Uno тоже можно, если плата питается от адаптера 12 В, — но следите за нагревом стабилизатора: передатчик в эфире просит десятки миллиампер сверх обычного бюджета платы, и слабый адаптер покажет это просадками и сбоями приёма у самого себя.
Сниффинг: выкрадываем код у родного пульта
Чтобы узнать свой код, приёмник ставят на пин 2 — нулевое прерывание Uno — и смотрят, что шлёт пульт при нажатии. Три вызова RCSwitch, и сниффер готов; механика прерываний разобрана в уроке про attachInterrupt. Приём у меня выглядел так: жму кнопку I на брелке — в мониторе код 4527361 на 24 бита, жму OFF — 4527364. Код от одного нажатия к другому повторяется один в один — на этом и стоит вся затея: записали, зашили в скетч, шлём сами.
Отличать настоящую посылку от мусора помогает длина: приёмник без сигнала сыплет обрывками на 1-8 бит, а настоящие пакеты держат свои 24 — фильтр по длине битов отсекает девять десятых шума. Полную историю про шум и повторы я разобрал в следующем уроке, про приём датчиков погоды. Здесь берём привычку: код считается украденным, только когда три нажатия подряд дали одно и то же число.
Тонкость, на которой спотыкаются: у части пультов длина импульса отличается от типовых 350 микросекунд — встречались и 144. RCSwitch угадывает её при приёме и печатает в сниффере, а перед отправкой вашу цифру задают через setPulseLength(). Если розетка молчит при, казалось бы, правильном коде — сверяйте pulse: это первое, что я смотрю после питания.
#include <RCSwitch.h> RCSwitch mySwitch; void setup() { Serial.begin(9600); mySwitch.enableReceive(0); // прерывание 0 - это пин 2 на Uno Serial.println("Sniffer gotov: zhmu knopku pulta");} void loop() { if (mySwitch.available()) { Serial.print("kod="); Serial.print(mySwitch.getReceivedValue()); Serial.print(" bit="); Serial.print(mySwitch.getReceivedBitlength()); Serial.print(" pulse="); Serial.print(mySwitch.getReceivedDelay()); Serial.print(" bin="); Serial.println(mySwitch.getReceivedValue(), BIN); mySwitch.resetAvailable(); // отпускаем: ждём следующий пакет }}#include <RCSwitch.h> RCSwitch mySwitch; const unsigned long KOD_ON = 4527361UL; // кнопка I: записано снифферомconst unsigned long KOD_OFF = 4527364UL; // кнопка OFF той же розетки void poslatTriZhdy(unsigned long kod) { for (int i = 0; i < 3; i++) { // пульты шлют команду трижды mySwitch.send(kod, 24); // посыл 24 бит delay(10); } Serial.print("TX kod="); Serial.println(kod);} void setup() { Serial.begin(9600); mySwitch.enableTransmit(10); // DATA передатчика FS1000A mySwitch.setPulseLength(350); // своя цифра - из строки pulse сниффера Serial.println("Peredatchik na pine 10 gotov");} void loop() { poslatTriZhdy(KOD_ON); delay(3000); poslatTriZhdy(KOD_OFF); delay(3000);}Время посылки стоит посчитать, чтобы не удивляться: 24 бита при пульсе 350 микросекунд со стартовой паузой занимают порядка 10-15 миллисекунд, и send() всё это время занят целиком — дёргает пин и не отпускает скетч. Для розетки неважно, а в общем цикле с датчиками это лишние 15 мс слепоты на каждую отправку — вычитайте их из бюджета, который мы считали в уроке про millis вместо delay. Повторы с паузой 10 мс между ними — не перестраховка, а привычка эфира: один посыл розетка может пропустить, три подряд пропустить куда труднее.
Куда встроить отправку в живой проект? Как обычное дело с расписанием: дверь открылась — открытие двери шлёт ON, таймаут три минуты — шлёт OFF. Никаких while и никаких ожиданий ответа: у этого канала их просто нет, и притворяться обратное — путь к скетчу, который верит в недоставленные посылки. В третьем уроке кластера мы дойдём дальше — до адресов и чексумм, когда устройств станет два.
Отдельно про батарейки: передатчик тянет миллиамперы и в покое, и в эфире, поэтому в автономных датчиках его кормят через транзисторный ключ — пин управляет базой, VCC модуля живёт на коллекторе, и радиотракт включается только на момент посылки. Такой ключ мы собирали на 2N2222 в уроке про транзистор. Для комнатного проекта с блоком питания это лишнее, для дверного датчика на кроне — разница между неделей и годом. Кстати, адресация из третьего урока закрывает и обратную задачу: один приёмник слушает несколько передатчиков и различает их по адресу.
- FS1000A и XY-MK-5V — пара на 433,92 МГц за копейки; всю модуляцию ведёт RCSwitch: enableTransmit(10) и send(код, 24)
- Дальность решает питание: 5 В — 5-10 м через стену, 12 В — 20-30 м, плюс антенна 17,3 см (четверть волны) — ещё треть сверху
- Код розетки выкрадывается сниффером: enableReceive(0) на пине 2, код засчитан, когда три нажатия подряд дали одно число
- send() занят 10-15 мс на посыл и не отпускает скетч; пульты шлют команду трижды — повторяйте и вы
- Эфир общий и без шифрования: чужой сниффер повторяет ваш код за секунду — по радио не включают обогреватели
- 1. Что делает второй аргумент в mySwitch.send(4527361, 24)?
- 2. Какой пин Uno сидит на прерывании 0 — том, что даёт enableReceive(0)?
- 3. Питание 5 В, антенны нет, розетка за двумя стенами. Что даст наибольший прирост дальности?
- 4. Почему send() называют блокирующим?
- 5. Приёмник в тишине сыплет пакетами на 1-8 бит. Что это?
Частые вопросы по теме урока
- Что делает второй аргумент в mySwitch.send(4527361, 24)?
- Второй аргумент — битность: RCSwitch кодирует число указанным количеством бит. Пин задаёт enableTransmit, повторов в send нет — их делает ваш цикл. длину посылки в битах — код едет двадцатью четырьмя битами
- Какой пин Uno сидит на прерывании 0 — том, что даёт enableReceive(0)?
- enableReceive принимает номер прерывания, а не пин: прерывание 0 на Uno — это пин 2. Пин 3 — прерывание 1. пин 2
- Питание 5 В, антенны нет, розетка за двумя стенами. Что даст наибольший прирост дальности?
- Дальность определяет питание и антенна: 12 В поднимает её до 20-30 м через стены, четвертьволновый провод добавляет ещё треть. Скорость порта и номер пина на радио не влияют. кормить FS1000A от 12 В и добавить антенну 17,3 см
- Почему send() называют блокирующим?
- На время посылки библиотека сама формирует импульсы: 24 бита при пульсе 350 мкс — порядка 10-15 мс, и loop всё это время стоит. Подтверждений на этом канале нет вовсе. во время посылки скетч дёргает пин и не делает ничего другого
- Приёмник в тишине сыплет пакетами на 1-8 бит. Что это?
- Дешёвый приёмник усиливает всё подряд, и без сигнала DATA сыплет короткими обрывками. Фильтр по длине пакетов отсекает мусор, не трогая настоящие посылки. шум канала: настоящие посылки держат свои 24 бита