Датчик звука, последовательное зажигание светодиодов.
- Войдите на сайт для отправки комментариев
Ср, 26/09/2018 - 22:39
Всем привет. Имеется задача следующего характера. Есть 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++;
}
Заранее всем спасибо. Надеюсь на ваши подсказки.
millis() знаете?
Читал у вас в справочнике. Если Вас не затруднит пример можете привести как я его могу задействовать?
Читал у вас в справочнике. Если Вас не затруднит пример можете привести как я его могу задействовать?
да все просто.
0. сначала у вас сигнала нет и переменная флаг =0
1. Читаете значение с микрофона.
2. Если есть сигнал и флаг ==0, то выставляем флаг =1 и запоминаем миллис
3. Если есть сигнал и флаг ==1 - берем разницу текущего миллис и запомненного в п.2, в зависмости от прошедшего времени зажигаем нужное число диодов
4. если сигнала нет, то флаг =0
5 GOTO 1
Еще проще, но не без нюансов:
1. Ждем сигнала с микрофона
2. Ждем 2 секунды и читаем микрофон
3. Если сигнал есть - включаем 1 светодиод, нет - идем на п.1.
4. Ждем 2 секунды... и т.д.
Еще проще, но не без нюансов:
1. Ждем сигнала с микрофона
2. Ждем 2 секунды и читаем микрофон
3. Если сигнал есть - включаем 1 светодиод, нет - идем на п.1.
4. Ждем 2 секунды... и т.д.
Если "ждем" - это dalay(), то решение явно неуниверсальное, а в противном случае - идейно не отличается от предыцдущего поста с чтением millis и выставлением флагов, но только более громоздкое и немасштабируемое.
Попробовал набросать код (следуя вашим советам) и получилось следующее.
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 не постоянно и плавает туда-сюда..
Попробовал набросать код (следуя вашим советам) и получилось следующее.
Неправильно.
Вы не разобрались в логике алгоритма. что я давал в сообщении #4. Обратите внимание, что там переменная флаг проверяется на втором и третьем шаге, а в вашем коде переменная micr_flag совершенно бесполезна - вы нигде не проверяете ее значение.
Пробуйте еще
А как лучше проверять наличие сигнала? Путём чтения функцией (analogRead) в цикле loop или использование прерывания?
А как лучше проверять наличие сигнала? Путём чтения функцией (analogRead) в цикле loop или использование прерывания?
зачем тут прерывание? У вас весь код на 20 строк и совершенно не требует быстрой реакции. Вы для начала разберитесь с простейшей логикой, чтобы код работал правильно - а потом, если захотите, можете и прерывание подтянуть.
Да ну вас, тут разговоров не о чем - сначала простую программу написать, а затем украшательства, 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; } }Делайте по частям.
Часть первая - засечь повышенный уровень громкости и засечь начало цикла, сохранив значение millis() в переменной. Применяйте переменную-защелку (флаг), чтобы засечь только один раз.
Часть вторая - засечь "тишину", сохранив значение millis() в переменную конца цикла. Вывести разницу между началом цикла и его концом один раз. Снова примените переменную-защелку (вторую).
Да ну вас, тут разговоров не о чем - сначала простую программу написать, а затем украшательства, 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). Хотя микрофон настроен на максимальную чувствительность (светодиод микрофона чуть подсвечивает даже в тишине).
Код немного доработал, теперь получается поддерживать постоянно включенным первый светодиод, через 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); }Код немного доработал, теперь получается поддерживать постоянно включенным первый светодиод, через 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); } }У меня такой же датчик звука, только плата синего цвета. Он хорошо работает. На выходе у него сигнал низкого уровня (0) когда говоришь громко и высокого уровня (1) когда тишина. Чуствительность на громкость звука регулируется переменным резистором (синий такой кубик на плате). Настроить желаемую можно подав питание на датчик, вращая резистор, подавая звуки и глядя на сигнальный светодиод. И это без Ардуино. Вообще датчик имеет только два состояния по выходу.
Скорее всего у тебя цифровой, а у меня аналоговый.
Скорее всего у тебя цифровой, а у меня аналоговый.
А где такой купил? Дай ссылку, посмотреть. А то с аналоговым тоже хочется попробовать.
Скорее всего у тебя цифровой, а у меня аналоговый.
А где такой купил? Дай ссылку, посмотреть. А то с аналоговым тоже хочется попробовать.
Покупал не я, одолжил у товарища. Боюсь здесь нельзя кидать ссылку (посчитают за рекламу), поищи на али, думаю без проблем найдешь.
Тут пожалуй забыли про частоту, сколько может выдать наша глотка? ;) необходимо поставить на входе R/C цепочку, тогда уровень сигнала после апроксимации будет более стабильнее. Но это как вариант, второй - вариант - постоянно контролировать АЦП (ну к примеру) если уровень (max) появляется каждые ХХ мСек. вот тогда и держим в true переменную(булеан).
Тут пожалуй забыли про частоту, сколько может выдать наша глотка? ;) необходимо поставить на входе R/C цепочку, тогда уровень сигнала после апроксимации будет более стабильнее. Но это как вариант, второй - вариант - постоянно контролировать АЦП (ну к примеру) если уровень (max) появляется каждые ХХ мСек. вот тогда и держим в true переменную(булеан).
Это которая интегрирующая ?
Осталось только рассчитать номиналы деталек..
Осталось только рассчитать номиналы деталек..
Если никто не снял про это мультик, тогда бида!, бида!
также есть 12 светодидов. Человек кричит в микрофон, если кричит на протяжении 2 секунд = загорается первый светодиод, если 4 секунды = загорается 2 светодиод. К 24 секунде должны загореться все 12 светодиодов. Пробовал и так и эдак, и через analogRead() и через прерывание. Пока получается зажечь криком только один светодиод ..
Никто так и не обратил внимание, подскажу: Автор, ты ДВАДЦАТЬ ЧЕТЫРЕ секунды пробовал кричать в микрофон НЕПРЕРЫВНО? :)
Посидел за кодом, повникал. Спасибо ребятам за дельные советы. В итоге получился код следующего содержания:
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); } }Надо будет ещё оптимизировать (особенно с перечислением портов), а так в целом поставленную задачу решает.