Ардуино - запись звука
Re: Ардуино - запись звука
[uquote="Dimon456",url="/forum/viewtopic.php?p=4244700#p4244700"]Я еще на какой странице про это торочил.[/uquote]Да, про прерывания я видел и полностью поддерживаю.
Решение с прерыванием, кстати, минимизирует потери в скорости. По крайне мере, из AЦП выжмется максимум, оптимизировать придётся лишь обработку данных, успеют обрабатываться - хорошо, не успеют - беда. Всё просто.
Добавлено after 3 minutes 22 seconds:
[uquote="roman.com",url="/forum/viewtopic.php?p=4244701#p4244701"]результат не возвращает.... чтобы не тратить впустую процессорное время.
результат преобразования содержится в регистрах...[/uquote] да ладно? и больше никто ниоткуда к этим регистрам доступа не получит? А использовать while, да ещё с риском вообще никогда не выйти из него с таким-то условием, это не трата процессорного времени впустую? И ещё раз: предложенная Вами функция есть. Это AnalogRead().
Решение с прерыванием, кстати, минимизирует потери в скорости. По крайне мере, из AЦП выжмется максимум, оптимизировать придётся лишь обработку данных, успеют обрабатываться - хорошо, не успеют - беда. Всё просто.
Добавлено after 3 minutes 22 seconds:
[uquote="roman.com",url="/forum/viewtopic.php?p=4244701#p4244701"]результат не возвращает.... чтобы не тратить впустую процессорное время.
результат преобразования содержится в регистрах...[/uquote] да ладно? и больше никто ниоткуда к этим регистрам доступа не получит? А использовать while, да ещё с риском вообще никогда не выйти из него с таким-то условием, это не трата процессорного времени впустую? И ещё раз: предложенная Вами функция есть. Это AnalogRead().
Re: Ардуино - запись звука
кроме вас никто доступа к регистрам не имеет...
в каком случае мы можем застрять в цикле while (ADCSRA & 0b01000000); ?
ADC в AVR соран на простой тупой логике))
в каком случае может зависнуть простая тупая логика ?
я даже себе представить такие случаи не могу... даже чисто гипотетически))
но даже если это каким то непостижимым образом случится... для этого люди придумали сторожевой таймер))
Добавлено after 2 minutes 1 second:
а запускать непрерывное преобразование и потом ловить результаты в прерываниях по окончанию преобразования - это пустая трата времени... и процессорного... и вашего))
в каком случае мы можем застрять в цикле while (ADCSRA & 0b01000000); ?
ADC в AVR соран на простой тупой логике))
в каком случае может зависнуть простая тупая логика ?
я даже себе представить такие случаи не могу... даже чисто гипотетически))
но даже если это каким то непостижимым образом случится... для этого люди придумали сторожевой таймер))
Добавлено after 2 minutes 1 second:
а запускать непрерывное преобразование и потом ловить результаты в прерываниях по окончанию преобразования - это пустая трата времени... и процессорного... и вашего))
Re: Ардуино - запись звука
Я не знаю устройство АЦП в атмеге, но привык просто избегать подобных конструкций. I2C тоже тупая логика, конечный автомат. Прекрасно зависает на таких while. А рассчитывать на сторожевой таймер (который ещё надо включить, настроить, написать пост-обработку события) - круто. Мне попадались устройства, где разработчик так же рассчитывал на наличие кнопки reset. Чтоб ему икалось.
Доступ к регистрам должен быть максимально безопасным. Наверняка в атмеге есть правила их чтения и какие-то блокировки. А может, их можно ещё и сбросить. А Вы предлагаете их читать хрен знает где? И хрен знает когда?
Доступ к регистрам должен быть максимально безопасным. Наверняка в атмеге есть правила их чтения и какие-то блокировки. А может, их можно ещё и сбросить. А Вы предлагаете их читать хрен знает где? И хрен знает когда?
Re: Ардуино - запись звука
в этом вся проблема))Martian писал(а):Я не знаю устройство...
I2C я не использую...
откуда в avr БЛОКИРОВКИ РЕГИСТРОВ ???Martian писал(а):Наверняка в атмеге есть правила их чтения и какие-то блокировки.
//Ст таймер тактируется от отдельного встроенного генератора частотой 1 МГц.Martian писал(а):сторожевой таймер (который ещё надо включить, настроить, написать пост-обработку события) - круто.
//Ст таймер сбрасывается при выключении или во время сброса микроконтроллера.
//WDTCR=0b00001111; // настройка сторожевого таймера:
//0... .... - Зарезервированные
//.0.. .... - Зарезервированные
//..0. .... - Зарезервированные
//...1 .... WDCE - Разрешение изменения сторожевого таймера
//.... 1... WDE - Вкл. сторожевого таймера
//.... .1.. WDP2 - предделитель
//.... ..1. WDP1 - предделитель
//.... ...1 WDP0 - предделитель
////////////////////////////////////////////////////////////////////////////////
//предделитель WDP2 -WDP1 -WDP0:
// 000: количество тактов: 16,384; время переполнения: 16,3 mc
// 001: количество тактов: 32,768; время переполнения: 32,5 mc
// 010: количество тактов: 65,536; время переполнения: 65 mc
// 011: количество тактов: 131,072; время переполнения: 0,13 c
// 100: количество тактов: 262,144; время переполнения: 0,26 c
// 101: количество тактов: 524,288; время переполнения: 0,52 c
// 110: количество тактов: 1.048,576; время переполнения: 1,0 c
// 111: количество тактов: 2.097,152; время переполнения: 2,1 c
////////////////////////////////////////////////////////////////////////////////
//Вкл. ст таймер:
WDTCR=0b00011000; // Разрешение изменения сторожевого таймера
WDTCR=0b00001000; // Вкл. ст таймер
// #asm("wdr") // Сброс сторожевого таймера
////////////////////////////////////////////////////////////////////////////////
//Выкл. ст таймер:
//WDTCR=0b00011000; // Разрешение изменения сторожевого таймера
//WDTCR=0b00000000; // Выкл. ст таймер
настроить ОДИН регистр - это просто безумно сложная задача !))
не вздумайте повторять это дома !
Martian писал(а):написать пост-обработку события
откуда в avr ОБРАБОТЧИК СОБЫТИЙ ???
при срабатывании сторожевого таймера... AVR перезапускает всю программу... читает инструкции из памяти сначала))
Re: Ардуино - запись звука
Ну вот я посмотрел - при чтении ADCL блокируется ADCH на запись. Может, и Вам стоит почитать про атмегу?
Да и про остальное тоже. Вы совершенно не понимаете, про что я гишу. Может быть, конечно, я пишу непонятно...
Но если программа не понимает, что была сброшена ватчдогом - то это либо уровень необходимой надёжности равен миганию светодиодиком, либо в топку такую программу.
Да и про остальное тоже. Вы совершенно не понимаете, про что я гишу. Может быть, конечно, я пишу непонятно...
Re: Ардуино - запись звука
[uquote="Dimon456",url="/forum/viewtopic.php?p=4244700#p4244700"]
Ну нет у меня на этом компе протеуса, что бы проверить с какой скоростью идет семплирование, и ни кто здесь про это не сказал. При последовательной оцифровке двух каналов скорость семплирования в два раза упадет.
olegue, за чем тебе второй канал, куда ты его собрался использовать? Писать во второй файл на карту?
Имей ввиду этот драйвер, на верное, я не смотрел код, не поддерживает работу с двумя открытыми файлами.
Ты так и не ответил на вопрос, рушит ли он файловую систему на карте?[/uquote]
1.Если скорость упадет до величины когда звук станет неприемлиым, то такое конечно , меня не устраивает. Например , я сделал вывод часов на экран 1602 и уже получил артефакты при записи. Данные со второго канала я планировал выводить на экран, ну и писать файл.
2.Да, я хотел писать еще один файл,одновременно со звуком.
3.Я не пробовал открывать второй файл, хотя конечно, надо было бы. (
Но уже понял, что без потерь для звука мне не удасться получить данные со второго канала. К тому же это усложняет проект, вводит его в среду, где я пока сильно плаваю.
Шикарный план.roman.com писал(а):while (ADCSRA & 0b01000000);
Я еще на какой странице про это торочил.Martian писал(а):Нормально - это написать обработчик прерывания АЦП
Ну нет у меня на этом компе протеуса, что бы проверить с какой скоростью идет семплирование, и ни кто здесь про это не сказал. При последовательной оцифровке двух каналов скорость семплирования в два раза упадет.
olegue, за чем тебе второй канал, куда ты его собрался использовать? Писать во второй файл на карту?
Имей ввиду этот драйвер, на верное, я не смотрел код, не поддерживает работу с двумя открытыми файлами.
Ты так и не ответил на вопрос, рушит ли он файловую систему на карте?[/uquote]
1.Если скорость упадет до величины когда звук станет неприемлиым, то такое конечно , меня не устраивает. Например , я сделал вывод часов на экран 1602 и уже получил артефакты при записи. Данные со второго канала я планировал выводить на экран, ну и писать файл.
2.Да, я хотел писать еще один файл,одновременно со звуком.
3.Я не пробовал открывать второй файл, хотя конечно, надо было бы. (
Но уже понял, что без потерь для звука мне не удасться получить данные со второго канала. К тому же это усложняет проект, вводит его в среду, где я пока сильно плаваю.
Re: Ардуино - запись звука
Не факт. на данный момент, между работой ацп и непосредственно записью тратится куча времени на всякое второстепенное и ненужное ожидание. Мне кажется, опрашивать два канала АЦП уж точно возможно быстрее (чаще), чем это делается сейчас. Если что и будет не успевать, так это запись.
Добавлено after 35 minutes 14 seconds:
добавляем две глобальных переменных:
после настройки ацп запускаем его однократно. Ацп настраивается в режим одиночного преобразования. прерывание включается в регистре ADCSRA
пишем обработчик прерывания АЦП:
далее в главном цикле, или таймере или где-то ещё:
примерно так. мухи отдельно, котлеты отдельно, просто и удобно. c механизмом блокирования старшего разряда возможно перемудрил, но, опять же, атмеги - это не моё.
АЦП будет предоставлять данные максимально быстро. Дело лишь за быстрой обработкой их.
Добавлено after 35 minutes 14 seconds:
добавляем две глобальных переменных:
Код: Выделить всё
char sound = -1; //звук с канала 0х61
volatile int nosound = -1; //где что-то с канала 0x60
пишем обработчик прерывания АЦП:
Код: Выделить всё
ISR(ADC_vect)
{
if (bit_is_set(ADMUX,0)) // проверка 0х61
{
sound = ADCH; // сохраняем звук (как я понял, только старший байт берётся)
cbi(ADMUX,0); //переключаем на другой канал
} else {
notsound = ADCL; // сохраняем младший байт результата АЦП, при этом блокируется запись в ADCH
notsound |= (ADCH << 8); // сохраняем старший байт АЦП, тем самым снимая блокировку и получая данные notsound
sbi(ADMUX,0); //переключаем на другой канал
}
sbi(ADCSRA, ADSC); // запуск ADC заново.
} Код: Выделить всё
if (sound >= 0) // в sound ацп что-то сохранило
{
///здесь обработали sound
sound = -1;
}
if (nosound >= 0){
///здесь обработали nosound
nosound = -1;
}
АЦП будет предоставлять данные максимально быстро. Дело лишь за быстрой обработкой их.
Последний раз редактировалось Martian Пн июн 13, 2022 18:19:35, всего редактировалось 2 раза.
Re: Ардуино - запись звука
мне не нужно читать про атмегу...Martian писал(а):Вам стоит почитать про атмегу?
выше писал как надо читать регистры...
[uquote="roman.com",url="/forum/viewtopic.php?p=4242597#p4242597"]нормальные люди сначала пишут младшие регистры...
ADCL = 11111111
а када младшие регистры заполнятся... переносим разряды в старшие регистры...
ADCH = 00000011
при чтении процесс обратный...[/uquote]
регистры не блокируются))
а почему так происходит ? потому шина данных 8-ми битная.))
да потому что AVR 8-ми битный !!!
поэтому при чтении 16-битных регистров чтение происходит поочереди...
сначала читаем первый регистр... по умолчанию младший... после этого значение второго переносится в первый... по умолчанию старший... затем читаем второй регистр...
а если первым читать старший регистр... то значение младшего потеряем...
и т.д. и т.п.
только нафиг нужны кому такие подробности))
читаем сразу оба регистра... ADCW = 00000011 11111111
и не забиваем себе голову такими подробностями))
[uquote="Martian",url="/forum/viewtopic.php?p=4244745#p4244745"]если программа не понимает, что была сброшена ватчдогом.[/uquote]
блин... нафига простому AVR знать чем он был сброшен))) это не Windows... с кодами ошибок))
ну если очень надо... то пишите... если совсем заняться нечем)))
ещё исключения допишите...
try {...} catch (Exception){}
если совсем заняться нечем))
Re: Ардуино - запись звука
roman.com, опять чушь несёте.
Re: Ардуино - запись звука
olegue что ты хочешь... не пойму))
писать два канала сразу ?
кто мешает ?)) делай "переключатель" каналов и пиши сразу два канала))
сделай две функции...
// включаем канал номер 0
void Setup_ADC_0() {
ADMUX = 0x60; // set ADC to read pin A5, ADLAR to 1 (left adjust)
cbi(ADCSRA, ADPS2); // set prescaler to 8 / ADC clock = 2MHz
sbi(ADCSRA, ADPS1);
sbi(ADCSRA, ADPS0);
}
// включаем канал номер 1
void Setup_ADC_1() {
ADMUX = 0x61; // set ADC to read pin A5, ADLAR to 1 (left adjust)
cbi(ADCSRA, ADPS2); // set prescaler to 8 / ADC clock = 2MHz
sbi(ADCSRA, ADPS1);
sbi(ADCSRA, ADPS0);
}
// в прерывании таймера переключаем каналы...
ISR(TIMER2_COMPA_vect) {
recByteCount++; // increment sample counter
bufByteCount++;
if (bufByteCount == 64 && bufWrite == 0) { bufByteCount = 0; bufWrite = 1;
} else if (bufByteCount == 64 & bufWrite == 1) { bufByteCount = 0; bufWrite = 0; }
if (bufWrite == 0) {
Setup_ADC_0(); // включаем канал номер 0
sbi(ADCSRA, ADSC); // start ADC sample
while (bit_is_set(ADCSRA, ADSC)); // wait until ADSC bit goes low = new sample ready
buf00[bufByteCount] = ADCH;
}
if (bufWrite == 1) {
Setup_ADC_1(); // включаем канал номер 1
sbi(ADCSRA, ADSC); // start ADC sample
while (bit_is_set(ADCSRA, ADSC)); // wait until ADSC bit goes low = new sample ready
buf01[bufByteCount] = ADCH;
}
}
чёто намудрили с буферами)))
писать два канала сразу ?
кто мешает ?)) делай "переключатель" каналов и пиши сразу два канала))
сделай две функции...
// включаем канал номер 0
void Setup_ADC_0() {
ADMUX = 0x60; // set ADC to read pin A5, ADLAR to 1 (left adjust)
cbi(ADCSRA, ADPS2); // set prescaler to 8 / ADC clock = 2MHz
sbi(ADCSRA, ADPS1);
sbi(ADCSRA, ADPS0);
}
// включаем канал номер 1
void Setup_ADC_1() {
ADMUX = 0x61; // set ADC to read pin A5, ADLAR to 1 (left adjust)
cbi(ADCSRA, ADPS2); // set prescaler to 8 / ADC clock = 2MHz
sbi(ADCSRA, ADPS1);
sbi(ADCSRA, ADPS0);
}
// в прерывании таймера переключаем каналы...
ISR(TIMER2_COMPA_vect) {
recByteCount++; // increment sample counter
bufByteCount++;
if (bufByteCount == 64 && bufWrite == 0) { bufByteCount = 0; bufWrite = 1;
} else if (bufByteCount == 64 & bufWrite == 1) { bufByteCount = 0; bufWrite = 0; }
if (bufWrite == 0) {
Setup_ADC_0(); // включаем канал номер 0
sbi(ADCSRA, ADSC); // start ADC sample
while (bit_is_set(ADCSRA, ADSC)); // wait until ADSC bit goes low = new sample ready
buf00[bufByteCount] = ADCH;
}
if (bufWrite == 1) {
Setup_ADC_1(); // включаем канал номер 1
sbi(ADCSRA, ADSC); // start ADC sample
while (bit_is_set(ADCSRA, ADSC)); // wait until ADSC bit goes low = new sample ready
buf01[bufByteCount] = ADCH;
}
}
чёто намудрили с буферами)))
Re: Ардуино - запись звука
Martian, Спасибо! Вроде все понятно, ну типа понятно что и куда всадить,а так ,конечно, темный лес. Буду пробовать вечерком.
вот например
if (bit_is_set(ADMUX,1)) // проверка 0х61
как тут происхоит проверка на 0x61, ADMUX это регистр у которого 8 бит , младшие (справа которые, я так понимаю) отвечают за порт с окторого идет оцифровка.
ну и далее тоже
cbi(ADMUX,1); //переключаем на другой канал
не понимаю как мы тут переключаем на другой канал?
вот например
if (bit_is_set(ADMUX,1)) // проверка 0х61
как тут происхоит проверка на 0x61, ADMUX это регистр у которого 8 бит , младшие (справа которые, я так понимаю) отвечают за порт с окторого идет оцифровка.
ну и далее тоже
cbi(ADMUX,1); //переключаем на другой канал
не понимаю как мы тут переключаем на другой канал?
Re: Ардуино - запись звука
не)) не такroman.com писал(а):// в прерывании таймера переключаем каналы...
ISR(TIMER2_COMPA_vect) {
recByteCount++; // increment sample counter
bufByteCount++;
if (bufByteCount == 64 && bufWrite == 0) { bufByteCount = 0; bufWrite = 1;
} else if (bufByteCount == 64 & bufWrite == 1) { bufByteCount = 0; bufWrite = 0; }
if (bufWrite == 0) {
Setup_ADC_0(); // включаем канал номер 0
sbi(ADCSRA, ADSC); // start ADC sample
while (bit_is_set(ADCSRA, ADSC)); // wait until ADSC bit goes low = new sample ready
buf00[bufByteCount] = ADCH;
}
if (bufWrite == 1) {
Setup_ADC_1(); // включаем канал номер 1
sbi(ADCSRA, ADSC); // start ADC sample
while (bit_is_set(ADCSRA, ADSC)); // wait until ADSC bit goes low = new sample ready
buf01[bufByteCount] = ADCH;
}
}
надо отдельную переменную для каналов... ))
char channels = 0; // номер канала
ISR(TIMER2_COMPA_vect) {
if (channels == 0) {Setup_ADC_0();}; // вкл канал номер 0
if (channels == 1) {Setup_ADC_1();}; // вкл канал номер 1
channels++;
if (channels == 2) {channels = 0;}; // вкл канал номер 0
sbi(ADCSRA, ADSC); // start ADC sample
while (bit_is_set(ADCSRA, ADSC)); // wait until ADSC bit goes low = new sample ready
recByteCount++; // increment sample counter
bufByteCount++;
if (bufByteCount == 64 && bufWrite == 0) { bufByteCount = 0; bufWrite = 1;
} else if (bufByteCount == 64 & bufWrite == 1) { bufByteCount = 0; bufWrite = 0; }
if (bufWrite == 0) {
buf00[bufByteCount] = ADCH;
}
if (bufWrite == 1) {
buf01[bufByteCount] = ADCH;
}
}
не... опять не так))
Последний раз редактировалось roman.com Пн июн 13, 2022 15:30:18, всего редактировалось 1 раз.
Re: Ардуино - запись звука
bit_is_set - проверяет, установлен ли бит, то есть, равен ли в каком-то байте (ADMUX) какой-то бит (первый) единице. Я, кстати, ошибся что-то...первый это же нулевой. вот так правильно:
if (bit_is_set(ADMUX,0)) // проверка 0х61
cbi очищает в указанном байте указанный бит, то есть, делает его равным 0. и тоже ошибся, правильно так:
cbi(ADMUX,0);
доподглядывался не разбираясь в чужой код
установкой-очисткой бита в данном случае удобней и быстрее, так как надо переключаться между 0х60 и 0х61, то есть, мы оперируем только последней единичкой. Разумеется, в SetupADC надо изначально присвоить ADMUX полное значение 0х61 или 0х60
Добавлено after 9 minutes 29 seconds:
присваивание sound и nosound -1 позволяет использовать их как флаги сигнализации, что АЦП что-то обработало, а заодно и определение, какой канал был. Притом сравнивает с 0, что ещё добавляет некоторой оптимизации (сравнение с нулём быстрее)
Добавлено after 3 minutes 7 seconds:
olegue, если приведёте полный текущий исходник, который сейчас работает, то я могу попробовать переделать его в новый вариант, Вам останется лишь отладить (убрать мои неизбежные ошибки, как путанье 1и 0 выше... как так?
)
if (bit_is_set(ADMUX,0)) // проверка 0х61
cbi очищает в указанном байте указанный бит, то есть, делает его равным 0. и тоже ошибся, правильно так:
cbi(ADMUX,0);
доподглядывался не разбираясь в чужой код
установкой-очисткой бита в данном случае удобней и быстрее, так как надо переключаться между 0х60 и 0х61, то есть, мы оперируем только последней единичкой. Разумеется, в SetupADC надо изначально присвоить ADMUX полное значение 0х61 или 0х60
Добавлено after 9 minutes 29 seconds:
присваивание sound и nosound -1 позволяет использовать их как флаги сигнализации, что АЦП что-то обработало, а заодно и определение, какой канал был. Притом сравнивает с 0, что ещё добавляет некоторой оптимизации (сравнение с нулём быстрее)
Добавлено after 3 minutes 7 seconds:
olegue, если приведёте полный текущий исходник, который сейчас работает, то я могу попробовать переделать его в новый вариант, Вам останется лишь отладить (убрать мои неизбежные ошибки, как путанье 1и 0 выше... как так?
Re: Ардуино - запись звука
спрашиваете еще...., кто ж от такого откажетсяMartian писал(а):olegue, если приведёте полный текущий исходник, который сейчас работает, то я могу попробовать переделать его
Спойлер
Код: Выделить всё
/* Dmitry OSIPOV. http://www.youtube.com/user/d36073?feature=watch
Arduino Audio Recorder V.1-20160524.
----------------------------------------------------
Arduino Projects: Digital Audio Recorder.
http://apcmag.com/arduino-projects-digital-audio-recorder.htm/
----------------------------------------------------
SD-карту лучше класс 10 и выше.
Питание от батареи или аккумулятора.
Микрофон подключить к pin (A5).
----------------------------------------------------
Download - sketch "Arduino Audio Recorder V.1-20160524"
Библиотеку - SdFat.
Фото.
https://yadi.sk/d/zqi8-L5xruhFq
+ sketch оставлю в комментарии - под видео.
----------------------------------------------------
*/
#include <LiquidCrystal_I2C.h>
#include <SdFat.h> // https://yadi.sk/d/zqi8-L5xruhFq
//#include <EEPROM.h>
#include <RTClib.h>
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
SdFat sd;
SdFile rec;
RTC_DS1307 rtc;
LiquidCrystal_I2C lcd(0x27,20,4); // set the LCD address to 0x27 for a 16 chars and 2 line display
const int chipSelect = 4; /* Поменял на 10-pln */
unsigned long fileSize = 0L;
unsigned long waveChunk = 16;
unsigned int waveType = 1;
unsigned int numChannels = 1;
unsigned long sampleRate = 22050;
unsigned long bytesPerSec = 22050;
unsigned int blockAlign = 1;
unsigned int bitsPerSample = 8;
unsigned long dataSize = 0L;
unsigned long recByteCount = 0L;
unsigned long recByteSaved = 0L;
const int btnStart = 6;
const int btnStop = 5;
const int ledStart = 2;
const int ledStop = 3;
int recPressed = 0;
int stopPressed = 0;
unsigned long oldTime = 0L;
unsigned long newTime = 0L;
byte buf00[64]; // buffer array 1
byte buf01[64]; // buffer array 2
byte byte1, byte2, byte3, byte4;
unsigned int bufByteCount;
byte bufWrite;
unsigned long timer1;
int timer1on = 0;
//----------------------------------------------------
//char NameRecord[4]; /* Имя нового - записываемого файла на SD-карту. */
//int RecordNumber; /* Номер записи - храним в EEPROM. в диапазоне 0..255. */
//char filename[12];
char filename[22];
char foldername[10];
unsigned long timerLCL;
int timerLCLon=0;
unsigned long timerRS;
int timerRSon=0;
int SrV,rsValue, procSrV, SrVmid;
char buffer[16] ;
void setup() { // THIS RUNS ONCE
//
lcd.init();
lcd.backlight();
//lcd.setCursor(3,0);
//lcd.print("Hello, world!");
//
rtc.begin();
//EEPROM.put(0, 20000);
Setup_timer2();
Setup_ADC();
pinMode(10, OUTPUT);
pinMode(ledStart, OUTPUT);
pinMode(ledStop, OUTPUT);
pinMode(btnStop, INPUT_PULLUP);
pinMode(btnStart, INPUT_PULLUP);
if (sd.begin(chipSelect, SPI_FULL_SPEED)) { // initialise card on SPI to 8MHz SPI bus speed
for (int dloop = 0; dloop < 4; dloop++) {
digitalWrite(ledStart, !digitalRead(ledStart));
delay(100);
}
} else {
lcd.setCursor(0,1);
lcd.print("SD Card not found");
// if error, flash LED twice per second, until reset
while (1) {
digitalWrite(ledStart, !digitalRead(ledStart));
delay(500);
}
}
}
void loop() { // THIS RUNS LOTS!
////////////// НАЧИНАЕМ С ОБРАБОТКИ ВХОДА А0 ////////////////////////
// Каждые 100 мс мы накапливаем значения (для усреднения)
if (timerRSon==0){ // запустим таймер для отображения часов
timerRS=millis(); // включим миллис
timerRSon=1;
}
if (timerRSon==1){
if (millis()-timerRS>50)
{
//rsValue=analogRead(A0);
SrV=SrV+rsValue;
timerRSon=0;
}
}
// Каждые 1000 мс мы отображаем усредненное значение
if (timerLCLon==0){ // запустим таймер для отображения часов
timerLCL=millis(); // включим миллис
timerLCLon=1;
}
if (timerLCLon==1){
if (millis()-timerLCL>500)
{
lcd.setCursor(0,0);
SrVmid=SrV/10;
if (SrVmid<125) SrVmid=125; // меньше 125 - это 0%
procSrV=((SrVmid-125)*100)/194; //в % макс -318(320), мин 125, 320-125=195
sprintf(buffer, "Power:%03i (%02i)",SrV/10,procSrV);
lcd.print(buffer);
//Show_time();
timerLCLon=0;
SrV=0;
///////////////////////
}
}
////////////// ЗДЕСЬ УЖЕ ОБРАБОТКА ВХОДА А1 ////////////////////////
if (digitalRead(btnStart) == LOW && recPressed == 0) {
DateTime now = rtc.now();
String strFile,strFolder; //declaring string.
strFolder=String(now.timestamp(DateTime::TIMESTAMP_DATE));
strFolder.replace("-", "");
strFolder.toCharArray(foldername, sizeof(foldername));
sd.mkdir(foldername); // Создаю директорию - пробовал без этого - никак
strFolder.concat("/");
strFile=String(now.timestamp(DateTime::TIMESTAMP_TIME));
strFile.replace(":", "-");
strFile.concat(".wav");
strFolder.concat(strFile);
strFolder.toCharArray(filename, sizeof(filename));
StartRec(); // launch StartRec method
timer1on = 0;
}
else if (digitalRead(btnStart) == HIGH && recPressed == 1 && timer1on == 0)
{
timer1 = millis();
timer1on = 1;
}
else if (digitalRead(btnStart) == LOW && recPressed == 1 && timer1on == 1) {
timer1on = 0;
}
else if (digitalRead(btnStart) == HIGH && recPressed == 1 && timer1on == 1 && (millis() - timer1) > 2000)
{
StopRec(); // launch StopRec method
/* Поэтому (Делаем программную перезагрузку). */
((void (*)())0x0000)(); /* Делаем программную перезагрузку - Arduino */
}
if (recByteCount % 128 == 64 && recPressed == 1) {
rec.write(buf00, 64); // save buf01 to card
recByteSaved += 64;
}
if (recByteCount % 128 == 0 && recPressed == 1) {
rec.write(buf01, 64); // save buf02 to card
recByteSaved += 64;
}
}
void StartRec() { // begin recording process
digitalWrite(ledStart, HIGH);
digitalWrite(ledStop, LOW);
recByteCount = 0;
recByteSaved = 0;
recPressed = 1; // recording button has been pressed
stopPressed = 0;
writeWavHeader();
sbi (TIMSK2, OCIE2A); // enable timer interrupt, start grabbing audio
}
void StopRec() { // stop recording process, update WAV header, close file
cbi (TIMSK2, OCIE2A); // disable timer interrupt
writeOutHeader();
digitalWrite(ledStart, LOW); // turn off recording LED
digitalWrite(ledStop, HIGH); // light stop LED
recPressed = 0;
}
void writeOutHeader() { // update WAV header with final filesize/datasize
rec.seekSet(4);
byte1 = recByteSaved & 0xff;
byte2 = (recByteSaved >> 8) & 0xff;
byte3 = (recByteSaved >> 16) & 0xff;
byte4 = (recByteSaved >> 24) & 0xff;
rec.write(byte1); rec.write(byte2); rec.write(byte3); rec.write(byte4);
rec.seekSet(40);
rec.write(byte1); rec.write(byte2); rec.write(byte3); rec.write(byte4);
rec.close();
}
void dateTime(uint16_t* date, uint16_t* time) {
DateTime now = rtc.now();
// return date using FAT_DATE macro to format fields
*date = FAT_DATE(now.year(), now.month(), now.day());
// return time using FAT_TIME macro to format fields
*time = FAT_TIME(now.hour(), now.minute(), now.second());
}
void writeWavHeader() { // write out original WAV header to file
recByteSaved = 0;
SdFile::dateTimeCallback(dateTime);
////
////
rec.open(filename, O_CREAT | O_TRUNC | O_RDWR); /* Имя нового - записываемого файла на SD-карту. */
rec.write("RIFF");
byte1 = fileSize & 0xff;
byte2 = (fileSize >> 8) & 0xff;
byte3 = (fileSize >> 16) & 0xff;
byte4 = (fileSize >> 24) & 0xff;
rec.write(byte1); rec.write(byte2); rec.write(byte3); rec.write(byte4);
rec.write("WAVE");
rec.write("fmt ");
byte1 = waveChunk & 0xff;
byte2 = (waveChunk >> 8) & 0xff;
byte3 = (waveChunk >> 16) & 0xff;
byte4 = (waveChunk >> 24) & 0xff;
rec.write(byte1); rec.write(byte2); rec.write(byte3); rec.write(byte4);
byte1 = waveType & 0xff;
byte2 = (waveType >> 8) & 0xff;
rec.write(byte1); rec.write(byte2);
byte1 = numChannels & 0xff;
byte2 = (numChannels >> 8) & 0xff;
rec.write(byte1); rec.write(byte2);
byte1 = sampleRate & 0xff;
byte2 = (sampleRate >> 8) & 0xff;
byte3 = (sampleRate >> 16) & 0xff;
byte4 = (sampleRate >> 24) & 0xff;
rec.write(byte1); rec.write(byte2); rec.write(byte3); rec.write(byte4);
byte1 = bytesPerSec & 0xff;
byte2 = (bytesPerSec >> 8) & 0xff;
byte3 = (bytesPerSec >> 16) & 0xff;
byte4 = (bytesPerSec >> 24) & 0xff;
rec.write(byte1); rec.write(byte2); rec.write(byte3); rec.write(byte4);
byte1 = blockAlign & 0xff;
byte2 = (blockAlign >> 8) & 0xff;
rec.write(byte1); rec.write(byte2);
byte1 = bitsPerSample & 0xff;
byte2 = (bitsPerSample >> 8) & 0xff;
rec.write(byte1); rec.write(byte2);
rec.write("data");
byte1 = dataSize & 0xff;
byte2 = (dataSize >> 8) & 0xff;
byte3 = (dataSize >> 16) & 0xff;
byte4 = (dataSize >> 24) & 0xff;
rec.write(byte1); rec.write(byte2); rec.write(byte3); rec.write(byte4);
}
void Setup_timer2() {
TCCR2B = _BV(CS21); // Timer2 Clock Prescaler to : 8
TCCR2A = _BV(WGM21); // Interupt frequency = 16MHz / (8 x 90 + 1) = 22191Hz
OCR2A = 90; // Compare Match register set to 90
}
void Show_time(){
DateTime now = rtc.now();
lcd.setCursor(1, 1);
lcd.print(now.hour());
lcd.print(":");
lcd.print(now.minute());
lcd.print(":");
lcd.print(now.second());
}
void Setup_ADC() {
ADMUX = 0x61; // set ADC to read pin A5, ADLAR to 1 (left adjust)
cbi(ADCSRA, ADPS2); // set prescaler to 8 / ADC clock = 2MHz
sbi(ADCSRA, ADPS1);
sbi(ADCSRA, ADPS0);
}
ISR(TIMER2_COMPA_vect) {
sbi(ADCSRA, ADSC); // start ADC sample
while (bit_is_set(ADCSRA, ADSC)); // wait until ADSC bit goes low = new sample ready
recByteCount++; // increment sample counter
bufByteCount++;
if (bufByteCount == 64 && bufWrite == 0) {
bufByteCount = 0;
bufWrite = 1;
} else if (bufByteCount == 64 & bufWrite == 1) {
bufByteCount = 0;
bufWrite = 0;
}
if (bufWrite == 0) {
buf00[bufByteCount] = ADCH;
}
if (bufWrite == 1) {
buf01[bufByteCount] = ADCH;
}
// if (recByteCount % 128 < 64) { // determine which buffer to store sample into
// buf01[recByteCount % 64] = ADCH;
// } else {
// buf02[recByteCount % 64 ] = ADCH;
// }
}//rsValue=analogRead(A0); - закоментил пока
Добавлено after 19 minutes 8 seconds:
еще вот статью нашел интересную
analogRead() — прощай
https://www.drive2.ru/b/468551383692346485/
надо изучить.
Re: Ардуино - запись звука
Я позволил себе вольность немного переделать всё, и предлагаю пересмотреть усреднение и имитацию таймера для A0, что-то она монструозно выглядит. Что это вообще делает? Что-то на дисплей смотрит выводит?
Обращаю внимание, что остался нерабочий таймер. В него можно впихнуть вызов отображения чего-то на дисплее.
Жду сообщений об ошибках, будем править...
ругается на кучу смайликов, вставлю файлом
Добавлено after 3 minutes 59 seconds:
а, и ещё: теперь частота получения и записи данных не регулируется таймером (его надо выключить, забыл, ща исправлю).
Она определяется скоростью работы АЦП и цикла loop. Если вдруг будет плохо, можно добавить синхронизацию таймером при помощи флага.
Добавлено after 1 minute 34 seconds:
а, хотя пусть там запускает, в старте записи и останавливает по окончании. но не забыть потом выкинуть, если таймер не понадобится.
Добавлено after 6 minutes 9 seconds:
себе что ли "диктофоно-аудио-напоминалку-на-холодильник" такую же собрать, что ли...
Обращаю внимание, что остался нерабочий таймер. В него можно впихнуть вызов отображения чего-то на дисплее.
Жду сообщений об ошибках, будем править...
ругается на кучу смайликов, вставлю файлом
Добавлено after 3 minutes 59 seconds:
а, и ещё: теперь частота получения и записи данных не регулируется таймером (его надо выключить, забыл, ща исправлю).
Она определяется скоростью работы АЦП и цикла loop. Если вдруг будет плохо, можно добавить синхронизацию таймером при помощи флага.
Добавлено after 1 minute 34 seconds:
а, хотя пусть там запускает, в старте записи и останавливает по окончании. но не забыть потом выкинуть, если таймер не понадобится.
Добавлено after 6 minutes 9 seconds:
себе что ли "диктофоно-аудио-напоминалку-на-холодильник" такую же собрать, что ли...
- Вложения
-
- Untitled-1.c
- (12.06 КБ) 71 скачивание
Re: Ардуино - запись звука
Как все сложно
Спойлер
Код: Выделить всё
// Voltage Reference: AVCC pin
#define ADC_VREF_TYPE ((0<<REFS1) | (1<<REFS0) | (1<<ADLAR))
volatile uint8_t sum_adc;
// ADC interrupt service routine
ISR(ADC_vect)
{
static uint8_t count = 0;
static uint8_t temp=0;
static uint32_t temp_adc=0;
if(ADMUX & (1<<MUX0)){
temp = ADCH;
rec.write(temp, 1); // save to card
ADMUX = ADC_VREF_TYPE | (0<<MUX0);//set ch 0
}else{
temp_adc += ADCH;
ADMUX = ADC_VREF_TYPE | (1<<MUX0);//set ch 1
}
if (++count > 127) {
count = 0;
sum_adc = temp_adc>>6;
temp=0;
temp_adc=0;
}
}
void StartRec() { // begin recording process
digitalWrite(ledStart, HIGH);
digitalWrite(ledStop, LOW);
recByteCount = 0;
recByteSaved = 0;
recPressed = 1; // recording button has been pressed
stopPressed = 0;
writeWavHeader();
//sbi (TIMSK2, OCIE2A); // enable timer interrupt, start grabbing audio
ADCSRA |= (1<<ADEN);
}
void StopRec() { // stop recording process, update WAV header, close file
//cbi (TIMSK2, OCIE2A); // disable timer interrupt
ADCSRA &= ~(1<<ADEN);
writeOutHeader();
digitalWrite(ledStart, LOW); // turn off recording LED
digitalWrite(ledStop, HIGH); // light stop LED
recPressed = 0;
}
void Setup_timer2() {
//TCCR2B = _BV(CS21); // Timer2 Clock Prescaler to : 8
//TCCR2A = _BV(WGM21); // Interupt frequency = 16MHz / (8 x 90 + 1) = 22191Hz
//OCR2A = 90; // Compare Match register set to 90
}
void Setup_ADC() {
// ADC initialization
DIDR0=(0<<ADC5D) | (0<<ADC4D) | (0<<ADC3D) | (0<<ADC2D) | (0<<ADC1D) | (0<<ADC0D);
ADMUX= (1<<MUX0) | ADC_VREF_TYPE;
ADCSRA=(0<<ADEN) | (1<<ADSC) | (1<<ADATE) | (0<<ADIF) | (1<<ADIE) | (1<<ADPS2) | (0<<ADPS1) | (1<<ADPS0); // 500kHz
sampleRate = 20000; bytesPerSec = 20000;
//ADCSRA=(0<<ADEN) | (1<<ADSC) | (1<<ADATE) | (0<<ADIF) | (1<<ADIE) | (1<<ADPS2) | (1<<ADPS1) | (0<<ADPS0); // 250kHz
//sampleRate = 9803; bytesPerSec = 9803;
//ADCSRA=(0<<ADEN) | (1<<ADSC) | (1<<ADATE) | (0<<ADIF) | (1<<ADIE) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0); // 125kHz
//sampleRate = 4807; bytesPerSec = 4807;
ADCSRB=(0<<ADTS2) | (0<<ADTS1) | (0<<ADTS0);
}Re: Ардуино - запись звука
дык тоже самое практически. просто я не рискнул переделывать основные механизмы записи у автора, там какие-то буферы, и не уверен, что вызов функций записи из прерывания ацп - хорошая идея.
Re: Ардуино - запись звука
Это по чему?Martian писал(а):и не уверен, что вызов функций записи из прерывания ацп - хорошая идея.
Еще ее и заинлайнить можно. Грубо говоря времени на один байт уйдет что-то около 10мкс.
Не нравится, так, с буферами сделайте.
Re: Ардуино - запись звука
потому что мне неизвестно, сколько там времени она будет работать, успеет ли... Если в прерывании ацп оставить только сбор данных, то становится пофиг, кто и как там чего успевает, не наша уже проблема. Я потому и не захотел бесконечное преобразование запускать, фиг его знает, какой канал в итоге попадёт в данные, где-то мелькало, что может ахинея выйти, но кто его знает, кто там про это писал, мож сам накосячил.
Но в общем-то концепт и Ваш и мой одинаков, надо им идти и Вам надо было настаивать на нём ещё кучу постов назад
Но в общем-то концепт и Ваш и мой одинаков, надо им идти и Вам надо было настаивать на нём ещё кучу постов назад
Re: Ардуино - запись звука
Martian,

чет, я не понял, что ему надо!
ну и еще добавил перед setup()
char notsound;
Добавлено after 8 minutes 9 seconds:
дык нету функции в коде
_write()
Добавлено after 1 minute 50 seconds:
а так это попытка обявить функции в теле другой функуции?
дык тут такое не прокатывает
выношу ее и вызываю
Добавлено after 1 minute 55 seconds:
или не надо вызывать, там она вызывается несколько раз, может только вынести ?
Добавлено after 5 minutes 46 seconds:

так пойдет или задумывалось по другому?
или убрать лишний вызов _write()
Добавлено after 5 minutes 17 seconds:
Ошибок компиляции нету, вкидываю в прошивку в МК. Буду смотреть че будет.
Добавлено after 6 minutes 44 seconds:
не пишет звук
пробую что-то записать- дает вот тайкой файл и светодиод (у меня красный-индикатор записи) - горит постоянно.

Добавлено after 3 minutes 39 seconds:
вот код без ошибок компиляции
чет, я не понял, что ему надо!
ну и еще добавил перед setup()
char notsound;
Добавлено after 8 minutes 9 seconds:
дык нету функции в коде
_write()
Добавлено after 1 minute 50 seconds:
а так это попытка обявить функции в теле другой функуции?
дык тут такое не прокатывает
выношу ее и вызываю
Добавлено after 1 minute 55 seconds:
или не надо вызывать, там она вызывается несколько раз, может только вынести ?
Добавлено after 5 minutes 46 seconds:
так пойдет или задумывалось по другому?
или убрать лишний вызов _write()
Добавлено after 5 minutes 17 seconds:
Ошибок компиляции нету, вкидываю в прошивку в МК. Буду смотреть че будет.
Добавлено after 6 minutes 44 seconds:
не пишет звук
пробую что-то записать- дает вот тайкой файл и светодиод (у меня красный-индикатор записи) - горит постоянно.
Добавлено after 3 minutes 39 seconds:
вот код без ошибок компиляции
- Вложения
-
- audiorecorder_martian.arduino.txt
- (11.1 КБ) 63 скачивания