Бесконтактный выключатель освещения со звуковым эффектом на Arduino
Всем привет!
Сегодня я Вам расскажу про бесконтактный выключатель с звуковым эффектом, который был сделан мной 9 лет назад, а если быть точным то в январе 2012 года. Ссылку на ролик 2012 г. я выложил в комментарии под этим видео.
С тех пор выключатель трудится у меня круглыми сутками на протяжении 9 лет. Что самое интересное он За все это время, он не выходил из строя и даже ни разу не подвис, а также у него никогда не было ложных срабатываний. Вообщем он хорошо себя зарекомендовал и я с уверенностью могу его Вам рекомендовать для самостоятельной сборки.
Если Вам интересны все подробности, то прошу посмотреть этот ролик до конца и оценить его подпиской и лайком.
У меня в коридоре смонтировано 7 светильников.

И для достижения красивого визуального эффекта, я использовал последовательное включение ламп, для этого мне нужно было протянуть к плате контроллера, отдельный провод от каждой точки освещения .

Саму плату я спрятал в пространстве между гипсокартоном и потолком, благо места там больше чем достаточно.

ИК приемник и светодиод я разместил в подрозетнике. Во избежании ложных срабатываний их нужно изолировать между собой, для этого я использовал термоусадочный кембрик. Что бы подключить этот оптический датчик к плате контроллера, можно использовать заложенные в стену провода.

Для того что бы дизайн выключателя не отличался от других установленных декоративных накладок в интерьере, я использовал из этой же серии телевизионную розетку, из которой выкинул все внутренности, а в отверстие вклеил круглое окошко вырезанное из фиолетового акрила.

Все компоненты были размещены мной на одной плате, на которой установлены винтовые коннекторы для подключения проводов от светильников.

Запитал я эту плату обычным зарядным устройством от телефона. Которое по сей день работает, видать в то время зарядки изготавливали по более надежным схемам чем сейчас.

Основой всего устройства является контроллер arduino Nano V.3, но можно так же использовать любые другие платы, с микроконтроллером Atmega328

ИК светодиод с фототранзистором можно взять от датчика препятствий, но не обязательно их выпаивать, достаточно перерезать лишние дорожки и припаять к ним 3 провода. Если у Вас есть откуда нибудь эти ранее выпаянные детали, то перед использованием, лучше сначала проверить их на работоспособность. Инфракрасный светодиод подключите к напряжению 5 В, через токоограничивающий резистор 120 Ом и посмотрите на него через камеру телефона, он должен светиться фиолетовым светом. Для проверки фототранзистора понадобится любой тестер с функцией прозвонки проводников. Переводим тестер в режим прозвонки, а выводы фототранзистора подключаем к щупам тестера. После чего нужно к нему в плотную поднести любой пульт от бытовой техники и нажать любую кнопку. В ответ раздастся прерывистый пищащий звук.

9 лет назад я не нашел подходящих твердотельных реле и мне пришлось их собирать самому из рассыпухи. Но на данный момент проще купить 8 канальный модуль твердотельных реле как на изображении, чем заниматься тратой времени на поиск этих компонентов.

Работает выключатель следующим образом
Arduino с выхода D5 постоянно выдает ШИМ сигнал с частотой примерно 977 Гц. К этому выходу через токоограничивающий резистор 82 Ом подключен светодиод, излучающий сигнал в инфракрасном диапазоне. Фототранзистор подключенный к входу D2 детектирует отраженный от руки ИК сигнал и проверяет его на достоверность и если сигнал из 20-ти или больше идущих подряд импульсов соответствует частоте 977 Гц, то тогда контроллер включает по очереди все 7 светильников и начинает воспроизводить звуковой эффект через ШИМ выход D11. Все тоже самое происходит и при выключении.

Воспроизведение звуков
Для воспроизведения звуковых эффектов используется формат WAV без сжатия, с частотой 16000 Гц и глубиной 8 бит , но при воспроизведении данного формата с использованием ШИМ, в аудио тракте наблюдается неприятный свист и шипение. По этому для для улучшения качества воспроизведения, я в коде использовал линейную интерполяцию. При которой, выборка семплов происходит на частоте 62.5 кГц и между оригинальными выборками вставляются еще 3 дополнительных семпла рассчитанных методом линейной интерполяции. Таким образом на выходе снижается шум квантования, пропадает свист, улучшается качество звука и для воспроизведения не обязательно использовать дополнительные RC фильтры.

Вместо динамика я использовал старую, маленькую компьютерную колонку без встроенного усилителя.

Для конвертирования Wave файлов в Си код, можно воспользоваться онлайн конвертером
Схема
На схеме серыми прямоугольниками отметил твердотельные реле, а тем кто хочет заморочиться, то может собрать схему полностью, так же как сделал я в далеком прошлом.

Компоненты для сборки
1 – Arduino Nano V.3
2 – Датчик препятствий
3 – 8-ми канальный модуль реле
4 – Соединительные провода Dupont
Код для Arduino
#include "TimerOne.h" #include "PlaySound.h" #include "fife.h" // звуковой фаил тра-ля-ля #include "off1.h" // звуковой фаил пиу #define power_ir 180 // Мощность импульсов ИК передатчика, Влияет на расстояние срабатывания максимум=180. минимум=50. #define lamp_delay 200 // задержка между включениями ламп #define lamp_num 7 // количество ламп от 1 до 7, от D13 до D19, если исп. 1 лампочка то она на D13 и т.д. в порядке увеличения #define IR_send 5 // выход на ИК светодиод(передатчик). переназначать нельзя #define IRrec 2 // выход на ИК фото-транзистор(приемник) переназначать нельзя uint8_t state = 0; // статус выключателя uint16_t Counter=0; // счетчик импульсов volatile uint8_t timerCount=0; //счетчик длительности периода импульса volatile uint8_t int_flag=0; // флаг или статус прерывания void setup() { for (byte i=13; i<(lamp_num+13); i++) { pinMode(i, OUTPUT);} // активируем выходы на Лампочки Lamp_Switch(); //выкл свет pinMode(IRrec, INPUT_PULLUP); // Вход с подтягивающим резистором для фототранзистора pinMode(IR_send, OUTPUT); //выход на ИК светодиод TCCR0B = TCCR0B & 0b11111000 | 3; //задать частоту ШИМ 976.5625 Гц для ИК светодода analogWrite(IR_send,power_ir); //запустить ИК передатчик attachInterrupt(0, Ir_sens, FALLING); //внешнее прерывание по заднему фронту, так как фототранзистор инвертирует сигнал Timer1.initialize(102); //инициализация таймера на 102мкс. если умножить на 10 то получим длительность периода частоты 980Гц Timer1.attachInterrupt(int_ir); //обработчик прерываний таймера } void loop() { if( int_flag==3 ) //если было второе прерывание то проверяем длительность периода полученного импульса { Timer1.restart(); // сбросить таймер счетчик на 0 int_flag = 0; // обнулить флаг прерывания if( timerCount<12 && timerCount>9 ) Counter++; else Counter=0; //если длительность в допуске то инкремент к счетчику импульсов timerCount=0; // сбросить счетчик длительности периода импульса } if( int_flag==1 ) //если было прерывание то начинаем отсчет длительности периода { Timer1.restart(); // сбросить таймер на 0 int_flag=2; // сбросить флаг прерывания timerCount=0; // сбросить счетчик длительности периода импульса } if(Counter>20) //если количество импульсов больше 20 то включить или выключить свет. { // Можно указать 200 но будет медленней срабатывать state=~state; //статус выключателя // if(state>0) PlaySound::startPlayback((uint8_t *)fife, sizeof(fife)); //если включили, то тра-ля-ля if(state==0) PlaySound::startPlayback((uint8_t *)off1, sizeof(off1)); //если выключили, то пиу-ля-ля Lamp_Switch(); // вкл/выкл свет timerCount=0; // сбросить счетчик длительности периода импульса Counter=0; // обнулить счетчик импульсов int_flag = 0; // обнулить флаг прерывания Timer1.restart(); // сбросить таймер на 0 } } //////////// обработка прерываний по таймеру /////////////////////////////// void int_ir() { timerCount++; //счетчик длительности периода } //////////// обработчик внешнего прерывания /////////////////////////////// void Ir_sens() { int_flag++; // установить флаг прерывания } ////////////// вкл/выкл свет ////////////////////////////////////// void Lamp_Switch() { if(state==0) { for (byte i=13; i<(lamp_num+13); i++) { digitalWrite(i, LOW); //выключить свет delay(lamp_delay); } }else{ for (byte i=13; i<(lamp_num+13); i++) { digitalWrite(i, HIGH); //включить свет delay(lamp_delay); } } }
В этот раз я решил добавить все используемые библиотеки в папку со скетчем, а в самом скетче прописал их локальное использование. Теперь надеюсь у новичков будет меньше ко мне вопросов, по поводу ошибок при компилировании.
В коде вынесены несколько констант, которые можно изменить перед прошивкой.
Константа power_ir – отвечает за дистанцию срабатывания выключателя, может принимать значения от минимума 20 и до максимума 200. Требуемое Вам значение можно определить экспериментальным путем.
lamp_num – определяет количество используемых Вами ламп. Минимальное число лампочек не может быть меньше 1, а максимальное не более 7. Если подправить код то можно увеличить до 15.
lamp_delay – это задержка между последовательными включениями ламп, которая выражена в миллисекундах и может начинаться от 0 и до 4 294 967 295 мс. Хотя я не думаю, что такие огромные задержки кому то понадобятся )
Заключение
В заключении хотелось бы добавить, что я очень удивлен, что микроконтроллер без WDT, за 9 лет ни разу не подвис. По этой же причине я не стал править код и добавлять в него WDT, так как Arduino со старыми bootloader не умеют работать с ним и их еще достаточно большое количество на руках у DIY сообщества
Спасибо, что дочитали до конца!
Если Вам понравилась моя статья — то поддержите ее лайком и подпиской
Если у Вас есть вопросы, то можете их задать в комментариях.
2 комментария
Please share full code. Thanks