Добрый день!
В этом посте я хочу поделится с хабр сообществом о принципе работы сделанного мной
бесконтактного выключателя. Выключатель планируется использовать в системе умный дом.
Основой выключателя является недавно купленный мной улучшенный клон контроллера Arduino, продающегося под названием Carduino Nano V.7
Работает выключатель так:
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ом
Как работает схема собранная мной на макетной плате, можно посмотреть на видео.
Код для 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; //частота ШИМ 1000Гц
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, вся схема с блоком питания будут собраны на отдельной плате и вмонтирована в коридорный выключатель.
Автор: CyberLab