Шторку в дверной проём мастерской я собирал дважды. Первая версия считала всё подряд: дрожь показаний у границы порога давала по три-четыре пересечения за один проход, и журнал в Serial выглядел как очередь из призраков. Вторая считает честно: лазер горит на одном косяке, фоторезистор ловит его на другом, а скетч меняет счётчик только по фронту — переходу «свободен → перекрыт», подтверждённому двумя порогами с зазором. Тот же приём, что в звуковом шкафу из урока про сигнализацию, только там считались режимы, здесь — прохожие.
Идея не нова: в irremote-кластере уже была счётная шторка на ИК-луче из урока про ИК-барьер — там невидимый пучок 940 нм и приёмник VS1838B, которому солнце безразлично, потому что он фильтрует всё, кроме модуляции 38 кГц. Лазерная версия на фоторезисторе проще и нагляднее — точку прицеливания видно, — но у неё честная слабость: LDR ловит весь видимый свет, и пороги приходится калибровать под место. Разберём обе стороны, чтобы выбор был осознанным.
Геометрия: лазер напротив фоторезистора
Схема из двух деталей и общего провода. Лазерный модуль на D12 — луч горит постоянно, один digitalWrite(HIGH) в setup(). Фоторезисторный модуль — на A0: тот, что из урока про ночной светильник, с делителем на плате — ярче свет, выше analogRead. Луч 650 нм попадает в чувствительность любого LDR: сульфид кадмия отзывается на весь видимый диапазон, красный — как родной.
Две практические мелочи решают больше кода. Первая — трубка: соломинка или корпус от авторучки на фоторезистор отсекает боковой свет, и пол шкалы падает — луч становится главным источником. Вторая — питание луча: тридцать миллиампер на пине сутками — на пределе, поэтому если середина модуля прозвонилась на плюс, питайте лазер от шины 5 В; если нет — транзисторный ключ на 2N2222, пин отдаёт на базу долю миллиампера и живёт спокойно.
И примите медлительность сенсора: у фоторезистора реакция на изменение света занимает десятки миллисекунд. Человека в дверях это не касается, а каплю дождя или вспышку блика LDR видит смазанно. Если когда-нибудь понадобится шторка на десятки пересечений в секунду — место фоторезистора займёт фототранзистор, и это будет уже другая схема.
| Состояние луча | Слайдер в симуляторе | analogRead | Что делает скетч |
|---|---|---|---|
| свободен | выше 39 % | выше 400 | дежурит и ждёт |
| перекрыт | ниже 29 % | ниже 300 | фронт: плюс один к счётчику |
| мёртвая зона | 29-39 % | 300-400 | режим не меняется — гасим дрожь |
Фронт вместо уровня: почему счёт не врёт
Почему два порога, а не один. Показания analogRead дрожат даже на неподвижном приёмнике: лампа мерцает, отражения ходят по комнате, у самого АЦП есть свои пара единиц шума. С одной границей в 300 значение гуляет 298-303, и каждый провал вниз — новое «пересечение». Зазор в сотню единиц создаёт мёртвую зону, где состояние не меняется вовсе: чтобы войти в «перекрыт», луч должен провалиться по-настоящему, чтобы вернуться в «свободен» — по-настоящему восстановиться.
Почему фронт, а не уровень. Пока рука в луче, условие «перекрыт» истинно сотни проходов loop(): при цикле 20 мс рука в проёме на полсекунды даёт двадцать пять истин. Счётчик, прибавляющий на каждом проходе, насчитает плюс двадцать пять вместо единицы. Поэтому прибавляем один раз — в момент перехода из «свободен» в «перекрыт»: переменная luch хранит прошлое состояние, и плюс один случается, только когда прошлый цикл был свободен, а этот — перекрыт. Тот же фронт, на котором урок про кнопку ловит нажатие.
const int LASER = 12;const int LDR = A0;const int POROG_ZAKR = 300; // ниже — луч перекрытconst int POROG_SVOB = 400; // выше — луч свободен int schet = 0;int luch = 0; // 0 — свободен, 1 — перекрыт void setup() { pinMode(LASER, OUTPUT); digitalWrite(LASER, HIGH); // луч горит постоянно Serial.begin(9600); Serial.println("Shtorka: laser D12, ldr A0");} void loop() { int uroven = analogRead(LDR); int tek = luch; // состояние с гистерезисом if (uroven < POROG_ZAKR) { tek = 1; } else if (uroven > POROG_SVOB) { tek = 0; } if (tek == 1 && luch == 0) { // фронт: свободен -> перекрыт schet = schet + 1; Serial.print("peresechenie "); Serial.println(schet); } luch = tek; Serial.print("ldr="); Serial.print(uroven); Serial.print(" luch="); Serial.print(luch); Serial.print(" schet="); Serial.println(schet); delay(20);}Что считается, а что нет
Шторка считает пересечения, а не людей. Прошёл туда — плюс один, вернулся обратно — ещё плюс один: в журнале два события, в комнате по-прежнему гость. Для дверного счётчика это обычно и нужно; если хочется знать, сколько людей внутри, нужны два луча вплотную и порядок их перекрытия — направление прохода. Это следующий уровень, и собирается он из двух таких шторок на разных пинах.
Второе ограничение — скорость с другой стороны. Человек перекрывает луч на 200-500 мс, скетч с циклом 20 мс делает 10-25 замеров — не промахнётся. А вот капля или вспышка блика дают провал на единицы миллисекунд: он либо проскочит между замерами, либо будет честно посчитан. В счётчике это терпимо, в охране — нет: там, в следующем уроке, на вход тревоги встанет фильтр 100 мс. Если захочется смотреть на форму провала, а не на числа, — те же значения ldr= красиво ложатся на график плоттера.
И отличие от PIR из урока про светильник: пиродатчик отвечает на движение в конусе — есть движение или нет, а шторка фиксирует пересечение конкретной линии. Движение мимо луча она не заметит, зато увидит ползущего, которого PIR теряет. Инструменты дополняют друг друга, а не заменяют.
- Лазер горит постоянно с D12, фоторезистор с делителем на A0: перекрыли луч — analogRead падает
- Два порога с зазором (300/400 в шкале симулятора) — мёртвая зона гасит дрожь показаний в единицы-десятки единиц
- Счёт по фронту «свободен → перекрыт»: переменная прошлого состояния, плюс один — один раз за пересечение
- Шторка считает пересечения, не людей и не направления; два луча вплотную дадут направление прохода
- Пол шкалы правится механикой: трубка на приёмник отсекает боковой свет, у живой платы пороги калибруют по своим показаниям
- 1. Показания дрожат вокруг порога 300. Что делает счётчик с одной границей?
- 2. Рука висела в луче 500 мс при цикле 20 мс. Сколько раз сработает счётчик по фронту?
- 3. Как в симуляторе изображают перекрытие луча?
- 4. Человек прошёл в дверь и через минуту вышел обратно. Что покажет счётчик?
- 5. Почему у лазерной шторки на LDR слабое место по сравнению с ИК-барьером на VS1838B?
Частые вопросы по теме урока
- Показания дрожат вокруг порога 300. Что делает счётчик с одной границей?
- Дрожь в 10-20 единиц у одной границы даёт трещотку. Лечение — гистерезис: вход в «перекрыт» ниже 300, выход только выше 400. сыпит пересечениями: каждый провал ниже границы — новый плюс один
- Рука висела в луче 500 мс при цикле 20 мс. Сколько раз сработает счётчик по фронту?
- Уровень «перекрыт» истинен все 25 проходов, но фронт один. Счёт по уровню насчитал бы 25 — потому и переход. один раз: плюс один случается только на переходе свободен → перекрыт
- Как в симуляторе изображают перекрытие луча?
- Ярче свет — выше analogRead: слайдер вниз опускает показания ниже порога, и скетч видит то же, что ладонь в реальном луче. тянуть слайдер яркости фоторезистора вниз
- Человек прошёл в дверь и через минуту вышел обратно. Что покажет счётчик?
- Счётчик считает пересечения линии: туда плюс один, обратно ещё плюс один. Направление прохода дают два луча вплотную и порядок их перекрытия. двойку — по одному пересечению в каждую сторону
- Почему у лазерной шторки на LDR слабое место по сравнению с ИК-барьером на VS1838B?
- Приёмник ИК-шторки отфильтровывает всё, кроме модуляции 38 кГц, — солнцу всё равно. LDR честно видит весь свет, поэтому трубка и калибровка обязательны. LDR ловит весь видимый свет: солнце и лампы поднимают пол шкалы