Датчик звука, последовательное зажигание светодиодов.

altdmb14
Offline
Зарегистрирован: 26.09.2018

Всем привет. Имеется задача следующего характера. Есть arduino Nano, датчик звука 

также есть 12 светодидов. Человек кричит в микрофон, если кричит на протяжении 2 секунд = загорается первый светодиод, если 4 секунды = загорается 2 светодиод. К 24 секунде должны загореться все 12 светодиодов. Пробовал и так и эдак, и через analogRead() и через прерывание. Пока получается зажечь криком только один светодиод, но не знаю:

1. как заставить гореть этот светодиод

2. как отсчитать время сигнала (что уже прошло 2 секунды)

 

Из того, что пока получилось набрать:

volatile byte count;

void setup() {
  Serial.begin(9600);
  pinMode(3, INPUT); // выход OUT
  pinMode(12, OUTPUT); // внешний светодиод
  attachInterrupt(1, myInterrupt, FALLING);

}

void loop() {
  Serial.println(count);
  digitalWrite(12,0);
  delay(500);
}

void myInterrupt() {
  digitalWrite(12,1);
  count++;
}

Заранее всем спасибо.  Надеюсь на ваши подсказки.

sadman41
Offline
Зарегистрирован: 19.10.2016

millis() знаете?

altdmb14
Offline
Зарегистрирован: 26.09.2018

Читал у вас в справочнике. Если Вас не затруднит пример можете привести как я его могу задействовать?

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Тут надо всю систему менять.

b707
Offline
Зарегистрирован: 26.05.2017

altdmb14 пишет:

Читал у вас в справочнике. Если Вас не затруднит пример можете привести как я его могу задействовать?

да все просто.

0. сначала у вас сигнала нет и переменная флаг =0

1. Читаете значение с микрофона.

2. Если есть сигнал и флаг ==0, то выставляем флаг =1 и запоминаем миллис

3. Если есть сигнал и флаг ==1 -  берем разницу текущего миллис и запомненного в п.2, в зависмости от прошедшего времени зажигаем нужное число диодов

4. если сигнала нет, то флаг =0

5 GOTO 1

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

Еще проще, но не без нюансов:

1. Ждем сигнала с микрофона

2. Ждем 2 секунды и читаем микрофон

3. Если сигнал есть - включаем 1 светодиод, нет - идем на п.1.

4. Ждем 2 секунды... и т.д.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

mykaida пишет:

Еще проще, но не без нюансов:

1. Ждем сигнала с микрофона

2. Ждем 2 секунды и читаем микрофон

3. Если сигнал есть - включаем 1 светодиод, нет - идем на п.1.

4. Ждем 2 секунды... и т.д.

Если "ждем" - это dalay(), то решение явно неуниверсальное, а в противном случае - идейно не отличается от предыцдущего поста с чтением millis и выставлением флагов, но только более громоздкое и немасштабируемое.

altdmb14
Offline
Зарегистрирован: 26.09.2018

Попробовал набросать код (следуя вашим советам) и получилось следующее.

boolean micr_flag =0;
int micr;
unsigned long last_krik =0;

void setup() {
  pinMode(12, OUTPUT);
  pinMode(11, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  micr = analogRead(A5);
  Serial.println(micr);
  Serial.print("TIME: "); Serial.println(millis());

  if (micr < 1000  && millis() - last_krik > 2000) {
    micr_flag = 1;
    digitalWrite(11,1);
    last_krik = millis();
  }
  else digitalWrite(11,0);
  Serial.print("LAST_KRIK: "); Serial.println(last_krik);
  
}

Все равно до конца не могу понять как отследить сигнал точнее.

Для чтения сигнала я использую функцию micr = analogRead(A5);

Которая (если смотреть по монитору порта), выдаёт цифровые значения. При тишине 1023, в случае крика значение проседает в районе 32-41. НО даже если я кричу в микрофон (например "ААААА"), то значение 32 не постоянно и плавает туда-сюда..

b707
Offline
Зарегистрирован: 26.05.2017

altdmb14 пишет:

Попробовал набросать код (следуя вашим советам) и получилось следующее.

Неправильно.

Вы не разобрались в логике алгоритма. что я давал в сообщении #4.  Обратите внимание, что там переменная флаг проверяется на втором и третьем шаге, а в вашем коде переменная micr_flag совершенно бесполезна - вы нигде не проверяете  ее значение.

Пробуйте еще

altdmb14
Offline
Зарегистрирован: 26.09.2018

А как лучше проверять наличие сигнала? Путём чтения функцией (analogRead) в цикле loop или использование прерывания? 

b707
Offline
Зарегистрирован: 26.05.2017

altdmb14 пишет:

А как лучше проверять наличие сигнала? Путём чтения функцией (analogRead) в цикле loop или использование прерывания? 

зачем тут прерывание? У вас весь код на 20 строк и совершенно не требует быстрой реакции. Вы для начала разберитесь с простейшей логикой, чтобы код работал правильно - а потом, если захотите, можете и прерывание подтянуть.

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

Да ну вас, тут разговоров не о чем - сначала простую программу написать, а затем украшательства, millis и т.д..

void setup() {
portn=2;
.........
}
void loop() {
while (analogRead(A5)>1000){
digitalWrite(portn,1);
delay(2000);
digitalWrite(portn,0);
portn++;
if (portn=13) portn=2;
}
}

 

sadman41
Offline
Зарегистрирован: 19.10.2016

Делайте по частям.

Часть первая - засечь повышенный уровень громкости и засечь начало цикла, сохранив значение millis() в переменной. Применяйте переменную-защелку (флаг), чтобы засечь только один раз.

Часть вторая - засечь "тишину", сохранив значение millis() в переменную конца цикла. Вывести разницу между началом цикла и его концом один раз. Снова примените переменную-защелку (вторую).

 

altdmb14
Offline
Зарегистрирован: 26.09.2018

mykaida пишет:

Да ну вас, тут разговоров не о чем - сначала простую программу написать, а затем украшательства, millis и т.д..

void setup() {
portn=2;
.........
}
void loop() {
while (analogRead(A5)>1000){
digitalWrite(portn,1);
delay(2000);
digitalWrite(portn,0);
portn++;
if (portn=13) portn=2;
}
}

 

 

Только наверное analogRead(A5)<1000, потому что всё что ВЫШЕ 1000 это тишина.

И ещё такой момент, как я уже говорил выше, даже если ты постоянно кричишь (или дуешь в микрофон) получаемое функцией analogRead - значение не постоянно, и плавает от минимума (31) к максимуму (1023). Хотя микрофон настроен на максимальную чувствительность (светодиод микрофона чуть подсвечивает даже в тишине).

altdmb14
Offline
Зарегистрирован: 26.09.2018

Код немного доработал, теперь получается поддерживать постоянно включенным первый светодиод, через 2 секунды загорается второй. Но только из-за того, что получаемые значения бегают, иногда срабатывает else, ктр гасит светодиод и который затем сразу же включается..

boolean micr_flag =0;
int micr;
unsigned long last_krik =0;

void setup() {
  pinMode(12, OUTPUT);
  pinMode(11, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  micr = analogRead(A5);
  Serial.println(micr);
  Serial.print("TIME: "); Serial.println(millis());

  if (micr < 1000 && micr_flag == 0) {
    micr_flag = 1;
    digitalWrite(12,1);
    last_krik = millis();
  }
  else if (micr > 1000 && millis() - last_krik > 5000){
    digitalWrite(12,0);
    micr_flag = 0;
  }
  
  if (micr_flag == 1 && millis() - last_krik > 2000){
    digitalWrite(11,1);
  }
  
  Serial.print("LAST_KRIK: "); Serial.println(last_krik);
  
}

 

sadman41
Offline
Зарегистрирован: 19.10.2016

altdmb14 пишет:

Код немного доработал, теперь получается поддерживать постоянно включенным первый светодиод, через 2 секунды загорается второй. Но только из-за того, что получаемые значения бегают, иногда срабатывает else, ктр гасит светодиод и который затем сразу же включается..

Вот так вам более понятно?

boolean soundOn = 0;
int soundLevel;
unsigned long startKrikTime, endKrikTime, krikDuration;

void setup() {
  Serial.begin(9600);
}

void loop() {
  soundLevel = analogRead(A5);
  Serial.println(soundLevel);
  Serial.print("TIME: "); Serial.println(millis());

  if (soundLevel > 700 && soundOn == 0) {
    soundOn = 1;
    startKrikTime = millis();
  }

  if (soundLevel < 300 && soundOn == 1){
    endKrikTime = millis();
    soundOn = 0; 
    krikDuration = endKrikTime - startKrikTime;  
    Serial.print("krikDuration: "); Serial.println(krikDuration);
  }
  
}

 

leks
Offline
Зарегистрирован: 22.10.2017

У меня такой же датчик звука, только плата синего цвета.  Он хорошо работает. На выходе у него сигнал низкого уровня (0) когда говоришь громко и высокого уровня (1) когда тишина. Чуствительность на громкость звука регулируется переменным резистором (синий такой кубик на плате). Настроить желаемую можно подав питание на датчик, вращая резистор, подавая звуки и глядя на сигнальный светодиод.  И это без Ардуино. Вообще датчик имеет только два состояния по выходу.  

altdmb14
Offline
Зарегистрирован: 26.09.2018

Скорее всего у тебя цифровой, а у меня аналоговый.

leks
Offline
Зарегистрирован: 22.10.2017

altdmb14 пишет:

Скорее всего у тебя цифровой, а у меня аналоговый.

А где такой купил? Дай ссылку, посмотреть. А то с аналоговым тоже хочется попробовать.

altdmb14
Offline
Зарегистрирован: 26.09.2018

leks пишет:

altdmb14 пишет:

Скорее всего у тебя цифровой, а у меня аналоговый.

А где такой купил? Дай ссылку, посмотреть. А то с аналоговым тоже хочется попробовать.

Покупал не я, одолжил у товарища. Боюсь здесь нельзя кидать ссылку (посчитают за рекламу), поищи на али, думаю без проблем найдешь.

faworit20
Offline
Зарегистрирован: 18.07.2017

Тут пожалуй забыли про частоту, сколько может выдать наша глотка? ;) необходимо поставить на входе R/C цепочку, тогда уровень сигнала после апроксимации будет более стабильнее. Но это как вариант, второй - вариант - постоянно контролировать АЦП (ну к примеру) если уровень (max) появляется каждые ХХ мСек. вот тогда и держим в true переменную(булеан).

altdmb14
Offline
Зарегистрирован: 26.09.2018

faworit20 пишет:

Тут пожалуй забыли про частоту, сколько может выдать наша глотка? ;) необходимо поставить на входе R/C цепочку, тогда уровень сигнала после апроксимации будет более стабильнее. Но это как вариант, второй - вариант - постоянно контролировать АЦП (ну к примеру) если уровень (max) появляется каждые ХХ мСек. вот тогда и держим в true переменную(булеан).

Это которая интегрирующая ? 

%D0%B8%D0%BD%D1%82%D0%B5%D0%B3%D1%80%D0%

Осталось только рассчитать номиналы деталек..

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

altdmb14 пишет:

Осталось только рассчитать номиналы деталек..

Если никто не снял про это мультик, тогда бида!, бида!

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

altdmb14 пишет:
Всем привет. Имеется задача следующего характера. Есть arduino Nano, датчик звука 

также есть 12 светодидов. Человек кричит в микрофон, если кричит на протяжении 2 секунд = загорается первый светодиод, если 4 секунды = загорается 2 светодиод. К 24 секунде должны загореться все 12 светодиодов. Пробовал и так и эдак, и через analogRead() и через прерывание. Пока получается зажечь криком только один светодиод ..

Никто так и не обратил внимание, подскажу: Автор, ты ДВАДЦАТЬ ЧЕТЫРЕ секунды пробовал кричать в микрофон НЕПРЕРЫВНО? :)

altdmb14
Offline
Зарегистрирован: 26.09.2018

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

boolean micr_flag =0;
int micr;
int portn;
unsigned long last_krik =0;
unsigned long last_start =0, last_tishina;
long krik_duration, last_led;

void setup() {
  pinMode(12, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(7, OUTPUT);
  portn = 11;
  Serial.begin(9600);
}

void loop() {
  micr = analogRead(A5);
  Serial.println(micr);
  Serial.print("TIME: "); Serial.println(millis());

  if (micr < 1000 && micr_flag == 0) {
    micr_flag = 1;
    digitalWrite(12,1);
    last_krik = millis();
  }
  Serial.print("LAST_KRIK: "); Serial.println(last_krik);
  
  if (micr < 1000){
    last_start = millis();
  }
  Serial.print("LAST_START: "); Serial.println(last_start);
  
  if (micr > 1000){
    last_tishina = millis();
    krik_duration = last_tishina - last_start;
  }
  Serial.print("LAST_TISHINA: "); Serial.println(last_tishina);
  Serial.print("KRIK_DURATION: "); Serial.println(krik_duration);
  
  if (krik_duration > 5000){
      digitalWrite(12,0);
      digitalWrite(11,0);
      digitalWrite(10,0);
      digitalWrite(9,0);
      digitalWrite(8,0);
    krik_duration = 0;
    micr_flag = 0;
    portn = 11;
  }

  if (micr_flag == 1 && millis() - last_krik > 2500){
    digitalWrite(portn,1);
    last_krik = millis();
    Serial.print("LAST_KRIKNEW: "); Serial.println(last_krik);
    portn--;
    Serial.print("LAST_PORTN: "); Serial.println(portn);
  }
}

Надо будет ещё оптимизировать (особенно с перечислением портов), а так в целом поставленную задачу решает.