Диктофон Ардуино с активацией по голосу
- Войдите на сайт для отправки комментариев
Всем привет!
Делаю диктофон на ардуино. Микрофон - MAX4466, подключен к любому аналоговому пину (А1), TL431 к AREF и по SPI подключена MicroSD.
Скетч:
/*
This sketch demonstrates recording of standard WAV files that can be played on any device that supports WAVs. The recording
uses a single ended input from any of the analog input pins. Uses AVCC (5V) reference currently.
Requirements:
Class 4 or 6 SD Card
Audio Input Device (Microphone, etc)
Arduino Uno,Nano, Mega, etc.
Steps:
1. Edit pcmConfig.h
a: On Uno or non-mega boards, #define buffSize 128. May need to increase.
b: Uncomment #define ENABLE_RECORDING and #define BLOCK_COUNT 10000UL
2. Usage is as below. See https://github.com/TMRh20/TMRpcm/wiki/Advanced-Features#wiki-recording-a... for
additional informaiton.
Notes: Recording will not work in Multi Mode.
Performance is very dependant on SD write speed, and memory used.
Better performance may be seen using the SdFat library. See included example for usage.
Running the Arduino from a battery or filtered power supply will reduce noise.
*/
#include <SD.h>
#include <SPI.h>
#include <TMRpcm.h>
#include <EEPROM.h>
#define SD_ChipSelectPin 10 //
#define ledStart 2 /* PIN LED Start */
#define ledStop 3 /* PIN LED Stop */
#define MicPin A1 /* PIN LED Stop */
char NameRecord[10]; // Имя нового - записываемого файла на SD-карту
int RecordNumber; // Номер записи - храним в EEPROM. в диапазоне от 0 до 32767
byte Recording = 0; // Переменная определяет идет сейчас запись или нет
int RecInterval = 5; // Минимальная продолжительность записи в секундах
unsigned long TimeInterval = 0; // Переменная для вычисления времени
int MaxAnalogPinValue = 1000; // Уровень сигнала на аналоговом входе при котором произойдет старт записи
//
TMRpcm audio; // create an object for use in this sketch
void setup() {
Serial.begin(9600);
pinMode(ledStart, OUTPUT);
pinMode(ledStop, OUTPUT);
//pinMode(14, OUTPUT); //A0
//pinMode(16, OUTPUT); //A2
//digitalWrite(14, LOW);
//digitalWrite(16, LOW);
audio.speakerPin = 11; //5,6,11 or 46 on Mega, 9 on Uno, Nano, etc
pinMode(10,OUTPUT); //Pin pairs: 9,10 Mega: 5-2,6-7,11-12,46-45
if (!SD.begin(SD_ChipSelectPin)) {
digitalWrite(ledStop, LOW);
digitalWrite(ledStart, LOW);
return;
}else{
digitalWrite(ledStop, LOW);
digitalWrite(ledStart, HIGH);
}
analogReference(EXTERNAL);
// The audio library needs to know which CS pin to use for recording
audio.CSPin = SD_ChipSelectPin;
RecordNumber = EEPROM.read(0);
RecInterval = RecInterval * 1000;
}
void loop() {
if (Recording == 0){
int AnR = analogRead(MicPin);
if (AnR >= MaxAnalogPinValue) {
Serial.println(1);
StartRec();
}
}
if (Recording == 1 && millis() - TimeInterval >= RecInterval) {
if (analogRead(MicPin) < MaxAnalogPinValue) {
StopRec();
Serial.println(2);
}else{
TimeInterval = millis()-1;
Serial.println(3);
}
}
}
void StartRec() { // begin recording process
Recording = 1;
digitalWrite(ledStop, HIGH);
digitalWrite(ledStart, LOW);
RecordNumber++;
if (RecordNumber > 32766)RecordNumber = 0; // небольшое огриничение в номерации файлов
EEPROM.write(0, RecordNumber); // Сохранение в EEPROM номера последнего аудиофайла
TimeInterval = millis(); // Запоминаем millis для отсчета времени записи
sprintf(NameRecord,"%d.wav", RecordNumber); // создаем название файла из номера и расширения ".wav"
audio.startRecording(NameRecord, 16000, MicPin, 0);// Старт записи
}
void StopRec() { // stop recording process, close file
audio.stopRecording(NameRecord);// Стоп записи
digitalWrite(ledStop, LOW);
digitalWrite(ledStart, HIGH);
Recording = 0;
}
Библиотека: https://github.com/TMRh20/TMRpcm
Пытаюсь сделать активацию записи голосом. То есть если превысить звуковой порог - включится запись. Дольше, через определенный интервал проверять наличие звукового сигнала. Это в LOOP прописано в условии:
if (Recording == 1 && millis() - TimeInterval >= RecInterval) {
И если есть звуковой сигнал - то продолжать запись. Если нет, то тогда стоп записи. Вроде должно все работать, но не работает! Проблема в том что после выполнения команды:
audio.startRecording(NameRecord, 16000, MicPin, 0);// Старт записи
обращение к аналоговому пину происходит неправильно! Вместо нормального значения возвращается постоянное и неизменное значение - 840. Из-за этого не срабатывает функция "продления" записи, так как не получает необходимого значения... И из-за этого не стартует новая запись после остановки предыдущей записи. Это можно как-то исправить? Есть какие-то идеи?
А автор кода чего говорит?
Я лишь взял пример из библиотеки:
/* This sketch demonstrates recording of standard WAV files that can be played on any device that supports WAVs. The recording uses a single ended input from any of the analog input pins. Uses AVCC (5V) reference currently. Requirements: Class 4 or 6 SD Card Audio Input Device (Microphone, etc) Arduino Uno,Nano, Mega, etc. Steps: 1. Edit pcmConfig.h a: On Uno or non-mega boards, #define buffSize 128. May need to increase. b: Uncomment #define ENABLE_RECORDING and #define BLOCK_COUNT 10000UL 2. Usage is as below. See <a data-cke-saved-href="https://github.com/TMRh20/TMRpcm/wiki/Advanced-Features#wiki-recording-audio" href="https://github.com/TMRh20/TMRpcm/wiki/Advanced-Features#wiki-recording-audio" rel="nofollow">https://github.com/TMRh20/TMRpcm/wiki/Advanced-Features#wiki-recording-audio</a> for additional informaiton. Notes: Recording will not work in Multi Mode. Performance is very dependant on SD write speed, and memory used. Better performance may be seen using the SdFat library. See included example for usage. Running the Arduino from a battery or filtered power supply will reduce noise. */ #include <SD.h> #include <SPI.h> #include <TMRpcm.h> #define SD_ChipSelectPin 53 //example uses hardware SS pin 53 on Mega2560 //#define SD_ChipSelectPin 4 //using digital pin 4 on arduino nano 328, can use other pins TMRpcm audio; // create an object for use in this sketch void setup() { audio.speakerPin = 11; //5,6,11 or 46 on Mega, 9 on Uno, Nano, etc pinMode(12,OUTPUT); //Pin pairs: 9,10 Mega: 5-2,6-7,11-12,46-45 Serial.begin(115200); if (!SD.begin(SD_ChipSelectPin)) { return; }else{ Serial.println("SD OK"); } // The audio library needs to know which CS pin to use for recording audio.CSPin = SD_ChipSelectPin; } void loop() { if(Serial.available()){ //Send commands over serial to play switch(Serial.read()){ case 'r': audio.startRecording("test.wav",16000,A0); break; //Record at 16khz sample rate on pin A0 case 'R': audio.startRecording("test.wav",16000,A0,1); break; //Record, but with passthrough to speaker. case 't': audio.startRecording("test.wav",16000,A0,2); break; //Do not record. Output direct to speaker //Note: If samples are dropped before writing, it // will not be heard in passthrough mode case 's': audio.stopRecording("test.wav"); break; //Stop recording case 'p': audio.play("test.wav"); break; //Play the recording case '=': audio.volume(1); break; //Increase volume by 1. Does not affect recording case '-': audio.volume(0); break; //Decrease volume by 1. Does not affect recording case 'S': audio.stopPlayback(); break; //Stop all playback } } }И пытаюсь его переделать под управление голосом. Изначально запись стартовала и останавливалась через сериал. Почитал что пишут на Гитхабе.. Библиотека задействует таймеры, настраивает АЦП, и даже отключает его. Вот кусок из библиотеки:
void TMRpcm::stopRecording(char *fileName){ ..... ADCSRA = 0; ADCSRB = 0; ..... }Я решил эту проблему так: сохраняю начальное значения ADCSRA и ADCSRB, и после их восстанавливаю:
void StartRec() { // begin recording process SaveADC1 = ADCSRA; SaveADC2 = ADCSRB; Recording = 1; digitalWrite(ledStop, HIGH); digitalWrite(ledStart, LOW); RecordNumber++; if (RecordNumber > 32766)RecordNumber = 0; // небольшое огриничение в номерации файлов EEPROM.write(0, RecordNumber); // Сохранение в EEPROM номера последнего аудиофайла TimeInterval = millis(); // Запоминаем millis для отсчета времени записи sprintf(NameRecord,"%d.wav", RecordNumber); // создаем название файла из номера и расширения ".wav" audio.startRecording(NameRecord, 16000, MicPin, 0);// Старт записи } void StopRec() { // stop recording process, close file audio.stopRecording(NameRecord);// Стоп записи digitalWrite(ledStop, LOW); digitalWrite(ledStart, HIGH); Recording = 0; ADCSRA = SaveADC1; ADCSRB = SaveADC2; }Это решило проблему с неработающим analogRead().
Осталось только придумать способ правильно "понимать" что речь все еще звучит. Простое
if(analogRead(MicPin) < MaxAnalogPinValue) {Не срабатывает, так как часто "ловит" не самый высокий фронт звуковой волны, из-за чего "думает" что уже тихо, и нет звука...
Я лишь взял пример из библиотеки:
Так я и спрашиваю Вас, что говорит автор примера/библиотеки. Вы его спрашивали?
Я ему описал все, пока что молчит. По поводу работы АЦП уже подымался вопрос: https://github.com/TMRh20/TMRpcm/issues/101
Но автор не стал это включать в библиотеку. Я это исправление использовал в скетче, по этому Старт/стоп стали работать нормально. Сейчас для меня стоит вопрос как правильно считать значение с аналогового входа, так чтобы понять что есть постоянный звук. Ведь звук - колебание. И если просто делать analogRead(MicPin) то легко можно попасть на уровень, не соответствующий заданному, хотя это все равно будет звуковой волной.
Все, проблему решил. Вот полный скетч:
/* This sketch demonstrates recording of standard WAV files that can be played on any device that supports WAVs. The recording uses a single ended input from any of the analog input pins. Uses AVCC (5V) reference currently. Requirements: Class 4 or 6 SD Card Audio Input Device (Microphone, etc) Arduino Uno,Nano, Mega, etc. Steps: 1. Edit pcmConfig.h a: On Uno or non-mega boards, #define buffSize 128. May need to increase. b: Uncomment #define ENABLE_RECORDING and #define BLOCK_COUNT 10000UL 2. Usage is as below. See <a href="https://github.com/TMRh20/TMRpcm/wiki/Advanced-Features#wiki-recording-audio" title="https://github.com/TMRh20/TMRpcm/wiki/Advanced-Features#wiki-recording-audio" rel="nofollow">https://github.com/TMRh20/TMRpcm/wiki/Advanced-Features#wiki-recording-a...</a> for additional informaiton. Notes: Recording will not work in Multi Mode. Performance is very dependant on SD write speed, and memory used. Better performance may be seen using the SdFat library. See included example for usage. Running the Arduino from a battery or filtered power supply will reduce noise. */ #include <SD.h> #include <SPI.h> #include <TMRpcm.h> #include <EEPROM.h> #define ENABLE_DEBUG //Включение вывода отладочной информации через Serial. Только для отладки! Закоментировать эту строку перед заливкой в готовое устройство! #define SD_ChipSelectPin 10 // #define ledStart 2 /* PIN LED Start */ #define ledStop 3 /* PIN LED Stop */ #define MicPin A1 // Аналоговый пин, к которму подключен микрофон char NameRecord[10]; // Имя нового - записываемого файла на SD-карту int RecordNumber; // Номер записи - храним в EEPROM. в диапазоне от 0 до 32767 byte Recording = 0; // Переменная определяет идет сейчас запись или нет //----------------------------------------------- int RecInterval = 5; //! Минимальная продолжительность записи в секундах ! //----------------------------------------------- unsigned long TimeInterval = 0; // Переменная для вычисления времени int MaxAnalogPinValue = 1000; // Уровень сигнала на аналоговом входе при котором произойдет старт записи // Значение подбирается индивидуально! (100 - 1024) int SaveADC1 = 0; int SaveADC2 = 0; unsigned int sample; unsigned int signalMax = 0; unsigned int signalMin = 256; unsigned int peakToPeak = 0; #define peakToPeakMinLevel 100 // Уровень срабатывания на звук. Значение подбирается индивидуально! // Максимальное значение - 255 TMRpcm audio; // create an object for use in this sketch void setup() { #if defined (ENABLE_DEBUG) Serial.begin(9600); #endif pinMode(ledStart, OUTPUT); pinMode(ledStop, OUTPUT); audio.speakerPin = 11; //5,6,11 or 46 on Mega, 9 on Uno, Nano, etc pinMode(10,OUTPUT); //Pin pairs: 9,10 Mega: 5-2,6-7,11-12,46-45 if (!SD.begin(SD_ChipSelectPin)) { digitalWrite(ledStop, LOW); digitalWrite(ledStart, LOW); return; }else{ digitalWrite(ledStop, LOW); digitalWrite(ledStart, HIGH); } analogReference(EXTERNAL); // The audio library needs to know which CS pin to use for recording audio.CSPin = SD_ChipSelectPin; RecordNumber = EEPROM.read(0); RecInterval = RecInterval * 1000; } void loop() { if (Recording == 0){ int AnR = analogRead(MicPin); #if defined (ENABLE_DEBUG) Serial.print("Analog level: "); Serial.println(AnR); #endif if (AnR >= MaxAnalogPinValue) { #if defined (ENABLE_DEBUG) Serial.print("Start recording! File: "); Serial.print(RecordNumber+1); Serial.println(".wav"); #endif StartRec(); } } if (Recording == 1){ sample = ADCH; if (sample < 256) { if (sample > signalMax) { signalMax = sample; // save just the max levels } else if (sample < signalMin) { signalMin = sample; // save just the min levels } } #if defined (ENABLE_DEBUG) Serial.print("Max MIC signal: "); Serial.println(signalMax); #endif if (millis() - TimeInterval >= RecInterval) { peakToPeak = signalMax - signalMin; signalMax = 0; signalMin = 256; #if defined (ENABLE_DEBUG) Serial.print("peakToPeak = "); Serial.println(peakToPeak); #endif if (peakToPeak < peakToPeakMinLevel) { analogRead(MicPin); StopRec(); #if defined (ENABLE_DEBUG) Serial.println("Recording stopped"); #endif }else{ TimeInterval = millis()-1; #if defined (ENABLE_DEBUG) Serial.println("Continue recording..."); #endif } } } } void StartRec() { // begin recording process SaveADC1 = ADCSRA; SaveADC2 = ADCSRB; Recording = 1; digitalWrite(ledStop, HIGH); digitalWrite(ledStart, LOW); RecordNumber++; if (RecordNumber > 32766)RecordNumber = 0; // небольшое огриничение в номерации файлов EEPROM.write(0, RecordNumber); // Сохранение в EEPROM номера последнего аудиофайла TimeInterval = millis(); // Запоминаем millis для отсчета времени записи sprintf(NameRecord,"%d.wav", RecordNumber); // создаем название файла из номера и расширения ".wav" audio.startRecording(NameRecord, 16000, MicPin, 0);// Старт записи } void StopRec() { // stop recording process, close file audio.stopRecording(NameRecord);// Стоп записи digitalWrite(ledStop, LOW); digitalWrite(ledStart, HIGH); Recording = 0; ADCSRA = SaveADC1; ADCSRB = SaveADC2; }