Ардуино - запись звука

Обсуждаем контроллеры компании Atmel.
roman.com
Друг Кота
Сообщения: 9147
Зарегистрирован: Вт мар 13, 2012 12:16:13
Откуда: .ru

Re: Ардуино - запись звука

Сообщение roman.com »

olegue писал(а):было бы неплохо если бы ко-то подробно прокоментировал строки из моего кода
:o
Справочник > Библиотеки > Sdfat

https://www.arduino.cc/reference/en/libraries/sdfat/

цитата
"Обеспечивает доступ к картам памяти SD.
Библиотека SdFat поддерживает файловые системы FAT16, FAT32 и exFAT на стандартных картах SD, SDHC и SDXC."

можете скачать последнюю версию тут... https://downloads.arduino.cc/libraries/ ... -2.1.2.zip
или посмотреть код на github тут... https://github.com/greiman/SdFat
:roll:

Добавлено after 23 minutes 9 seconds:
Morroc писал(а):Куда подробнее еще...
Надо ещё подробнее !!! :kill:

Разбираем код Ардуино... подробно))
:)))
Arduino Audio Recorder.txt
(8.24 КБ) 112 скачиваний
1.
Библиотека SdFat поддерживает файловые системы FAT16, FAT32 и exFAT на стандартных картах SD, SDHC и SDXC."
Об этом я писал выше...

а чтобы после наших издевательств мы могли вставить флешку в ПК и прочитать что мы там записали... нам нужно писать на флешку не просто по секторам... а писать согласно файловой системе... FAT32... FAT16... и т.д.)) а для этого надо писать отдельную функцию - работа с файловой системой...

https://cxem.net/mc/mc435.php

Библиотека SdFat поддерживает эту фишку))
:tea:
Morroc
Друг Кота
Сообщения: 19495
Зарегистрирован: Чт фев 20, 2014 18:57:55

Re: Ардуино - запись звука

Сообщение Morroc »

Неудобно с файловой системой работать без буфера как ни крути. Все кластерно-секторное.
"Вся военная пропаганда, все крики, ложь и ненависть исходят от людей, которые на эту войну не пойдут !" / Джордж Оруэлл /
"Война - это,когда за интересы других,гибнут совершенно безвинные люди." / Уинстон Черчилль /
roman.com
Друг Кота
Сообщения: 9147
Зарегистрирован: Вт мар 13, 2012 12:16:13
Откуда: .ru

Re: Ардуино - запись звука

Сообщение roman.com »

2.
вот кусок кода из Ардуино...

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);

что этот кусок кода делает в Ардуино ?
об этом я тоже писал выше...

и на последок... забегая вперёд))
если вдруг... все что мы записали на самодельный диктофон... мы захотим послушать на ПК... в браузере... или на своём любимом плеере... то перед началом записи на флешку мы должны добавить на флешку заголовок... с описанием формата wav...
заголовок wav.txt
(2.26 КБ) 96 скачиваний
браузеры... или любые плееры... сначала читают заголовки... а потом читают wav поток...
заголовок_wav.jpg
(81.6 КБ) 50 скачиваний
теперь разберём код из Ардуино...

Добавлено after 4 minutes 52 seconds:
кусок кода из Ардуино.txt
(2.46 КБ) 75 скачиваний
// заголовок на флешку записали...
// далее переходим непосредственно к записи данных... по 512 байт...
:)

Добавлено after 14 minutes 27 seconds:
[uquote="Morroc",url="/forum/viewtopic.php?p=4242464#p4242464"]Неудобно с файловой системой работать без буфера как ни крути. Все кластерно-секторное.[/uquote]
файловая система нужна для работы ПК...

а моему самодельному плееру...
2.jpg
(84.78 КБ) 46 скачиваний
не нужны никакие заголовки wav)) поэтому я все заголовки wav из своей меги8 удалил... и освободил память меги8 для других задач.

Добавлено after 1 minute 17 seconds:
далее...
[uquote="olegue",url="/forum/viewtopic.php?p=4242446#p4242446"]касающиеся накопления байт в буфере и сброса их на карту.[/uquote]
:roll:

Добавлено after 14 minutes 50 seconds:
запись данных на флешку осуществляется по прерыванию таймера номер 2.

// старт записи

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

}


а вот и сам таймер ))
sbi (TIMSK2, OCIE2A); //enable timer interrupt, start grabbing audio (или по-русски включаем таймер и начинаем захват аудио... по прерыванию таймера номер 2)

// остановка записи

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;

}

а вот и сам таймер ))
cbi (TIMSK2, OCIE2A); // disable timer interrupt (или по-русски отключить прерывание таймера номер 2...)


sbi (TIMSK2, OCIE2A)
cbi (TIMSK2, OCIE2A)
это чё такое... типа ассемблерный вставки... ))
точно))
sbi - установить бит в регистре маски прерывания TIMSK2...
cbi - сбросить бит в регистре маски прерывания TIMSK2...
ассемблер.jpg
(101.98 КБ) 47 скачиваний
Ардуина на Ассемблере !!!
Это круто!!! ))
:)

Добавлено after 7 minutes 12 seconds:
// настройки таймера номер 2
// тут мы устанавливаем скорость записи/чтения данный на флешку...

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

}

// настройки ADC
// тут мы устанавливаем режим работы ADC

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);
}

// а вот обработчик прерывания таймера номер 2.
// тут мы читаем данные из ADC и записываем данные в буфер... для последующей записи на флешку...

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 == 386 && bufWrite == 0) {
bufByteCount = 0;
bufWrite = 1;
} else if (bufByteCount == 386 & bufWrite == 1) {
bufByteCount = 0;
bufWrite = 0;
}

if (bufWrite == 0) {
buf00[bufByteCount] = ADCH;
}
if (bufWrite == 1) {
buf01[bufByteCount] = ADCH;
}
Аватара пользователя
olegue
Собутыльник Кота
Сообщения: 2977
Зарегистрирован: Сб май 21, 2016 11:04:52
Откуда: Беларусь

Re: Ардуино - запись звука

Сообщение olegue »

if (recByteCount % 1024 == 512 && recPressed == 1) {
rec.write(buf00, 512); // save buf01 to card
recByteSaved += 512;
}
if (recByteCount % 1024 == 0 && recPressed == 1) {
rec.write(buf01, 512); // save buf02 to card
recByteSaved += 512;
}

строка rec.write rec.write(buf00, 512) должна обязательно по 512 байт буфер на карту ложить? а если напишем 400, то сектор будет недописан данными и следущий начнется заново? т.е в данных будет перерыв на 112 байт?
Morroc
Друг Кота
Сообщения: 19495
Зарегистрирован: Чт фев 20, 2014 18:57:55

Re: Ардуино - запись звука

Сообщение Morroc »

[uquote="roman.com",url="/forum/viewtopic.php?p=4242470#p4242470"]файловая система нужна для работы ПК...[/uquote]
Все равно придется придумать какую то простенькую вроде тех, что были на спектруме/бк - номер файла, время и т.п., придумать что делать после заполнения флэшки (как удалить что то ненужное, не снося остальное).
"Вся военная пропаганда, все крики, ложь и ненависть исходят от людей, которые на эту войну не пойдут !" / Джордж Оруэлл /
"Война - это,когда за интересы других,гибнут совершенно безвинные люди." / Уинстон Черчилль /
roman.com
Друг Кота
Сообщения: 9147
Зарегистрирован: Вт мар 13, 2012 12:16:13
Откуда: .ru

Re: Ардуино - запись звука

Сообщение roman.com »

Morroc писал(а):Все равно придется придумать какую то простенькую
не обязательно)) это по желанию )) мы можем просто читать/писать на флешку непрерывный поток... всё подряд...
а потом можем найти что угодно... по номеру сектора... или тупо по начальному адреса...
или вообще можем писать всё в кольцевой буфер... по кругу))
короче... мы как угодно можем !!! и нас никто не остановит))
:)))
Аватара пользователя
Ivanoff-iv
Друг Кота
Сообщения: 7077
Зарегистрирован: Пт ноя 11, 2016 05:48:09
Откуда: Сердце Пармы

Re: Ардуино - запись звука

Сообщение Ivanoff-iv »

посмею повториться...
я предлагаю создать дубль функции rec.write(buf, n); (например: rec.write.double(buf, n);) такой, чтобы он каждый элемент массива в SPI отправлял дважды, тогда буфер в 256 элементов полностью запишет сектор.
останется либо воспроизводить вдвое быстрее, либо при воспроизведении игнорировать (не)четные байты (или считать их инйормацией для 2го канала, или младшим разрядом 16 битного числа)

Добавлено after 1 minute 18 seconds:
roman.com писал(а):мы как угодно можем !!! и нас никто не остановит))
ага, сделайте из флешки кассету! :))) :))) :)))
Для тех, кто не учил магию мир полон физики :)
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Аватара пользователя
olegue
Собутыльник Кота
Сообщения: 2977
Зарегистрирован: Сб май 21, 2016 11:04:52
Откуда: Беларусь

Re: Ардуино - запись звука

Сообщение olegue »

не, без файловой системы - это не дело. Ну я тут немного разобрался. Перспективы так себе

Ivanoff-iv писал(а):можно заявить стерео (или 16 бит запись) но данные передавать или по 2 раза одинаковые или через байт слать 0, тогда буфера потребуются не по 512, а по 256 байт.
Ivanoff-iv писал(а):сделать массив чар[256] а на отправку отправлять инт переменную... 256 интов как-раз будут 512 байт.
Dimon456 писал(а):Но думаю, раз запись звука значит используется АЦП, а раз АЦП значит можно запись на флеш-карту объединить с АЦП и один буфер в 512 байт вообще исключить.
счас обдумываю вот это

Добавлено after 6 minutes 34 seconds:
Ivanoff-iv писал(а):посмею повториться...
я все перечитываю по несколько раз , ищу приемлемыйй для себя вариант
Ivanoff-iv писал(а):я предлагаю создать дубль функции rec.write(buf, n); (например: rec.write.double(buf, n);) такой, чтобы он каждый элемент массива в SPI отправлял дважды, тогда буфер в 256 элементов полностью запишет сектор.
останется либо воспроизводить вдвое быстрее, либо при воспроизведении игнорировать (не)четные байты (или считать их инйормацией для 2го канала, или младшим разрядом 16 битного числа)
не сразу понял, но прикольно
Аватара пользователя
Ivanoff-iv
Друг Кота
Сообщения: 7077
Зарегистрирован: Пт ноя 11, 2016 05:48:09
Откуда: Сердце Пармы

Re: Ардуино - запись звука

Сообщение Ivanoff-iv »

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

Добавлено after 1 minute 17 seconds:
т.е. размер аудиозаписи будет всегда кратен 512 байт
Для тех, кто не учил магию мир полон физики :)
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Аватара пользователя
olegue
Собутыльник Кота
Сообщения: 2977
Зарегистрирован: Сб май 21, 2016 11:04:52
Откуда: Беларусь

Re: Ардуино - запись звука

Сообщение olegue »

А если две функции сделать rec.write, одна будет писать первую часть сектора 256байт, а вторая вторую?

Добавлено after 34 seconds:
и тогда буфур будет 256 байт
Аватара пользователя
Ivanoff-iv
Друг Кота
Сообщения: 7077
Зарегистрирован: Пт ноя 11, 2016 05:48:09
Откуда: Сердце Пармы

Re: Ардуино - запись звука

Сообщение Ivanoff-iv »

да, это тоже возможно, я это тоже предлагал.... отличаться функции будут лишь тем, что одна из функций по завершению массива отправляет команду прожига, а вторая — нет
Для тех, кто не учил магию мир полон физики :)
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
roman.com
Друг Кота
Сообщения: 9147
Зарегистрирован: Вт мар 13, 2012 12:16:13
Откуда: .ru

Re: Ардуино - запись звука

Сообщение roman.com »

[uquote="olegue",url="/forum/viewtopic.php?p=4242487#p4242487"]т.е в данных будет перерыв на 112 байт?[/uquote]
до этого мы ещё не дошли... код библиотеки... сильно большой... ))

мыв делаем самый полный комментарий Ардуины...)) за всю жизнь существования самой Ардуины))
:)))

всё по порядку ))
:tea:

а в каком режиме у нас работает ADC ?
у ADC есть много режимов с работы...
ATmega8-ADC.c
(2.76 КБ) 63 скачивания
А что у нас в Ардуино ?

// настройки ADC
// тут мы устанавливаем режим работы ADC

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);
}

или можно записать так (что одно и то же):

ADMUX = 0b01100001;

//ADMUX
//1... .... REFS1 - опорное напряжение - 0
//.1.. .... REFS0 - опорное напряжение - 1 - AVCC
//..1. .... ADLAR - Выравнивание результата
//...1 .... -
//.... 1... MUX3 - номер канала
//.... .1.. MUX2 - номер канала
//.... ..1. MUX1 - номер канала
//.... ...1 MUX0 - номер канала - ADC0...ADC7 (0000=ADC0)


//.1.. .... REFS0 - опорное напряжение - 1 - AVCC
// т.е. мы все измерения ADC проводим относительно напряжения питания Ардуино = 5 V.

//..1. .... ADLAR - Выравнивание результата
//ADLAR=1
// Выравнивание результата в левую сторону < (8-бит):
// ADCH // 1111 1111 - читать вторым (или первым, тогда последии 2 бит теряем)
// ADCL // 0000 0011 - читать первым

Это не совсем нормально))

я использую режим по умолчанию...

//ADLAR=0
// Выравнивание результата в правую сторону > (10-бит):
// ADCH // 0000 0011 - читать вторым
// ADCL // 1111 1111 - читать первым

Хотя ADLAR не принципиально... работать будет и так и так)) но я лучше буду использовать стандартные настройки ADLAR=0))

// MUX3...MUX0 - номер канала:
// 0000 - ADC0
// 0001 - ADC1
// .................
// 0111 - ADC7

Ардуина использует канал ADC номер 1. Что соответствует пину номер 24...
мега8.jpg
(21.55 КБ) 50 скачиваний
мега328.jpg
(49.68 КБ) 44 скачивания
далее устанавливаем частоту преобразования ADC для Ардуины...

пишем регистр ADCSRA...

//ADCSRA
//1... .... ADEN - 1- вкл ADC. (0-ADC не потребляет мощности)
//.1.. .... ADSC - 1- Старт. При завершении преобразования сбрасывается аппаратно.
//..1. .... ADFR - 1- режим Непрерывного Преобразования.
//...1 .... ADIF - 1- флаг завершения преобразования
-сброс программно.
-для прерывания очищается аппаратно.
//.... 1... ADIE - 1- Разрешение прерывания
//.... .1.. ADPS2 - предделитель
//.... ..1. ADPS1 - предделитель
//.... ...1 ADPS0 - предделитель

для Ардуино написано так :

cbi(ADCSRA, ADPS2); // set prescaler to 8 / ADC clock = 2MHz
sbi(ADCSRA, ADPS1);
sbi(ADCSRA, ADPS0);

по человечески это будет так:

cbi(ADCSRA, ADPS2); // cbi - сбросить бит в регистре ADCSRA
sbi(ADCSRA, ADPS1); // sbi - установить бит в регистре ADCSRA
sbi(ADCSRA, ADPS0); // sbi - установить бит в регистре ADCSRA

Пипец... тут Ассемблер... так и валит))
А может мы весь код Ардуины перепишем на Ассемблер ??
:)))

или можно записать так (что одно и то же):

ADCSRA = 0b00000011;

предделитель ADC:
ADPS2 -ADPS1 -ADPS0
-------------------------------------
// 000: 1 МГц/2=500.000 Hz
// 001: 1 МГц/2=500.000 Hz
// 010: 1 МГц/4=250.000 Hz
// 011: 1 МГц/8=125.000 Hz
// 100: 1 МГц/16=62.500 Hz
// 101: 1 МГц/32=31.250 Hz
// 110: 1 МГц/64=15.625 Hz
// 111: 1 МГц/128=7.812,5 Hz
-------------------------------------

предделитель ADC = 8
тактовая частота Ардуино 16 мгц.
значит... частота преобразования ADC в Ардуино = 16 мгц / 8 = 2 мгц.
:tea:
Аватара пользователя
olegue
Собутыльник Кота
Сообщения: 2977
Зарегистрирован: Сб май 21, 2016 11:04:52
Откуда: Беларусь

Re: Ардуино - запись звука

Сообщение olegue »

[uquote="Ivanoff-iv",url="/forum/viewtopic.php?p=4242522#p4242522"]да, это тоже возможно, я это тоже предлагал.... отличаться функции будут лишь тем, что одна из функций по завершению массива отправляет команду прожига, а вторая — нет[/uquote]

или 2 буфера по 128 байт, пишем попеременно , полный скидываем в буфер 512, который скидываем на карту.
roman.com
Друг Кота
Сообщения: 9147
Зарегистрирован: Вт мар 13, 2012 12:16:13
Откуда: .ru

Re: Ардуино - запись звука

Сообщение roman.com »

далее... таймер 2

// настройки таймера номер 2
// тут мы устанавливаем скорость записи/чтения данный на флешку...

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

}

в каком режиме работает таймер 2 в Ардуине ?
ATmega8-таймер-2-ШИМ.c
(1.35 КБ) 59 скачиваний
TCCR2
//0-WGM20-COM21-COM20-WGM21-CS22-CS21-CS20// режим работы таймера
...
и т.д.
это всё для ATmega8 ))

Значит у нас Ардуина на другой меги... )) ATmega328

TCCR2B = _BV(CS21); // Timer2 Clock Prescaler to : 8

это можно записать так (что одно и то же):
TCCR2B = 0b00000010;

//CS22-CS21-CS20 -предделитель и режим синхронизации:

//предделитель таймер-счетчик 1:
////////////////////////////////////////////////////////////////////////////////////////////
// 001: 1 МГц/1=1.000.000 Hz
// 010: 1 МГц/8=125.000 Hz
// 011: 1 МГц/32=31.350 Hz
// 100: 1 МГц/64=15.625 Hz ---------
// 101: 1 МГц/128=7.812,5 Hz
// 110: 1 МГц/256=3.906,25 Hz
// 111: 1 МГц/1024=976,5625 Hz
///////////////////////////////////////////////////////////////////////////////////////////

//CS21 - это предделитель на 8

значит таймер 2 в Ардуине работает с частотой 16MHz / 8 = 2 МHz

далее...
TCCR2A = _BV(WGM21); // Interupt frequency = 16MHz / (8 x 90 + 1) = 22191Hz

это можно записать так (что одно и то же):
TCCR2A = 0b00000010;

// WGM21 - это режим работы таймера CTC
режим.jpg
(37.65 КБ) 43 скачивания
Временная диаграмма для режима CTC
CTC.jpg
(16.81 КБ) 57 скачиваний
В режиме CTC счетчик сбрасывается до нуля, когда значение счетчика (TCNT) совпадает с OCR2A.
:roll:
OCR2A = 90; // Compare Match register set to 90

это можно записать так (что одно и то же):
OCR2A = 0b01011010;

Значение счетчика (TCNT) увеличивается до тех пор, пока не произойдет совпадение сравнения с OCR2A, а затем счетчик (TCNT) очищается.

поэтому частота прерывания таймера номер 2 = 22222,22222222222 Hz
соответственно время одного прерывания = 0,000045 секунд.
:roll:

именно с такой частотой мы вызываем обработчик прерываний))

// а вот и сам обработчик прерывания таймера номер 2.
// тут мы читаем данные из ADC и записываем данные в буфер... для последующей записи на флешку...

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 == 386 && bufWrite == 0) {
bufByteCount = 0;
bufWrite = 1;
} else if (bufByteCount == 386 & bufWrite == 1) {
bufByteCount = 0;
bufWrite = 0;
}

if (bufWrite == 0) {
buf00[bufByteCount] = ADCH;
}
if (bufWrite == 1) {
buf01[bufByteCount] = ADCH;
}
:)
Аватара пользователя
Ivanoff-iv
Друг Кота
Сообщения: 7077
Зарегистрирован: Пт ноя 11, 2016 05:48:09
Откуда: Сердце Пармы

Re: Ардуино - запись звука

Сообщение Ivanoff-iv »

[uquote="olegue",url="/forum/viewtopic.php?p=4242535#p4242535"]или 2 буфера по 128 байт, пишем попеременно , полный скидываем в буфер 512, который скидываем на карту.[/uquote]абсолютно бесполезно.
тогда лучше просто один буфер на 512, по заполнению отправляй во флеш, когда ацп оцифрует следующий семпл, нулевой байт из массива уже будет на флешке.
Для тех, кто не учил магию мир полон физики :)
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
roman.com
Друг Кота
Сообщения: 9147
Зарегистрирован: Вт мар 13, 2012 12:16:13
Откуда: .ru

Re: Ардуино - запись звука

Сообщение roman.com »

Ivanoff-iv писал(а):когда ацп оцифрует следующий семпл, нулевой байт из массива уже будет на флешке.
не всё так просто))
:tea:
а что мы делаем в обработчике прерывания ?

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 == 386 && bufWrite == 0) {
bufByteCount = 0;
bufWrite = 1;
} else if (bufByteCount == 386 & bufWrite == 1) {
bufByteCount = 0;
bufWrite = 0;
}

if (bufWrite == 0) {
buf00[bufByteCount] = ADCH;
}
if (bufWrite == 1) {
buf01[bufByteCount] = ADCH;
}


// запуск преобразования ADC
//ADCSRA
//1... .... ADEN - 1- вкл ADC. (0-ADC не потребляет мощности)
//.1.. .... ADSC - 1- Старт. При завершении преобразования сбрасывается аппаратно.
//..1. .... ADFR - 1- режим Непрерывного Преобразования.
//...1 .... ADIF - 1- флаг завершения преобразования
// -сброс программно.
// -для прерывания очищается аппаратно.
//.... 1... ADIE - 1- Разрешение прерывания
//.... .1.. ADPS2 - предделитель
//.... ..1. ADPS1 - предделитель
//.... ...1 ADPS0 - предделитель

sbi(ADCSRA, ADSC); // установить бит ADSC в регистре ADCSRA

это можно записать так (что одно и то же):
ADCSRA |= 0b01000000;
//.1.. .... ADSC - 1- Старт. При завершении преобразования сбрасывается аппаратно.

while (bit_is_set(ADCSRA, ADSC)); //
//ждём окончания преобразования ADC...
//.1.. .... ADSC - 1- Старт. При завершении преобразования сбрасывается аппаратно.

а интересно... сколько времени у нас занимает одно преобразование ?

для частоты преобразования ADC = 250.000 Hz время одного преобразования занимает ~57 микросекунды
ADC_250000Hz .jpg
(97.71 КБ) 47 скачиваний
при этом мы считали что обработчик прерывания работает с частотой 8000 Hz
тайминг_ADC_8000.jpg
(105.6 КБ) 55 скачиваний
Но в Ардуино настройки немного другие...

в Ардуино частота преобразования ADC = 2.000.000 Hz
соответственно время одного преобразования в Ардуине занимает ~6 микросекунды

в Ардуино частота прерывания таймера номер 2 = 22222,22222222222 Hz
соответственно время одного прерывания = 0,000045 секунд.

итого:
0,000006 секунды - одно преобразование ADC.
0,000039 секунды - пауза между преобразованиями ADC.

вот если мы уложимся в эти самые 0,000039 секунды между преобразованиями ADC... то тогда мы можем сделать такое:
Ivanoff-iv писал(а):когда ацп оцифрует следующий семпл, нулевой байт из массива уже будет на флешке.
всё дело в таймингах... мы должны в них уложиться))
:)

Добавлено after 13 minutes 40 seconds:
далее...

recByteCount++; // increment sample counter - считаем семплы...
bufByteCount++; // считаем буфер...

if (bufByteCount == 386 && bufWrite == 0) {
bufByteCount = 0;
bufWrite = 1;
} else if (bufByteCount == 386 && bufWrite == 1) { // тут ОШИБКА !!! & вместо && !!! Исправлено))
bufByteCount = 0;
bufWrite = 0;
}


// тут мы выбираем буфер... в который мы будем писать данные ADC...
if (bufWrite == 0) {
buf00[bufByteCount] = ADCH; // будем писать данные ADC в буфер 00
}
if (bufWrite == 1) {
buf01[bufByteCount] = ADCH; // будем писать данные ADC в буфер 01
}

:roll:
а вы уверены в правильности этого кода ?)))

if (bufByteCount == 386 && bufWrite == 0) {
bufByteCount = 0;
bufWrite = 1;

переменную обнулили ))) bufByteCount = 0;

if (bufWrite == 0) {
buf00[bufByteCount] = ADCH;
}

переменную передали в буфер buf00[bufByteCount] )))

а что мы передали в буфер buf00[0] ? Ноль ? ))


в оригинале вроде было так:

if (recByteCount % 1024 < 386) { // determine which buffer to store sample into
buf01[recByteCount % 386] = ADCH;
}

переменную recByteCount передали в буфер buf00[recByteCount] )))

или вам без разницы что передавать в буфер))
:tea:

Добавлено after 23 minutes 48 seconds:
и ещё...

buf00[bufByteCount] = ADCH; // на флешку запишутся СТАРШИЕ 8 бит результат преобразования ADC...

птому что Ардуина использует сдвиг результат преобразования ADC влево...

//..1. .... ADLAR - Выравнивание результата
//ADLAR=1
// Выравнивание результата в левую сторону < (8-бит):
// ADCH // 1111 1111 - читать вторым (или первым, тогда последии 2 бит теряем)
// ADCL // 0000 0011 - читать первым

Это не совсем нормально))

При таком режиме мы потеряем качество звука ))

я использую сдвиг результат преобразования ADC вправо...

/ADLAR=0
// Выравнивание результата в правую сторону > (10-бит):
// ADCH // 0000 0011 - читать вторым
// ADCL // 1111 1111 - читать первым

у меня на флешку запишутся младшие 8 бит...

buf00[bufByteCount] = ADCL; // на флешку запишутся МЛАДШИЕ 8 бит результат преобразования ADC...

а в чём разница ? а разница в отсутствии искажения типа "ступенька" ))

или вам пофигу в каком качестве писать звук на флешку)))
:))

а могу записать и все 10 бит...

buf00[bufByteCount] = ADCW; // на флешку запишутся ВСЕ 10 бит результат преобразования ADC...

тогда у меня будет самое высокое качество записи звука))
:music:

Добавлено after 16 minutes 37 seconds:
[uquote="roman.com",url="/forum/viewtopic.php?p=4242470#p4242470"]sbi (TIMSK2, OCIE2A)
cbi (TIMSK2, OCIE2A)
это чё такое... типа ассемблерный вставки... ))
точно))[/uquote]
нет))
это обычные дефайны))) :)))

#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))

Ассемблера тут и близко нет))
Аватара пользователя
olegue
Собутыльник Кота
Сообщения: 2977
Зарегистрирован: Сб май 21, 2016 11:04:52
Откуда: Беларусь

Re: Ардуино - запись звука

Сообщение olegue »

хотелось бы определенности , что мы называем сэмплом.
Я понимаю что это напряжение измеренное АЦП в единицу времени. Правлиьно?
Dimon456
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Re: Ардуино - запись звука

Сообщение Dimon456 »

roman.com писал(а):Это не совсем нормально))
С чего ты взял?
roman.com писал(а):я использую сдвиг результат преобразования ADC вправо...
плевать куда двигать.
roman.com писал(а):а могу записать и все 10 бит...
а оперативы хватит?
roman.com писал(а):тогда у меня будет самое высокое качество записи звука))
но до 96кГц и глубины 24 бита тебе далеко.
Прячь свои портянки под спойлер, модератор проследи.
roman.com
Друг Кота
Сообщения: 9147
Зарегистрирован: Вт мар 13, 2012 12:16:13
Откуда: .ru

Re: Ардуино - запись звука

Сообщение roman.com »

Dimon456 писал(а):плевать куда двигать.
нормальные люди сначала пишут младшие регистры...
ADCL = 11111111
а када младшие регистры заполнятся... переносим разряды в старшие регистры...
ADCH = 00000011

при чтении процесс обратный...

а всякие умники... могут двигать результаты как им вздумается)) хоть по диагонали !! )) :)))
Dimon456 писал(а):а оперативы хватит?
4 гига оперативы в ПК... на DDR4... мне вполне хватает))
Dimon456 писал(а):но до 96кГц и глубины 24 бита тебе далеко.
на Ардуино ?)) будем... будем... )) как только сделаем сигма-дельта-модулятор :))
olegue писал(а):Я понимаю что это напряжение измеренное АЦП в единицу времени. Правлиьно?

Правлиьно.
:tea:

Добавлено after 6 minutes 48 seconds:
[uquote="roman.com",url="/forum/viewtopic.php?p=4242547#p4242547"]поэтому частота прерывания таймера номер 2 = 22222,22222222222 Hz[/uquote]
не правильно))
мы забыли дописать единичку)) + 1

TCCR2A = _BV(WGM21); // Interupt frequency = 16MHz / (8 x 90 + 1) = 22191Hz

откуда берётся единичка ? када таймер переполнится... то нужен один такт процессора что бы этот таймер обнулить...
CTC.jpg
(16.81 КБ) 42 скачивания
я не стал писать такие подробности... думаю и так все тут уже догадались))
:))
а почему у вас в заголовке WAV написано что частота семплов - unsigned long sampleRate = 22050 Hz;
а таймер у вас работает с частотой семплов - 22191 Hz ????

вы кого хотите обмануть ? плеер ? ))
:tea:
Novice user
Мудрый кот
Сообщения: 1704
Зарегистрирован: Вт янв 05, 2016 10:14:25
Откуда: поселок Мелеуз

Re: Ардуино - запись звука

Сообщение Novice user »

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

Вернуться в «AVR»