В этой статье мы расскажем как сделать включение света по хлопку, а именно как превратить ATtiny13 со звуковым детектором в интеллектуальный переключатель Clap Clap Switch. Устройство разработано, чтобы оно реагировало только на двойные хлопки (двойной хлопок — ВКЛ, двойной хлопок — ВЫКЛ).
Выключатель света по хлопку — как это работает?
Есть один контакт (6) микроконтроллера Attiny13 для микрофона (цифровой выход из модуля детектора звука) и один контакт (5) для светодиода (для отображения процесса включения / выключения).

Для проверки состояния микрофона используется внешнее прерывание (INT0). В основном цикле есть алгоритм, который заботится о процессах обнаружения хлопков, счетчиков, сброса состояний и переключения светодиода.
Пользователь выключателя света по хлопку имеет широкий временной интервал от 0,1 до 1 секунды между первым и вторым хлопком. На мой взгляд, достаточно времени для двойного хлопка, но не стесняйтесь экспериментировать с другими значениями!
Одиночный хлопок/шум не должны влиять на процесс обнаружения двойного хлопка (такова была цель!). Этот проект можно легко расширить, добавив дополнительные компоненты, такие как, например, реле для управления высоковольтными устройствами. Код находится на Github.
Требуемые компоненты
- ATtiny13
- Модуль датчика микрофона (на базе LM393)
- Резистор — 220 Ом (см. Расчет резистора светодиодов)
- Светодиод

Код программы
Этот код написан на C и может быть скомпилирован с помощью avr-gcc. Вся информация о том, как скомпилировать этот проект, находится здесь.
/** * Copyright (c) 2019, Łukasz Marcin Podkalicki <lpodkalicki@gmail.com> * ATtiny13/050 * Clap-Clap Switch. */ #include <avr/io.h> #include <avr/interrupt.h> #include <util/delay.h> #define LED_PIN PB0 #define MIC_PIN PB1 static volatile uint8_t state = 0; int main(void) { uint8_t reset = 0, claps = 0; /* setup */ DDRB |= _BV(LED_PIN); // устанавливаем вывод светодиода как выход MCUCR &= ~(_BV(ISC01)|_BV(ISC00)); // запускаем прерывание INT0 при обнаружении низкого уровня GIMSK |= _BV(INT0); // разрешить прерывание INT0 sei(); // разрешаем глобальные прерывания /* loop */ while (1) { /* если обнаружен одиночный хлопок, запускаем процедуру */ if (state) { claps++; // увеличиваем количество хлопков if (claps == 1) { // если это первый хлопок, reset = 0; // обнуляем счетчик сброса } else if (claps == 2) { // если это второй хлопок, PORTB ^= _BV(LED_PIN); // включение / выключение светодиода claps = reset = 0; // и устанавливаем начальные значения } state = 0; // для каждого обнаружения хлопка сбрасываем состояние _delay_ms(200); // и ждем 0,2 с. } /* если счетчик отдыха равен макс (1 с), то устанавливаем начальные значения */ if (++reset >= 10) { claps = state = reset = 0; } _delay_ms(100); // задержка цикла } } ISR(INT0_vect) { state = 1; }
