# 🔊 Теория: активные бузеры

## 1. Конструкция и принцип работы

**Бузер** (звуковой излучатель) — это компонент, который превращает электрический
сигнал в звук. Внутри активного бузера уже впаяна небольшая генераторная схема,
которая сама создаёт колебания мембраны на фиксированной частоте (обычно 2–3 кГц).

Поэтому управление предельно простое: подать на управляющий вывод бузера постоянное
напряжение (логический уровень HIGH или LOW, без переменного сигнала) — и он звучит,
пока напряжение не снимут. Это то, что в коде драйвера делает `digitalWrite()` —
см. [`ActiveBuzzer.cpp:11-14`](src/ActiveBuzzer.cpp#L11-L14), метод `setPinState()`.

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

| Характеристика | Активный бузер | Пассивный бузер |
| :--- | :--- | :--- |
| Как включается | `digitalWrite()` — постоянный уровень | `tone()` — переменный сигнал (PWM) |
| Нагрузка на CPU/таймеры | Не использует | Занимает аппаратный таймер под `tone()` |
| Какие звуки может издавать | Один фиксированный тон | Любая частота, можно играть мелодии |
| Типичное применение | Простые сигналы: пищит/не пищит | Индикация уровней, мелодии |

Это принципиальное отличие определяет и код: там, где пассивному бузеру нужно было бы
менять частоту `tone()`, активный бузер лишь включается и выключается в нужные моменты
времени — вся "музыка" сводится к тайминг-паттернам.

## 3. Как драйвер строит сигналы поверх одного тона

Раз у активного бузера нет регулировки частоты, единственный доступный инструмент —
модулировать *время* включения/выключения. Драйвер реализует это без `delay()` —
через машину состояний в [`update()`](src/ActiveBuzzer.cpp#L46-L84), которая
вызывается на каждой итерации `loop()` и сравнивает `millis()` с моментом последнего
переключения:

- **Одиночный писк** (`beep(durationMs)`, [ActiveBuzzer.cpp:28-36](src/ActiveBuzzer.cpp#L28-L36)) —
  включить и выключиться самостоятельно через `durationMs`.
- **`Pattern::Alert`** ([ActiveBuzzer.cpp:60-67](src/ActiveBuzzer.cpp#L60-L67)) — прерывистая
  тревога: переключение состояния каждые `kAlertPeriodMs` (500 мс,
  [ActiveBuzzer.h:68](include/ActiveBuzzer.h#L68)), пока не вызовут `turnOff()`.
- **`Pattern::Confirm`** ([ActiveBuzzer.cpp:69-78](src/ActiveBuzzer.cpp#L69-L78)) — два
  коротких писка по `kConfirmPulseMs` (100 мс, [ActiveBuzzer.h:69](include/ActiveBuzzer.h#L69))
  и автоматическое выключение.

Тайминги 500 мс и 100 мс — не характеристика бузера из даташита, а методический выбор:
такие интервалы хорошо различимы на слух и удобны для демонстрации на уроке.

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

В большинстве компонентов этого репозитория драйвер умеет проверять, жив ли обмен
данными с датчиком (`isAlive()`). У активного бузера обмена данными нет вообще —
только один исходящий сигнал `digitalWrite()`, без какой-либо обратной связи. Поэтому
программно узнать, оборван ли провод или неисправен ли сам зуммер, невозможно —
это физическое ограничение схемы (см. `@note` в [ActiveBuzzer.h:22-25](include/ActiveBuzzer.h#L22-L25)).
