Свет в прихожей у меня включала кнопка у двери, и не включала никогда по-другому: руки у входа всегда заняты — коробки, пакеты, ключи, — а кнопка под локоть не подстроена. Хуже того, выключать её забывали все, включая меня: лампа горела ночами в пустом коридоре, и по счётчику это выходило заметнее, чем весь мой стенд с Arduino. Ручное решение провалилось по-человечески: оно требовало от людей помнить, а люди не помнят.
Первый PIR-датчик я поставил и чуть не отправил обратно: свет включался сам, безо всякого движения, примерно через двадцать секунд после подачи питания. Я трижды правил скетч, подозревал плавающий вход и плохой контакт, а потом прочитал в описании модуля слово, которое всё объяснило: прогрев. Первые 30–60 секунд после питания плата датчика стабилизируется и выдаёт ложные срабатывания, это её нормальное поведение, а не брак. С тех пор первый запуск любого PIR-проекта у меня планируется так, чтобы минуту после включения никто не смотрел на свет с подозрением.
Разберём подключение по трём проводам, два подстроечника и джампер, соберём светильник, который держит свет сам — на millis, а не на доверии к винтику, — и пройдёмся по списку ложных тревог: сквозняки, батареи и собаки. И да — сначала скетч в симуляторе, потом провод на реальный модуль: порядок, который экономит половину ложных выводов о датчике.
Три провода и два подстроечника
У HC-SR501 три ноги: питание, земля, выход. Питание — 5 В от платы: у модуля свой стабилизатор, паспортный диапазон от 4.5 до 20 В, поэтому 5 В от Uno — в самый раз. Выход датчика — 3.3 В, и для digitalRead на Uno это честная единица: порог логической единицы при пяттивольтовом питании — примерно три вольта. Выход сам держит и HIGH, и LOW, это не кнопка с подтяжкой: ставим pinMode INPUT без всяких PULLUP, как у кнопки из урока про digitalRead мы подтяжку ставили именно потому, что у кнопки нет своего мнения о уровне.
Два подстроечника задают характер датчика. Первый — чувствительность: дальность обзора примерно от трёх до семи метров, чем шире, тем дальше он видит. Второй — время: сколько выход держит HIGH после срабатывания, от пары секунд до пяти минут по паспортным цифрам. У меня время выкручено на минимум, секунды три: решение «сколько горит свет» я хочу принимать в скетче, а не отвёрткой. Джампер режима — отдельная история: положение H продлевает HIGH повторными срабатываниями, L выдаёт один импульс на эпизод движения; для светильника нужен H, иначе свет мигает на границе зоны.
И правило прогрева: первые 30–60 секунд после подачи питания датчик калибруется и может выдать несколько ложных срабатываний подряд. Число с условием: если питание пропадало — скетч первые 60 секунд сигналам не верит, просто смотрит на millis(). Это одна строка в коде, которая экономит вечер отладки, как и unsigned long для метки времени — тип мы выбирали ещё в уроке про переменные и типы.
Монтаж — тоже часть настройки. Датчик вешается на высоте около метра-полутора, объективом к двери: зона обзора — конус, и от угла установки зависит, что в этот конус попадает. Мой первый экземпляр смотрел вдоль стены коридора под острым углом и честно рапортовал о движении всякий раз, когда за перегородкой проходили соседи: тёплое тело у тонкой стены для PIR — как гость в прихожей. Полчаса с рулеткой и картонным тубусом экономят месяцы раздражения.
const int PIR = 2;const int SVET = 12;const unsigned long PAUZA = 5000; // сколько секунд тишины выдерживаем unsigned long posledneeDvizhenie = 0;int svetGorit = 0; void setup() { pinMode(PIR, INPUT); pinMode(SVET, OUTPUT); Serial.begin(9600); Serial.println("Svetilnik: 0");} void loop() { int dvizhenie = digitalRead(PIR); if (dvizhenie == HIGH) { posledneeDvizhenie = millis(); // движение есть — таймер свежий if (svetGorit == 0) { svetGorit = 1; digitalWrite(SVET, HIGH); Serial.println("Svet: 1"); } } if (svetGorit == 1 && millis() - posledneeDvizhenie > PAUZA) { svetGorit = 0; digitalWrite(SVET, LOW); Serial.println("Svet: 0"); } delay(100);}Скелет скетча — не «включить по движению», а «держать время самому». Датчик только освежает метку posledneeDvizhenie; гашение живёт в отдельном условии: тишина дольше PAUZA — свет погас. Ветвление здесь то же, что в уроке про if/else, а отсчёт без блокировки — прямой родственник уроку про millis вместо delay: поставь я тут delay(5000), скетч на пять секунд ослеп бы для нового движения. Строки Svet: 1 и Svet: 0 в журнале — старый добрый приём из первого урока про монитор: числа парами имя=значение, чтобы и глазу было видно, и плоттер не путался.
Второй подход — доверить удержание самому модулю: выкрутить Tx на нужные минуты и писать тупое if (dvizhenie == HIGH) digitalWrite(SVET, HIGH); else digitalWrite(SVET, LOW); — три строки, и держит датчик. Минус один: время зашито в винте и не меняется перепрошивкой; минус два: Tx у дешёвых экземпляров плавает от температуры. Я держу время в скетче, а Tx на минимуме, но для «свет в чулане на три минуты» вариант с винтом — честная экономия усилий, я его тоже использую.
Теперь ложные тревоги. PIR видит инфракрасное тепло, а не «людей» — любое тёплое тело и даже поток тёплого воздуха. Мой прихожий датчик ловил кухню через открытую дверь: сквозняк нёс нагретый воздух прямо через зону обзора. Помогли картонный тубус на объектив и уменьшенная чувствительность: зона сузилась до прихожей. Батарея за шторой и собака работают так же — это не глюки, а честная работа датчика по его паспорту.
Отдельный кейс — длительное движение. Пока датчик видит людей, он присылает HIGH снова и снова, метка millis освежается, свет горит бесконечно — так и задумано. Но если человек сидит неподвижно, тёплый и тихий, в кресле за спинкой, датчик его теряет: через пять секунд тишины свет гаснет прямо над читающим. Лечится двумя путями: поднять PAUZA до минуты-другой или переложить удержание на модуль, выкрутив Tx, — для читальной комнаты я бы выбрал второе.
| Что вижу | Причина | Что делать |
|---|---|---|
| Свет включается сам после подачи питания | прогрев модуля первые 30–60 секунд | не верить датчику, пока millis() < 60000 |
| Свет горит минутами после выхода | подстроечник Tx выкручен на минуты | время на минимум, держит скетч |
| Срабатывает на проходящих в коридоре | чувствительность на максимуме, зона шире двери | уменьшить Sx, тубус на объектив |
| Включения у батареи или плиты | PIR видит тёплый воздух, а не людей | увести зону обзора от источников тепла |
| Лампа не зажигается от выхода датчика | выход сигнальный, 3.3 В — не силовая линия | реле или транзистор между датчиком и нагрузкой |
Светильник как автомат и границы метода
Посмотрите на скетч глазами автомата: состояний два — свет горит и свет погас; переходы — движение и таймер тишины. Это тот же скелет, что у светофора из урока про конечный автомат, только состояний меньше. Когда захочется ночного режима — после полуночи светить тускло — появится третье состояние и условие по времени, и скетч перейдёт из «датчик плюс лампа» в настоящий автомат с таблицей переходов, не меняя ни пина.
Где PIR не нужен или нужен с оговорками. Лестница между этажами: датчик за спиной погасит свет над головой — там ставят два датчика, сверху и снизу, и логика посложнее. Улица: капли дождя и нагретое солнцем стекло на объективе дают ложные, для улицы берут герметизированные датчики с регулировкой зоны. Обратная сторона того же свойства: кладовка с духовкой рядом — PIR будет видеть духовку, как гостя. И ещё одна граница: датчик слеп к неподвижному человеку — PIR реагирует на изменение теплового пятна, и статичное тело через минуту становится мебелью. Датчик любит помещение, ровную температуру и предсказуемую зону обзора.
Про симулятор — честно. На макетке датчик движения — это тумблер «движение есть / движения нет»: он воспроизводит цифровую суть, HIGH на входе при движении, и ничего больше. Ни прогрева, ни зоны, ни подстроечников в симуляторе нет — всё, что связано с винтами и прогревом, проверяется только на реальном модуле. Зато логика скетча — освежил метку, выдержал паузу, погасил — в симуляторе та же до последней строки.
- 1. Почему для выхода HC-SR501 ставят pinMode INPUT, а не INPUT_PULLUP?
- 2. За что отвечает подстроечник Tx на модуле?
- 3. Свет включился сам через 20 секунд после подачи питания. Наиболее вероятная причина?
- 4. Что делает PAUZA = 5000 в скетче светильника?
- 5. Куда подключить саму лампу прихожей?
- HC-SR501 — три провода: 5 В, земля, выход 3.3 В. Выход push-pull, поэтому pinMode INPUT без подтяжки — не как у кнопки.
- Два подстроечника: чувствительность Sx — примерно 3–7 м, время Tx — от ~3 секунд до 5 минут. Моё правило: Tx на минимум, время держит скетч.
- Первые 30–60 секунд после питания модуль калибруется и врёт: скетч игнорирует датчик, пока millis() < 60000.
- Светильник = движение освежает метку millis, тишина дольше PAUZA гасит свет: никакого delay, loop остаётся отзывчивым.
- Нагрузка — только через реле или транзистор; ложные тревоги дают сквозняки, батареи и животные: PIR видит тепло, а не людей.
Частые вопросы по теме урока
- Почему для выхода HC-SR501 ставят pinMode INPUT, а не INPUT_PULLUP?
- Выход PIR — push-pull: он активно выдаёт оба уровня, как кнопка из ранних уроков не умеет. Подтяжка на таком входе ничего не ломает, но и не нужна. Выход датчика сам держит и HIGH, и LOW — подтяжка не нужна
- За что отвечает подстроечник Tx на модуле?
- Tx — время удержания выхода. Моё правило: Tx на минимум, а решение «сколько горит свет» принимает скетч через PAUZA. За время, которое выход держит HIGH после срабатывания — от секунд до минут
- Свет включился сам через 20 секунд после подачи питания. Наиболее вероятная причина?
- Плата датчика стабилизируется после включения и врёт. Лечение — игнорировать датчик, пока millis() < 60000. Прогрев: первые 30–60 секунд HC-SR501 выдаёт ложные срабатывания
- Что делает PAUZA = 5000 в скетче светильника?
- Движение освежает метку millis, и как только тишина длится дольше PAUZA, свет гаснет. loop при этом крутится без остановки. Сколько миллисекунд тишины выдерживаем, прежде чем погасить свет
- Куда подключить саму лампу прихожей?
- Выход датчика даёт 3.3 В и миллиамперы: достаточно для digitalRead и недостаточно для лампы. Между ними — реле или транзистор. Через реле или транзистор: выход датчика — сигнальный, не силовой