Оптический выключатель со звуковым эффектом на Arduino

Добрый день!
В этом посте я хочу поделится с хабр сообществом о принципе работы сделанного мной
бесконтактного выключателя. Выключатель планируется использовать в системе умный дом.

Основой выключателя является недавно купленный мной улучшенный клон контроллера Arduino, продающегося под названием Carduino Nano V.7
image


Работает выключатель так:
Arduino с выхода D5 постоянно выдает ШИМ сигнал с частотой 976Гц и со скважностью 50%. К выходу
D5 через токограничивающий резистор подключен светодиод, излучающий световой сигнал в инфракрасном диапазоне. Фототранзистор подключенный к входу Arduino D2 детектирует
отраженный от руки ИК сигнал. Arduino получает ИК сигнал, проверяет его на достоверность и если сигнал из 20 идущих подряд импульсов соответствует частоте 976Гц, то тогда контроллер включает синий светодиод (L) на выходе D13 Arduino и начинает воспроизводить звуковой эффект через выход SPK контроллера. Все тоже самое происходит и при выключении светодиода (L).

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

Схема простая для ее сборки я использовал
1-Carduino Nano V.7
2-IR светодиод из старого пульта ДУ от телевизора, светодиод нужно запаять в термоусадку, во избежании бокового излучения
3-Фототранзистор LTR-3208E
4-Динамическая головка из детской игрушки
5-Резисторы 10к и 68ом

image

Как работает схема собранная мной на макетной плате, можно посмотреть на видео.


Код для Arduino Nano:

#include <TimerOne.h>     
#include <avr/delay.h>
#include <avr/pgmspace.h>
#include "fife.h"
#include "hi.h"

////////переменные проигрывателя////////////////////////////////////
#define speakerPin 11
volatile uint16_t sample=0;
volatile uint8_t lastSample, FirstSample;
volatile byte new_data,future_data,old_data;
volatile byte stat=0;
unsigned char *wave;
unsigned int length;
////////переменные выключателя////////////////////////////////////
uint8_t state = 0;
volatile uint16_t timerCount, lengthImpuls;
volatile uint16_t Counter=0;
////////////начальная предустановка///////////////////////////////
void setup() 
{ 
  pinMode(speakerPin, OUTPUT);    //выход на динамик
  digitalWrite(speakerPin, LOW);   //что бы не спалить динамик
  pinMode(2, INPUT);              // Вход, к фототранзистору 
 // digitalWrite(2, HIGH);          //Подключить подтягивающий резистор
  pinMode(13, OUTPUT);              //Лампочка
  pinMode(5, OUTPUT);               //выход ШИМ на ИК светодиод
  TCCR0B = TCCR0B & 0b11111000 | 3;  //частота ШИМ 976Гц
  analogWrite(5,128 );               //запустить ШИМ
  attachInterrupt(0, Ir_sens, RISING); //внешнее прерывание по фронту
  Timer1.initialize(10);              //инициализация таймера  
  Timer1.attachInterrupt(callback);   //прерывание таймера
} 
////////////обработка прерывания по таймеру///////////////////////////////
void callback() { timerCount++; }
////////////обработчик внешнего прерывания///////////////////////////////
void Ir_sens()
{ 
lengthImpuls = timerCount;
timerCount=0;
Counter++; 
}
///////////////////////Обработчик прерывания по совпадению с OCR2///////////////////
ISR(TIMER2_COMPA_vect) 
{        
 switch (stat)
  { 
    case 0:{
              old_data = pgm_read_byte(&wave[sample]);
              OCR2A = old_data; 
              stat=1;
              ++sample;  
              if (sample == length) stat=4;
              future_data = pgm_read_byte(&wave[sample]); 
              new_data = (old_data+future_data)/2; 
            }  
      break;
    case 1:  {OCR2A=(old_data+new_data)/2; stat=2; } 
      break;  
    case 2:   {OCR2A = new_data; stat=3; }
      break;    
    case 3:   {OCR2A=(new_data+future_data)/2; stat=0; } 
      break;
    case 4:   if(lastSample==0) stat=5; else {--lastSample; OCR2A=lastSample;} 
      break;      
    case 5:   stopPlayback(); 
      break;
  }    
}
////////////главный цикл программы///////////////////////////////
void loop() 
{ 
 if(lengthImpuls>105 || lengthImpuls<99) Counter=0;  
 if(lengthImpuls>99 && lengthImpuls<105 && Counter>20) 
 {  
    state=~state; 
    digitalWrite(13, state);    
    if(state>0) play_wave((unsigned char *)hi,  hi_length);  
    if(state==0) play_wave((unsigned char *)fife,  fife_length);  
   _delay_ms(200);    

   while(Counter>10)  
       {
         if(lengthImpuls>105 || lengthImpuls<99) Counter=0; 
       }             
    lengthImpuls=0;  
  }
}
////////////начать воспроизведение///////////////////////////////
void play_wave(unsigned char *wave_data, unsigned int wave_length)
{
 wave=wave_data; 
 length=wave_length;
 startPlayback(); 
}

void startPlayback()
{
    sample=0;
    stat=0;
    
    ASSR |=(1<<AS2);

   TCCR2A |= ((1<<COM2B1)|(0<<COM2B0)|(1<<COM2A1)|(0<<COM2A0)|(1<<WGM21)|(0<<WGM20)); 
    TCCR2B = ((0 << CS22) | (0 << CS21) | (1 << CS20) | (0<<WGM22) | (1<<FOC2A) |  (1<<FOC2B)); 

    lastSample = pgm_read_byte(&wave[length-1]); 

    TCNT2 = 0; 
    TIMSK2|=(1<<OCIE2A);
    sei();
   
     for (int i=0; i <50; i++)
     {
       new_data=i;
         stat=2;
          sample = 0;         	
      _delay_us(1);
     }
   stat=0;  
}
////////////остановить воспроизведение///////////////////////////////
void stopPlayback()
{
    TIMSK2&=(0<<OCIE2A); 
    TCCR2B &=(0<<CS10);
}


Скачать исходники одним файлом

В следующей статье:
Arduino Nano будет заменен на контроллер Atmega328, вся схема с блоком питания будут собраны на отдельной плате и вмонтирована в коридорный выключатель.
Поделиться публикацией

Комментарии 17

    +1
    Спасибо за статью! Первая мысль, куда пристроить «безконтактный» переключатель, была общественный туалет. А вот свет выключать удобно было бы удаленно, а не без контакта. Но все равно хорошая работа.
      0
      Как раз сейчас работаю над выключателем с удаленным управлением
      Как доведу его до ума, выложу здесь статью.
        0
        >Arduino Nano будет заменен на контроллер Atmega328, вся схема с блоком питания будут собраны на отдельной плате и вмонтирована в коридорный выключатель.

        Вот за это вам большой плюс. Не зацикливаетесь на готовых ардуинах и правильно делаете.

        Единственное что — лично мне вот всегда хотелось включать/выключать свет удаленно, т.к. обычно такое желание приходит когда уже ложишься, поэтому я для себя собирал сначала выключатель, управляемый с пульта от ТВ, потом голосовой. Мне кажется, это чаще требуется)
          0
          А почему Atmega328, думаю вполне модно обойтись менее мощным и более дешевым контроллером. Например ATTiny85 или ATTiny2313A/4313A
            0
            Потому что Wave хранится в памяти программ контроллера равной 32к для сравнения у ATTiny85 всего 8к.
            Если выкинуть звуковые эффекты то тогда можно и Tiny применить
          +1
          Интересная реализация проигрывания WAV-файла. Взял на заметку!
            0
            Звук порадовал, спасибо! А насчёт бесконтактного срабатывания от руки на близком расстоянии — вот тут посмотрите, как ещё один вариант. Я делал контакнтый способ, но если поставить резисторы побольше то будет на расстоянии срабатывать, там в комментах уже опробовали.
            0
            Планирую так же написать статьи на тему выключатели:
            «Выключатель с голосовым управлением»
            «Выключатель с даленным управлением по сети»
            «Выключатель управляемый любым ПДУ от бытовой техники»
            «Автоматический выключатель с оптическим датчиком присутствия»
            «Емкостной выключатель»
              0
              Все хотел озвучить открывание двери звуком из Вавилона 5, хороший вариант!
                0
                вся схема с блоком питания будут собраны на отдельной плате и вмонтирована в коридорный выключатель.

                Вот это было очень круто!
                  0
                  Статью написал, но выложить ее здесь нет возможности так как не хватает кармы.
                  Так что немножко потерпите, буду добывать карму.
                  0
                  Пошел далать «стартовый аккорд» для хакинтош
                    0
                    Не совсем понял — где хранится WAV?
                      0
                      WAVE хранится в основной памяти программ.
                      Wave из бинарного типа нужно предварительно проконвертировать в HEX
                      Посмотри вот эти файлы, это и есть Wave
                      #include «fife.h»
                      #include «hi.h»

                    • НЛО прилетело и опубликовало эту надпись здесь
                        0
                        Спасибо за идею, сделал аналогичную штуку на «Уно», но только с УЗ-датчиком.

                        Хотел расположить это дело на потолке (2,60 м).
                        Так он жену не определяет. Волосы, очевидно, причиной.

                        И еще, когда пробовал заливать скетч, в уно, также весь не входил, пришлось обрезать «звуковые» массивы.
                        Поэтому мега, с 128 памяти. конечно больше подходит.

                        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                        Самое читаемое