Ардуино - запись звука
- Ivanoff-iv
- Друг Кота
- Сообщения: 7077
- Зарегистрирован: Пт ноя 11, 2016 05:48:09
- Откуда: Сердце Пармы
Re: Ардуино - запись звука
можно измерять напряжение не задействуя ацп - при помощи ШИМа и компаратора:
если на выходе компаратора 1 - в OCR добавляем 1 иначе вычитаем.
входы компаратора прицеплены к измеряемому сигналу и к выходу ШИМ (через RC фильтр).
а АЦП пусть звук пишет...
если на выходе компаратора 1 - в OCR добавляем 1 иначе вычитаем.
входы компаратора прицеплены к измеряемому сигналу и к выходу ШИМ (через RC фильтр).
а АЦП пусть звук пишет...
Для тех, кто не учил магию мир полон физики 
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Re: Ардуино - запись звука
roman.com, ниче не понял
Re: Ардуино - запись звука
[uquote="olegue",url="/forum/viewtopic.php?p=4245416#p4245416"]что если я увеличу время преобзования для А0 (напряжене) до 125кгц (делитель 128) - до 8мкс, сняв лишную нагрузку с процессоа, а время преобразования АЦП для звука оставлю тем же. -0.5мкс.[/uquote]
чтобы снять лишнюю нагрузку с процессора... надо не уменьшать частоту ADC, а увеличивать частоту ADC...
чем выше частота ADC, тем быстрей работает ADC ))
а чем быстрей работает ADC, тем меньше время ожидания процессора...
поэтому мы должны установить максимальную частоту для ADC...
максимальная частота ADC - это когда предделитель отключён... ))
ADCSRA = 0b10000000; // вкл. ADC без предделителя.
или так
ADCSRA=0x80; // вкл. 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 - предделитель
в этом случаем ADC будет работать с частотой кварца Ардуино - 16 МГц !
это максимальная частота ADC...))
итого:
надо записать так:
ADCSRA=0x80; // вкл. ADC без предделителя. C частотой кварца Ардуино - 16 МГц
а как это будет на дуратском языке Ардуино... ? ))
[uquote="olegue",url="/forum/viewtopic.php?p=4245416#p4245416"]Хотя я вот все равно не понимаю, если таймер лопатит с частотой 22кгц, то какая разница каким будет время преобразования и как это повлияет на результ оцифровки звука???[/uquote]
тайминги... тайминги... тайминги...
не соблюдение таймингов приводит к срыву синхронизации ! и весь твой код... идёт в разнос))
Добавлено after 1 minute 18 seconds:
[uquote="Ivanoff-iv",url="/forum/viewtopic.php?p=4245434#p4245434"]можно измерять напряжение не задействуя ацп - при помощи ШИМа и компаратора:
если на выходе компаратора 1 - в OCR добавляем 1 иначе вычитаем.
входы компаратора прицеплены к измеряемому сигналу и к выходу ШИМ (через RC фильтр).
а АЦП пусть звук пишет...[/uquote]
давайте сначала разберёмся с таймингами... а потом займёмся вашими самодельными преобразователями))
чтобы снять лишнюю нагрузку с процессора... надо не уменьшать частоту ADC, а увеличивать частоту ADC...
чем выше частота ADC, тем быстрей работает ADC ))
а чем быстрей работает ADC, тем меньше время ожидания процессора...
поэтому мы должны установить максимальную частоту для ADC...
максимальная частота ADC - это когда предделитель отключён... ))
ADCSRA = 0b10000000; // вкл. ADC без предделителя.
или так
ADCSRA=0x80; // вкл. 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 - предделитель
в этом случаем ADC будет работать с частотой кварца Ардуино - 16 МГц !
это максимальная частота ADC...))
итого:
надо записать так:
ADCSRA=0x80; // вкл. ADC без предделителя. C частотой кварца Ардуино - 16 МГц
а как это будет на дуратском языке Ардуино... ? ))
[uquote="olegue",url="/forum/viewtopic.php?p=4245416#p4245416"]Хотя я вот все равно не понимаю, если таймер лопатит с частотой 22кгц, то какая разница каким будет время преобразования и как это повлияет на результ оцифровки звука???[/uquote]
тайминги... тайминги... тайминги...
не соблюдение таймингов приводит к срыву синхронизации ! и весь твой код... идёт в разнос))
Добавлено after 1 minute 18 seconds:
[uquote="Ivanoff-iv",url="/forum/viewtopic.php?p=4245434#p4245434"]можно измерять напряжение не задействуя ацп - при помощи ШИМа и компаратора:
если на выходе компаратора 1 - в OCR добавляем 1 иначе вычитаем.
входы компаратора прицеплены к измеряемому сигналу и к выходу ШИМ (через RC фильтр).
а АЦП пусть звук пишет...[/uquote]
давайте сначала разберёмся с таймингами... а потом займёмся вашими самодельными преобразователями))
Re: Ардуино - запись звука
Ну дак поставь, это я с телефона, а вы (относится ко всем) за компами сидите.Martian писал(а):у меня нет протеуса
От силы 30 мин потормошить протеус и все станет на свои места.
Не поверю что ардуиновский драйвер целиком сектор пишет.
Re: Ардуино - запись звука
а АЦП успеет выполнить преобразование за 1/16 000 000 = 0.0625мкс?
Re: Ардуино - запись звука
шо ? опять ничего не понял ?
))
ну ты же сам пишиш... (пиши комментарии по-русски)
ISR(TIMER2_COMPA_vect) {
// циффруем напряжени с A0
ADMUX = 0x40; // выбираем канал с которого будем цифровать - pin A0
sbi(ADCSRA, ADSC); // запускаем ADC
while (bit_is_set(ADCSRA, ADSC)); // ждём пока ADC закончит работу по оцифровки...
в этом месте программа останавливается...
дальше код программы не выполняется, потому процессор Ардуины ждёт пока ADC закончит работу по оцифровке...
а как долго в этом месте процессор будет ждать пока ADC закончит работу по оцифровке ?
это зависит с какой частотой работает ADC.
чем выше частота ADC, тем быстрей ADC закончит работу по оцифровке...
так понятней или нет ?))

Добавлено after 4 minutes 54 seconds:
[uquote="olegue",url="/forum/viewtopic.php?p=4245448#p4245448"]а АЦП успеет выполнить преобразование за 1/16 000 000 = 0.0625мкс?[/uquote]
можно посчитать вручную)) в даташите сказано что ADC цифрует за 13 тактов...
16 000 000 / 13 = ... мкс
Или около того))
давайте посчитаем))
допустим у нас ADC работает с частотой 250 000 Гц.
за сколько ADC завершит преобразование ?
1/250 000 * 13 = 52 мкс
а теперь давайте проверим наши расчёты в Протеусе))
вот я взял ADC с частотой 250 000 и закинул в Протеус...
протеус ответил - 57 мкс что очень близко с нашими расчётам))
а теперь давайте посчитаем за сколько ADC завершит преобразование с частотой 16 000 000 ?
1/16 000 000 * 13 = 0,812 мкс
а теперь берём ADC с частотой 16 000 000 и закидываем в Протеус...
...

))
ну ты же сам пишиш... (пиши комментарии по-русски)
ISR(TIMER2_COMPA_vect) {
// циффруем напряжени с A0
ADMUX = 0x40; // выбираем канал с которого будем цифровать - pin A0
sbi(ADCSRA, ADSC); // запускаем ADC
while (bit_is_set(ADCSRA, ADSC)); // ждём пока ADC закончит работу по оцифровки...
в этом месте программа останавливается...
дальше код программы не выполняется, потому процессор Ардуины ждёт пока ADC закончит работу по оцифровке...
а как долго в этом месте процессор будет ждать пока ADC закончит работу по оцифровке ?
это зависит с какой частотой работает ADC.
чем выше частота ADC, тем быстрей ADC закончит работу по оцифровке...
так понятней или нет ?))
Добавлено after 4 minutes 54 seconds:
[uquote="olegue",url="/forum/viewtopic.php?p=4245448#p4245448"]а АЦП успеет выполнить преобразование за 1/16 000 000 = 0.0625мкс?[/uquote]
можно посчитать вручную)) в даташите сказано что ADC цифрует за 13 тактов...
16 000 000 / 13 = ... мкс
Или около того))
давайте посчитаем))
допустим у нас ADC работает с частотой 250 000 Гц.
за сколько ADC завершит преобразование ?
1/250 000 * 13 = 52 мкс
а теперь давайте проверим наши расчёты в Протеусе))
вот я взял ADC с частотой 250 000 и закинул в Протеус...
протеус ответил - 57 мкс что очень близко с нашими расчётам))
а теперь давайте посчитаем за сколько ADC завершит преобразование с частотой 16 000 000 ?
1/16 000 000 * 13 = 0,812 мкс
а теперь берём ADC с частотой 16 000 000 и закидываем в Протеус...
...
Re: Ардуино - запись звука
roman.com, дальше...
Добавлено after 6 minutes 9 seconds:
по моеей матиматике получается что такт это 1/16мгц=0.0625мкс
13 тактов *0.0625=0.8125 мкс - минимальное время преобразования
минимальная частота преобразования АДС =1/0.8125=1 230 769 гц
Добавлено after 1 minute 31 second:
тока к чему это привязать пока не понятно
Добавлено after 6 minutes 9 seconds:
по моеей матиматике получается что такт это 1/16мгц=0.0625мкс
13 тактов *0.0625=0.8125 мкс - минимальное время преобразования
минимальная частота преобразования АДС =1/0.8125=1 230 769 гц
Добавлено after 1 minute 31 second:
тока к чему это привязать пока не понятно
- Ivanoff-iv
- Друг Кота
- Сообщения: 7077
- Зарегистрирован: Пт ноя 11, 2016 05:48:09
- Откуда: Сердце Пармы
Re: Ардуино - запись звука
я не пробовал АЦП на таких частотах гонять... не уверен, что там чтото адекватное намеряется...
наверно рекоммендация в д.ш. о частоте тактирования АЦП не с потолка взята
наверно рекоммендация в д.ш. о частоте тактирования АЦП не с потолка взята
Для тех, кто не учил магию мир полон физики 
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Re: Ардуино - запись звука
всё верно.
примерно так и получается...
на самом деле получается чуть-чуть больше тактов... потому что там идёт опрос флага ADC... несколько тактов нужно ещё самому процессору Ардуины... чтобы "подумать"... ))
но мы не будем углубляться в принцип работы процессоров Ардуины)) это уже отдельная тема...

примерно так и получается...
на самом деле получается чуть-чуть больше тактов... потому что там идёт опрос флага ADC... несколько тактов нужно ещё самому процессору Ардуины... чтобы "подумать"... ))
но мы не будем углубляться в принцип работы процессоров Ардуины)) это уже отдельная тема...
Re: Ардуино - запись звука
а преобразование - это процесс измерения и заполнения регистровой пары ADCH и ADCL?
Re: Ардуино - запись звука
[uquote="Ivanoff-iv",url="/forum/viewtopic.php?p=4245480#p4245480"]я не пробовал АЦП на таких частотах гонять... не уверен, что там чтото адекватное намеряется...
наверно рекоммендация в д.ш. о частоте тактирования АЦП не с потолка взята[/uquote]
в даташите рекомендуют не делать частоту ADC больше 200 000 Гц.
иначе это приведёт к неправильным показаниям)))
но нам и не нужно супер точные показания ADC)) мы не собираемся запускать спутники в космос)) мы просто записываем ЗВУК !
на практике... при оцифровке звука... на повышенных частотах ADC... приводит просто к повышенному шуму... из-за всяких переходных процессов ADC...))

Добавлено after 51 second:
[uquote="olegue",url="/forum/viewtopic.php?p=4245475#p4245475"]тока к чему это привязать пока не понятно[/uquote]
к таймеру
Добавлено after 24 seconds:
[uquote="olegue",url="/forum/viewtopic.php?p=4245485#p4245485"]а преобразование - это процесс измерения и заполнения регистровой пары ADCH и ADCL?[/uquote]
да
наверно рекоммендация в д.ш. о частоте тактирования АЦП не с потолка взята[/uquote]
в даташите рекомендуют не делать частоту ADC больше 200 000 Гц.
иначе это приведёт к неправильным показаниям)))
но нам и не нужно супер точные показания ADC)) мы не собираемся запускать спутники в космос)) мы просто записываем ЗВУК !
на практике... при оцифровке звука... на повышенных частотах ADC... приводит просто к повышенному шуму... из-за всяких переходных процессов ADC...))
Добавлено after 51 second:
[uquote="olegue",url="/forum/viewtopic.php?p=4245475#p4245475"]тока к чему это привязать пока не понятно[/uquote]
к таймеру
Добавлено after 24 seconds:
[uquote="olegue",url="/forum/viewtopic.php?p=4245485#p4245485"]а преобразование - это процесс измерения и заполнения регистровой пары ADCH и ADCL?[/uquote]
да
Re: Ардуино - запись звука
а у меня в коде стоит частота АДС -2мгц, то это сделано, что бы можно было хоть как-то хоть что то записать?roman.com писал(а):в даташите рекомендуют не делать частоту ADC больше 200 000 Гц.
Добавлено after 1 minute 22 seconds:
так это больше чем я тут насчитал, как такое возможно?
Добавлено after 4 minutes 49 seconds:olegue писал(а):13 тактов *0.0625=0.8125 мкс - минимальное время преобразования
минимальная частота преобразования АДС =1/0.8125=1 230 769 гц
Вывод: частоту АДС увеличивать нету смысла. Она и так 2мгц. ЗНачит надо дергать таймер. Увеличивать частоту дискретизации, ну типа в итоге это уже будет не частота дискретизатии, фиг пойми что, так подобрать придется так что бы этой частоты хватило чтобы из звук оцифровать и напряжение измерить на одновременно на разных каналах Адсroman.com писал(а):в даташите рекомендуют не делать частоту ADC больше 200 000 Гц.
иначе это приведёт к неправильным показаниям)))
Re: Ардуино - запись звука
сейчас у тебя ADC работает с частотой 2 мгц...
а сколько это по времени ?
1/2 000 000 * 13 = 6,5 мкс
дальше считаем тайминги...
а сколько времени у нас по таймеру ?
1/22000= 45мкс
а мы успеваем за 45 мкс оцифровать всё ?
одно преобразование сделать за 45 мкс успеваем)) поэтому качество звука хорошее))
а два преобразования за 45 мкс мы уже делать не успеваем... )) поэтому звук плохого качества ))
значит... надо дергать таймер)) будем уменьшать частоту таймера...

Добавлено after 24 minutes 55 seconds:
в оригинальной программе частота ADC составляет 2мгц.
значит время преобразования ADC составляет 6,5 мкс.
и всё прекрасно работает))
затем мы добавили второе преобразование...
итого у нас получилось два преобразования 6,5 мкс * 2 = 13 мкс.
мы вышли за пределы таймера 45 мкс.
как вернуться обратно ?)) в пределы таймера 45 мкс ?
можно увеличить частоту ADC с 2 мгц до 16 мгц.
тогда получим одно преобразование 0.8125 мкс
а два преобразования 0.8125 мкс * 2 = 1,625 мкс.
замечательно)) мы вернулись в пределы таймера 45 мкс.
а как частота ADC = 16 мгц отразится на качестве звука ?
а это уже надо проверять на практике))

а сколько это по времени ?
1/2 000 000 * 13 = 6,5 мкс
дальше считаем тайминги...
а сколько времени у нас по таймеру ?
1/22000= 45мкс
а мы успеваем за 45 мкс оцифровать всё ?
одно преобразование сделать за 45 мкс успеваем)) поэтому качество звука хорошее))
а два преобразования за 45 мкс мы уже делать не успеваем... )) поэтому звук плохого качества ))
значит... надо дергать таймер)) будем уменьшать частоту таймера...
Добавлено after 24 minutes 55 seconds:
выводы делать рано... пока всё не посчитаем))olegue писал(а):Вывод: частоту АДС увеличивать нету смысла. Она и так 2мгц. ЗНачит надо дергать таймер.
в оригинальной программе частота ADC составляет 2мгц.
значит время преобразования ADC составляет 6,5 мкс.
и всё прекрасно работает))
затем мы добавили второе преобразование...
итого у нас получилось два преобразования 6,5 мкс * 2 = 13 мкс.
мы вышли за пределы таймера 45 мкс.
как вернуться обратно ?)) в пределы таймера 45 мкс ?
можно увеличить частоту ADC с 2 мгц до 16 мгц.
тогда получим одно преобразование 0.8125 мкс
а два преобразования 0.8125 мкс * 2 = 1,625 мкс.
замечательно)) мы вернулись в пределы таймера 45 мкс.
а как частота ADC = 16 мгц отразится на качестве звука ?
а это уже надо проверять на практике))
Re: Ардуино - запись звука
так может не нужно сразу без делителя. Есть еще промежуточные значения. Поставлю делитель 4. Посмотрю че будут.
Re: Ардуино - запись звука
блин... а форум никто не читает))
никто не заметил ошибку))
на самом деле ADC не может совсем работать без делителя... выше писал...
предделитель 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
----------
даже если мы запишем нули... то частота будет делится на два ))
ADCSRA=0x80; // вкл. ADC с делителем на 2. C частотой кварца Ардуино - 16 МГц / 2 = 8 МГц
8 МГц - это максимальная частота ADC у Ардуины))
как вернуться обратно ?)) в пределы таймера 45 мкс ?
можно увеличить частоту ADC с 2 мгц до 8мгц.
тогда получим одно преобразование 1,625 мкс
а два преобразования 1,625 мкс * 2 = 3,25 мкс.
замечательно)) мы вернулись в пределы таймера 45 мкс.

никто не заметил ошибку))
на самом деле ADC не может совсем работать без делителя... выше писал...
предделитель 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
----------
даже если мы запишем нули... то частота будет делится на два ))
ADCSRA=0x80; // вкл. ADC с делителем на 2. C частотой кварца Ардуино - 16 МГц / 2 = 8 МГц
8 МГц - это максимальная частота ADC у Ардуины))
как вернуться обратно ?)) в пределы таймера 45 мкс ?
можно увеличить частоту ADC с 2 мгц до 8мгц.
тогда получим одно преобразование 1,625 мкс
а два преобразования 1,625 мкс * 2 = 3,25 мкс.
замечательно)) мы вернулись в пределы таймера 45 мкс.
Re: Ардуино - запись звука
О чем вы спорите?
Ниже 100Гц и выше 10кГц не хрена не слышите, ну разве что на хорошую акустику.
А человеческая речь лежит в пределах 300Гц - 3,4кГц.
Ниже 100Гц и выше 10кГц не хрена не слышите, ну разве что на хорошую акустику.
А человеческая речь лежит в пределах 300Гц - 3,4кГц.
Re: Ардуино - запись звука
Dimon456, ща аудиофилы линчуют за такое оскорбление 
Re: Ардуино - запись звука
Martian, пусть выстраиваются в очередь .
Re: Ардуино - запись звука
Ну че сказать, оно работает
Перво-наперво я начал играться с частотой преобразования АЦП выставил делитель 4, ну стало типа 4 мгц. На слух это мало на что повлияло. Решил в итоге снижать битрейт, нашел что ближайшее вниз после 22050 - это 16кгц. Выставил число сравнения 125 в итоге
в заголовке поменял тоже
частота потока стала 8*16000=128кгц вместо 174кгц
Ну вот после этого стало заметно лучше по звуку
Но пока не могу понять что происходит с оцифровкой напряжения. Если ставлю код АЦП измерения напряжения в начало скетца в loop() то выдает адекватные нормальные значения , но начинает сходит с ума во время оцифровки, может прихватывает еще ADCH их оцифровки - я не знаю. А если в прерывание засовываю, то увеличивает значения раза в 2. Я грешу на то что ADCH и ADCL общие и гдето пересекаются. Потому что когда оцифровка звука не работает второй канал показывает на экране правильные результаты.
в итоге вот это
а весь код здесь
Перво-наперво я начал играться с частотой преобразования АЦП выставил делитель 4, ну стало типа 4 мгц. На слух это мало на что повлияло. Решил в итоге снижать битрейт, нашел что ближайшее вниз после 22050 - это 16кгц. Выставил число сравнения 125 в итоге
Код: Выделить всё
void Setup_timer2() {
TCCR2B = _BV(CS21); // Timer2 Clock Prescaler to : 8
TCCR2A = _BV(WGM21); // Interupt frequency = 16MHz / (8 x 125 + 1) = 16000Hz
OCR2A = 125; // Compare Match register set to 125 (было 90) Перешл на 16кгц
}Код: Выделить всё
unsigned long sampleRate = 16000;
unsigned long bytesPerSec = 16000;
unsigned int blockAlign = 1;
unsigned int bitsPerSample = 8;Ну вот после этого стало заметно лучше по звуку
Но пока не могу понять что происходит с оцифровкой напряжения. Если ставлю код АЦП измерения напряжения в начало скетца в loop() то выдает адекватные нормальные значения , но начинает сходит с ума во время оцифровки, может прихватывает еще ADCH их оцифровки - я не знаю. А если в прерывание засовываю, то увеличивает значения раза в 2. Я грешу на то что ADCH и ADCL общие и гдето пересекаются. Потому что когда оцифровка звука не работает второй канал показывает на экране правильные результаты.
в итоге вот это
Код: Выделить всё
ISR(TIMER2_COMPA_vect) {
ADMUX = 0x40; // set ADC to read pin A0, ADLAR to 1 (left adjust)
sbi(ADCSRA, ADSC); // start ADC sample
while (bit_is_set(ADCSRA, ADSC)); // wait until ADSC bit goes low = new sample ready
rsValue=(ADCL|ADCH<<8);
ADMUX = 0x61; // set ADC to read pin A1, ADLAR to 1 (left adjust)
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;
}
а весь код здесь
Спойлер
Код: Выделить всё
/* 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 = 16000;
unsigned long bytesPerSec = 16000;
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);
lcd.setCursor(0,0);
///sprintf(buffer, "Pow:%05i",rsValue);
///lcd.print(buffer);
/////////////
SrV=SrV+rsValue;
timerRSon=0;
}
}
// Каждые 1000 мс мы отображаем усредненное значение
if (timerLCLon==0){ // запустим таймер для отображения часов
timerLCL=millis(); // включим миллис
timerLCLon=1;
}
if (timerLCLon==1){
if (millis()-timerLCL>1000)
{
//lcd.setCursor(0,0);
SrVmid=SrV/20;
if (SrVmid<125) SrVmid=125; // меньше 125 - это 0%
procSrV=((SrVmid-125)*100)/194; //в % макс -318(320), мин 125, 320-125=195
sprintf(buffer, "Power:%04i (%02i)",SrV/20,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 125 + 1) = 16000Hz
OCR2A = 125; // Compare Match register set to 125 (было 90) Перешл на 16кгц
}
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)
sbi(ADCSRA, ADEN); // включить модуль АЦП
//sbi(ADCSRA, ADATE); // Непрерывный режим работы АЦП (это не прокатило) Экран стал пуст
cbi(ADCSRA, ADPS2); // set prescaler to 8 / ADC clock = 2MHz
sbi(ADCSRA, ADPS1);
sbi(ADCSRA, ADPS0);
}
ISR(TIMER2_COMPA_vect) {
ADMUX = 0x40; // set ADC to read pin A0, ADLAR to 1 (left adjust)
sbi(ADCSRA, ADSC); // start ADC sample
while (bit_is_set(ADCSRA, ADSC)); // wait until ADSC bit goes low = new sample ready
rsValue=(ADCL|ADCH<<8);
ADMUX = 0x61; // set ADC to read pin A1, ADLAR to 1 (left adjust)
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;
// }
}
Re: Ардуино - запись звука
Вот не хотят идти по простому пути.olegue писал(а):но кого вы тут ждете? Седьмого пришествия?Код: Выделить всё
while (bit_is_set(ADCSRA, ADSC));А это что такое?Код: Выделить всё
rsValue=(ADCL|ADCH<<8);ну а здесь тогда по чему так?Код: Выделить всё
buf00[bufByteCount] = ADCH;
Вот вам с буферами
Спойлер
Код: Выделить всё
volatile uint8_t sum_adc;
volatile bool n0=0, n1=0;
byte buf00[256]; // buffer array 1
byte buf01[256]; // buffer array 2
// ADC interrupt service routine
ISR(ADC_vect)
{
static uint8_t count = 0;
static uint8_t temp=0;
static uint32_t temp_adc=0;
static uint16_t count_buf = 0;
if(ADMUX & (1<<MUX0)){
temp = ADCH;
if(count_buf < 256) {
buf00[count_buf] = temp;
} else buf01[count_buf - 256] = temp;
if(count_buf == 255) {
n0=0; n1=1;
}
if(++count_buf > 511) {
count_buf=0; n0=1; n1=0;
}
ADMUX = ADC_VREF_TYPE | (0<<MUX0);//set ch 0
}else{
temp_adc += ADCH;
if (++count > ((127))) {
count = 0;
sum_adc = temp_adc>>7;
temp_adc=0;
}
ADMUX = ADC_VREF_TYPE | (1<<MUX0);//set ch 1
}
}
void loop() {
if (n0==0 && n1 == 1) {
rec.write(buf00, 256); // save buf01 to card
n0=0; n1=0;
}
if (n0==1 && n1 == 0) {
rec.write(buf01, 256); // save buf02 to card
n0=0; n1=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();
ADCSRA |= (1<<ADEN);
}
void StopRec() { // stop recording process, update WAV header, close file
ADCSRA &= ~(1<<ADEN);
writeOutHeader();
digitalWrite(ledStart, LOW); // turn off recording LED
digitalWrite(ledStop, HIGH); // light stop LED
recPressed = 0;
}
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 = 19600; bytesPerSec = 19600;
//ADCSRA=(0<<ADEN) | (1<<ADSC) | (1<<ADATE) | (0<<ADIF) | (1<<ADIE) | (1<<ADPS2) | (1<<ADPS1) | (0<<ADPS0); // 250kHz
//sampleRate = 9800; bytesPerSec = 9800;
//ADCSRA=(0<<ADEN) | (1<<ADSC) | (1<<ADATE) | (0<<ADIF) | (1<<ADIE) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0); // 125kHz
//sampleRate = 4900; bytesPerSec = 4900;
ADCSRB=(0<<ADTS2) | (0<<ADTS1) | (0<<ADTS0);
}Код: Выделить всё
if (++count > ((255))) {
count = 0;
sum_adc = temp_adc>>8;
temp_adc=0;
}Соответственно
Код: Выделить всё
static uint8_t count = 0;Код: Выделить всё
static uint16_t count = 0;