# 🔊 Теория: пассивные бузеры и генерация звука

## 1. Активный vs пассивный бузер

- **Активный бузер:** внутри уже есть генератор. Подать постоянное напряжение —
  он сам издаёт звук фиксированной частоты.
- **Пассивный бузер (динамик/пьезоэлемент):** генератора внутри нет. Чтобы он зазвучал,
  на управляющий вывод нужно подавать переменный сигнал (меандр) нужной частоты. Зато
  можно менять частоту и играть разные тона — этим и пользуется этот драйвер.

## 2. Физика звука

Звук — механическая волна. Частота этой волны (в Герцах, Гц) определяет высоту звука:
- **Низкие частоты (100–500 Гц):** басовые, глухие звуки.
- **Средние частоты (1000–3000 Гц):** наиболее слышимые человеческим ухом (сирены, звонки).
- **Высокие частоты (>5000 Гц):** писк, свист.

## 3. Метод генерации: функция `tone()`

Arduino Core предоставляет функцию `tone(pin, frequency)` — она сама генерирует на
указанном пине прямоугольный сигнал (меандр) с заполнением 50% на заданной частоте,
не занимая процессор построением сигнала вручную. Останавливает генерацию `noTone(pin)`.
В коде драйвера это `tone()`/`noTone()` в
[`PassiveBuzzer.cpp`](src/PassiveBuzzer.cpp) — например, `turnOn()`
([PassiveBuzzer.cpp:19-27](src/PassiveBuzzer.cpp#L19-L27)).

## 4. Как драйвер строит паттерны поверх `tone()`

Оба паттерна реализованы без `delay()` — через машину состояний в
[`update()`](src/PassiveBuzzer.cpp#L51-L79), которая на каждой итерации `loop()`
сравнивает `millis()` с моментом последнего переключения:

- **`Pattern::Siren`** ([PassiveBuzzer.cpp:56-63](src/PassiveBuzzer.cpp#L56-L63)) —
  чередование двух контрастных частот, `kSirenHighHz` (1200 Гц) и `kSirenLowHz`
  (800 Гц), каждые `kSirenSwitchMs` (150 мс) —
  см. [PassiveBuzzer.h:73-75](include/PassiveBuzzer.h#L73-L75). Пока не вызовут `turnOff()`.
- **`Pattern::BeepTriple`** ([PassiveBuzzer.cpp:65-74](src/PassiveBuzzer.cpp#L65-L74)) —
  три коротких писка на частоте `kBeepTripleFreqHz` (2000 Гц) по `kBeepTriplePulseMs`
  (100 мс), затем автоматическое выключение.

Частоты и интервалы — не характеристика конкретного бузера из даташита, а методический
выбор: 800/1200 Гц хорошо различимы на слух и создают узнаваемый эффект сирены.

## 5. Блокирующий помощник `beepBlocking()`

В отличие от остального API, `beepBlocking()` ([PassiveBuzzer.cpp:11-17](src/PassiveBuzzer.cpp#L11-L17))
использует `delay()` и останавливает программу на время сигнала. Это осознанное
исключение: он предназначен только для короткого сигнала при старте программы
("устройство готово"), пока ещё нечему мешать. Использовать его в `loop()` во время
основной работы не стоит — для этого есть неблокирующие `turnOn()`/`playSiren()`/`playBeepTriple()`.

## 6. Почему нет `isAlive()`

У пассивного бузера, как и у активного, нет канала обратной связи — только исходящий
сигнал `tone()`. Программно узнать, оборван ли провод или неисправен ли сам излучатель,
невозможно — это физическое ограничение схемы (см. `@note` в
[PassiveBuzzer.h:27-30](include/PassiveBuzzer.h#L27-L30)).
