Цепляем микрофон по кривой схеме :)    источник      <<<назад


Взбрела в голову идея собрать старую игрушку - управление светом с хлопков в ладоши. Подцепил микрофон к Arduino - выяснилось что сигнал слабоватый, и вообще-то надо ставить операционник. Под рукой никакого операционника не нашлось - придумал идиотскую схему через RC-цепочку. С такой схемой при тишине получаем на выходе ноль вольт, а различные хлопки дают слабенький сигнал.
Чтобы его хоть как-то поймать, переключаем диапазон АЦП с 5 на 1.1 вольта, и уже что-то там начинает ловиться.
Для защиты от ложных срабатываний программа ловит 2 последовательных хлопка с обязательной тишиной между ними.
Микрофон подобный обычно зовется в радиомагазине как "электретный обычный китайский, сейчас посмотрю по бумагам... CNZ15E" :). Можно брать любой подобный - китайцы такие куда только не суют. Чувствительность каждого конкретного микрофона сильно зависит от значения R1. Если я ничего не путаю, то при нормальном значении R1 нога 1 микрофона имеет потенциал примерно половина от напряжения питания. В данном случае в .pdf'ке на микрофон указан R1=2.2k, но при 9.1k он значительно чувствительнее.

схема.



исходник.
-------------
int MicPin = 0;          //вход микрофона
int CtlPin = 13;         //нога, которой управляем
int CtlVal = 0;          //состояние этой ноги сразу после включения
int ClapMargin = 11;     //порог хлопка (определяется экспериментально)
int SkipLen = 1500;      //длительность защитной паузы
int SilenceLen = 3000;   //длительность тишины после хлопка
int NextClapLen = 1000;  //время, в течение которого ждем след. хлопок
 
void setup()
{
  //настраивыем выход управления
  pinMode(CtlPin, OUTPUT);
  digitalWrite(CtlPin, CtlVal);
  //устанавливаем предел АЦП на 1.1В (для увеличения чувствительности микрофона)
  analogReference(INTERNAL);
//  Serial.begin(115200);
}
 
int mic_prev = 0;
//ф-ия ReadNext выдает следующий байт данных. Это не просто напряжение на MicPin входе, а
//модуль разницы между текущим значением и предыдущим. Фактически - модуль производной
int ReadNext() {
  int result;
  int d;
  d = analogRead(MicPin);   //читаем
  result = abs(mic_prev-d); //считаем модуль разницы
  mic_prev = d;             //сохраняем текущее значение
  return result;            //возвращаем результат
}
 
//ф-ия ожидает хлопка в течении WaitLen циклов. Если за это время хлопок произошел,
//возвращает 1, иначе 0. Если WaitLen == -1, то по времени ограничения нет
//Если был хлопок, то завершается сразу как только его обнаружит
int WaitForClap(int WaitLen) {
  int d, i;
  i = 0;      //счетчик циклов
  do {
    d = ReadNext();                //читаем вход
    i++;                           //увеличиваем счетчик
    if (d > ClapMargin) {          //если есть хлопок
      return 1;                    //возвращаем 1
    }
    if ( (WaitLen != -1) && (i >= WaitLen) ) { //если счетчик досчитал до WaitLen и WaitLen не равен -1
      return 0;                                //возвращаем 0
    }
  } while (1);
}
 
//ф-ия просто ждет SkipLen циклов
void Skip(int SkipLen) {
  int i;
  for (i=0; i<SkipLen; i++) {
    ReadNext();
  }
}
 
void loop() {
  int d1, d2;
  WaitForClap(-1);              //ждем хлопок
  Skip(SkipLen);                //пропускаем после него защитный интервал
  d1 = WaitForClap(SilenceLen); //слушаем тишину
  if (d1 == 0) {                //если была тишина
    d2 = WaitForClap(NextClapLen);   //ждем 2го хлопка
    if (d2 == 1) {                   //если есть 2й хлопок
      CtlVal = 1 - CtlVal;              //переключаем выход управления на противоположный
      digitalWrite(CtlPin, CtlVal);
    }
  }
  Skip(SkipLen);                 //пропускаем еще один защитный интервал
}