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

Обсуждаем контроллеры компании Atmel.
Martian
Друг Кота
Сообщения: 12867
Зарегистрирован: Сб дек 18, 2021 19:25:32
Контактная информация:

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

Сообщение Martian »

[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().
roman.com
Друг Кота
Сообщения: 9147
Зарегистрирован: Вт мар 13, 2012 12:16:13
Откуда: .ru

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

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

кроме вас никто доступа к регистрам не имеет...

в каком случае мы можем застрять в цикле while (ADCSRA & 0b01000000); ?

ADC в AVR соран на простой тупой логике))

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

но даже если это каким то непостижимым образом случится... для этого люди придумали сторожевой таймер))

Добавлено after 2 minutes 1 second:
а запускать непрерывное преобразование и потом ловить результаты в прерываниях по окончанию преобразования - это пустая трата времени... и процессорного... и вашего))
Martian
Друг Кота
Сообщения: 12867
Зарегистрирован: Сб дек 18, 2021 19:25:32
Контактная информация:

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

Сообщение Martian »

Я не знаю устройство АЦП в атмеге, но привык просто избегать подобных конструкций. I2C тоже тупая логика, конечный автомат. Прекрасно зависает на таких while. А рассчитывать на сторожевой таймер (который ещё надо включить, настроить, написать пост-обработку события) - круто. Мне попадались устройства, где разработчик так же рассчитывал на наличие кнопки reset. Чтоб ему икалось.

Доступ к регистрам должен быть максимально безопасным. Наверняка в атмеге есть правила их чтения и какие-то блокировки. А может, их можно ещё и сбросить. А Вы предлагаете их читать хрен знает где? И хрен знает когда?
roman.com
Друг Кота
Сообщения: 9147
Зарегистрирован: Вт мар 13, 2012 12:16:13
Откуда: .ru

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

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

Martian писал(а):Я не знаю устройство...
в этом вся проблема))
I2C я не использую...
Martian писал(а):Наверняка в атмеге есть правила их чтения и какие-то блокировки.
откуда в avr БЛОКИРОВКИ РЕГИСТРОВ ??? :))
Martian писал(а):сторожевой таймер (который ещё надо включить, настроить, написать пост-обработку события) - круто.
//Ст таймер тактируется от отдельного встроенного генератора частотой 1 МГц.
//Ст таймер сбрасывается при выключении или во время сброса микроконтроллера.
//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 писал(а):написать пост-обработку события
:o
откуда в avr ОБРАБОТЧИК СОБЫТИЙ ??? :))

при срабатывании сторожевого таймера... AVR перезапускает всю программу... читает инструкции из памяти сначала))
Martian
Друг Кота
Сообщения: 12867
Зарегистрирован: Сб дек 18, 2021 19:25:32
Контактная информация:

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

Сообщение Martian »

Ну вот я посмотрел - при чтении ADCL блокируется ADCH на запись. Может, и Вам стоит почитать про атмегу? :tea:
Да и про остальное тоже. Вы совершенно не понимаете, про что я гишу. Может быть, конечно, я пишу непонятно... :dont_know: Но если программа не понимает, что была сброшена ватчдогом - то это либо уровень необходимой надёжности равен миганию светодиодиком, либо в топку такую программу.
Аватара пользователя
olegue
Собутыльник Кота
Сообщения: 2977
Зарегистрирован: Сб май 21, 2016 11:04:52
Откуда: Беларусь

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

Сообщение olegue »

[uquote="Dimon456",url="/forum/viewtopic.php?p=4244700#p4244700"]
roman.com писал(а):while (ADCSRA & 0b01000000);
Шикарный план.
Martian писал(а):Нормально - это написать обработчик прерывания АЦП
Я еще на какой странице про это торочил.
Ну нет у меня на этом компе протеуса, что бы проверить с какой скоростью идет семплирование, и ни кто здесь про это не сказал. При последовательной оцифровке двух каналов скорость семплирования в два раза упадет.

olegue, за чем тебе второй канал, куда ты его собрался использовать? Писать во второй файл на карту?
Имей ввиду этот драйвер, на верное, я не смотрел код, не поддерживает работу с двумя открытыми файлами.
Ты так и не ответил на вопрос, рушит ли он файловую систему на карте?[/uquote]


1.Если скорость упадет до величины когда звук станет неприемлиым, то такое конечно , меня не устраивает. Например , я сделал вывод часов на экран 1602 и уже получил артефакты при записи. Данные со второго канала я планировал выводить на экран, ну и писать файл.

2.Да, я хотел писать еще один файл,одновременно со звуком.

3.Я не пробовал открывать второй файл, хотя конечно, надо было бы. (

Но уже понял, что без потерь для звука мне не удасться получить данные со второго канала. К тому же это усложняет проект, вводит его в среду, где я пока сильно плаваю.
Martian
Друг Кота
Сообщения: 12867
Зарегистрирован: Сб дек 18, 2021 19:25:32
Контактная информация:

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

Сообщение Martian »

Не факт. на данный момент, между работой ацп и непосредственно записью тратится куча времени на всякое второстепенное и ненужное ожидание. Мне кажется, опрашивать два канала АЦП уж точно возможно быстрее (чаще), чем это делается сейчас. Если что и будет не успевать, так это запись.

Добавлено after 35 minutes 14 seconds:
добавляем две глобальных переменных:

Код: Выделить всё

char sound = -1; //звук с канала 0х61
volatile int nosound = -1; //где что-то с канала 0x60
после настройки ацп запускаем его однократно. Ацп настраивается в режим одиночного преобразования. прерывание включается в регистре ADCSRA

пишем обработчик прерывания АЦП:

Код: Выделить всё

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;
} 
 
примерно так. мухи отдельно, котлеты отдельно, просто и удобно. c механизмом блокирования старшего разряда возможно перемудрил, но, опять же, атмеги - это не моё.

АЦП будет предоставлять данные максимально быстро. Дело лишь за быстрой обработкой их.
Последний раз редактировалось Martian Пн июн 13, 2022 18:19:35, всего редактировалось 2 раза.
roman.com
Друг Кота
Сообщения: 9147
Зарегистрирован: Вт мар 13, 2012 12:16:13
Откуда: .ru

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

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

Martian писал(а):Вам стоит почитать про атмегу?
мне не нужно читать про атмегу...

выше писал как надо читать регистры...
[uquote="roman.com",url="/forum/viewtopic.php?p=4242597#p4242597"]нормальные люди сначала пишут младшие регистры...
ADCL = 11111111
а када младшие регистры заполнятся... переносим разряды в старшие регистры...
ADCH = 00000011

при чтении процесс обратный...[/uquote]
регистры не блокируются))
а почему так происходит ? потому шина данных 8-ми битная.))
да потому что AVR 8-ми битный !!!
поэтому при чтении 16-битных регистров чтение происходит поочереди...
сначала читаем первый регистр... по умолчанию младший... после этого значение второго переносится в первый... по умолчанию старший... затем читаем второй регистр...
а если первым читать старший регистр... то значение младшего потеряем...
и т.д. и т.п.

только нафиг нужны кому такие подробности))
читаем сразу оба регистра... ADCW = 00000011 11111111

и не забиваем себе голову такими подробностями))
:tea:
[uquote="Martian",url="/forum/viewtopic.php?p=4244745#p4244745"]если программа не понимает, что была сброшена ватчдогом.[/uquote]
блин... нафига простому AVR знать чем он был сброшен))) это не Windows... с кодами ошибок)) :))
ну если очень надо... то пишите... если совсем заняться нечем)))

ещё исключения допишите...

try {...} catch (Exception){}

если совсем заняться нечем))
:))
Martian
Друг Кота
Сообщения: 12867
Зарегистрирован: Сб дек 18, 2021 19:25:32
Контактная информация:

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

Сообщение Martian »

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

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

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

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

}

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

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

Сообщение olegue »

Martian, Спасибо! Вроде все понятно, ну типа понятно что и куда всадить,а так ,конечно, темный лес. Буду пробовать вечерком.

вот например

if (bit_is_set(ADMUX,1)) // проверка 0х61

как тут происхоит проверка на 0x61, ADMUX это регистр у которого 8 бит , младшие (справа которые, я так понимаю) отвечают за порт с окторого идет оцифровка.
ну и далее тоже

cbi(ADMUX,1); //переключаем на другой канал

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

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

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

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 раз.
Martian
Друг Кота
Сообщения: 12867
Зарегистрирован: Сб дек 18, 2021 19:25:32
Контактная информация:

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

Сообщение Martian »

bit_is_set - проверяет, установлен ли бит, то есть, равен ли в каком-то байте (ADMUX) какой-то бит (первый) единице. Я, кстати, ошибся что-то...первый это же нулевой. вот так правильно:
if (bit_is_set(ADMUX,0)) // проверка 0х61

cbi очищает в указанном байте указанный бит, то есть, делает его равным 0. и тоже ошибся, правильно так:
cbi(ADMUX,0);
доподглядывался не разбираясь в чужой код :facepalm:

установкой-очисткой бита в данном случае удобней и быстрее, так как надо переключаться между 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 выше... как так? :dont_know: )
Аватара пользователя
olegue
Собутыльник Кота
Сообщения: 2977
Зарегистрирован: Сб май 21, 2016 11:04:52
Откуда: Беларусь

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

Сообщение olegue »

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/

надо изучить.
Martian
Друг Кота
Сообщения: 12867
Зарегистрирован: Сб дек 18, 2021 19:25:32
Контактная информация:

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

Сообщение Martian »

Я позволил себе вольность немного переделать всё, и предлагаю пересмотреть усреднение и имитацию таймера для A0, что-то она монструозно выглядит. Что это вообще делает? Что-то на дисплей смотрит выводит?
Обращаю внимание, что остался нерабочий таймер. В него можно впихнуть вызов отображения чего-то на дисплее.

Жду сообщений об ошибках, будем править...

ругается на кучу смайликов, вставлю файлом

Добавлено after 3 minutes 59 seconds:
а, и ещё: теперь частота получения и записи данных не регулируется таймером (его надо выключить, забыл, ща исправлю).
Она определяется скоростью работы АЦП и цикла loop. Если вдруг будет плохо, можно добавить синхронизацию таймером при помощи флага.

Добавлено after 1 minute 34 seconds:
а, хотя пусть там запускает, в старте записи и останавливает по окончании. но не забыть потом выкинуть, если таймер не понадобится.

Добавлено after 6 minutes 9 seconds:
себе что ли "диктофоно-аудио-напоминалку-на-холодильник" такую же собрать, что ли... :)
Вложения
Untitled-1.c
(12.06 КБ) 71 скачивание
Dimon456
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

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

Сообщение Dimon456 »

Как все сложно
Спойлер

Код: Выделить всё

// 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);
}
Martian
Друг Кота
Сообщения: 12867
Зарегистрирован: Сб дек 18, 2021 19:25:32
Контактная информация:

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

Сообщение Martian »

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

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

Сообщение Dimon456 »

Martian писал(а):и не уверен, что вызов функций записи из прерывания ацп - хорошая идея.
Это по чему?
Еще ее и заинлайнить можно. Грубо говоря времени на один байт уйдет что-то около 10мкс.
Не нравится, так, с буферами сделайте.
Martian
Друг Кота
Сообщения: 12867
Зарегистрирован: Сб дек 18, 2021 19:25:32
Контактная информация:

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

Сообщение Martian »

потому что мне неизвестно, сколько там времени она будет работать, успеет ли... Если в прерывании ацп оставить только сбор данных, то становится пофиг, кто и как там чего успевает, не наша уже проблема. Я потому и не захотел бесконечное преобразование запускать, фиг его знает, какой канал в итоге попадёт в данные, где-то мелькало, что может ахинея выйти, но кто его знает, кто там про это писал, мож сам накосячил.

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

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

Сообщение olegue »

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:
вот код без ошибок компиляции
Вложения
audiorecorder_martian.arduino.txt
(11.1 КБ) 63 скачивания
Ответить

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