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

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

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

olegue писал(а):ну вот в этом месте мне совсем не хватает компетенции, буду разбираться
что тут разбираться))

выше писал...
wav формат поддерживает разные форматы записи... и разный битрейт...
8 бит, моно/ стерео.
16 бит, моно/стерео.

но в конкретно нашем случае (с Ардуино) всё это не имеет значение... Буфер 512 надо писать целиком. )) Потому что так работает библиотека Ардуино)) А как именно работает библиотека Ардуино... мы так и не разобрались...
:tea:
--------------
8 бит, моно. (один канал - 00000000)
00000000
00000000
00000000
...
всего 512 байт.
--------------
8 бит, стерео. (левый канал - 00000000, правый канал - 00000000)
00000000 00000000
00000000 00000000
00000000 00000000
...
всего 512 байт.
--------------
16 бит, моно. (один канал - 00000000 00000000)
00000000 00000000
00000000 00000000
00000000 00000000
...
всего 512 байт.
--------------
16 бит, стерео. (левый канал - 0000000 000000000, правый канал - 00000000 000000000)
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000
...
всего 512 байт.
--------------
и т.д.
:)

я пишу на ПК )) wav формат я переключаю кнопочками))
а так же меняю битрейт... 8000,11025,16000,22050,44100...
причём всё переключается "на ходу"... без остановки записи))

а буфер для записи я выбираю сам...
можно писать весь wav файл целиком...
а можно писать wav файл по одному байту...
2.jpg
(84.78 КБ) 60 скачиваний
на самом деле программа на ПК и программа в Ардуино ничем не отличается))
принцип работы везде одинаковый))
:tea:
Реклама
Друг Кота
Аватара пользователя
Сообщения: 7083
Зарегистрирован: Пт ноя 11, 2016 05:48:09
Откуда: Сердце Пармы

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

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

Сообщение olegue »

Dimon456,
Dimon456 писал(а):К сожалению его кода не видно.
без проблема. Вот код фактически что счас есть буфер 512 байт заменен на 386 для освобождения памяти
в коде где было 512 заменил на 386. Остальное не трогал, в части где касается сэмплирования и сброса на карту.
Спойлер

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

 // Arduino Audio Recorder 


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

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[386]; // buffer array 1
byte buf01[386]; // 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]; 

void setup() { // THIS RUNS ONCE
  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 { // if error, flash LED twice per second, until reset
    while (1) {
      digitalWrite(ledStart, !digitalRead(ledStart));
      delay(500);
    }
  }

}

void loop() { // THIS RUNS LOTS!

 if (digitalRead(btnStart) == LOW && recPressed == 0) {
    /* Записываем в RecordNumber, значение из ячейки №0 EEPROM, и прибавляем 1. */
    /*RecordNumber = EEPROM.read(0) + 1;*/
     if (RecordNumber == 32767)RecordNumber = 0;
/*RecordNumber==RecordNumber+1;*/
       EEPROM.get(0,RecordNumber) ;
       /* Записываем в ячейку №0 EEPROM, увеличенное значение RecordNumber. */
    /*EEPROM.write(0, RecordNumber);*/
    EEPROM.put(0, RecordNumber+1);
   String str;  //declaring string.
    //
   str = String(RecordNumber); //converting integer into a string.
   while (str.length() < 6)
    {
    str = "0" + str;
      }
   str.concat(".wav");
   str.toCharArray(filename, sizeof(filename));
    /*str.toCharArray(NameRecord, 4); //passing the value of the string to the character array.*/
    /*SdFile::dateTimeCallback(dateTime);*/
    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 % 1024 == 386 && recPressed == 1) {
    rec.write(buf00, 386);  // save buf01 to card
    recByteSaved += 386;
  }
  if (recByteCount % 1024 == 0 && recPressed == 1) {
    rec.write(buf01, 386);  // save buf02 to card
    recByteSaved += 386;
  }
}

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;
  // rec.open("rec00000.wav", O_CREAT | O_TRUNC | O_RDWR);
  /*rec.open(NameRecord, O_CREAT | O_TRUNC | O_RDWR); /* Имя нового - записываемого файла на SD-карту. */
  //DateTime now = rtc.now();
   SdFile::dateTimeCallback(dateTime);
   rec.open(filename, O_CREAT | O_TRUNC | O_RDWR); /* Имя нового - записываемого файла на SD-карту. */
   //rec.timestamp(T_CREATE, now.year(), now.month(), now.day(), now.hour(), now.minute(), now.second());
  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 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 == 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;
  }


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

}

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

Скетч использует 16214 байт (50%) памяти устройства. Всего доступно 32256 байт.
Глобальные переменные используют 1745 байт (85%) динамической памяти, оставляя 303 байт для локальных переменных. Максимум: 2048 байт.
Недостаточно памяти, программа может работать нестабильно.
Добавлено after 8 minutes 23 seconds:
roman.com,
Потому что так работает библиотека Ардуино)) А как именно работает библиотека Ардуино... мы так и не разобрались...
которая библиотека? sdfat? Библиотека работы с картой?
Друг Кота
Сообщения: 19496
Зарегистрирован: Чт фев 20, 2014 18:57:55

Сообщение Morroc »

Да, она. Она же вроде секторами пишет.
"Вся военная пропаганда, все крики, ложь и ненависть исходят от людей, которые на эту войну не пойдут !" / Джордж Оруэлл /
"Война - это,когда за интересы других,гибнут совершенно безвинные люди." / Уинстон Черчилль /
Реклама
Эиком - электронные компоненты и радиодетали
Собутыльник Кота
Аватара пользователя
Сообщения: 2977
Зарегистрирован: Сб май 21, 2016 11:04:52
Откуда: Беларусь

Сообщение olegue »

400 байт поставил буфера. 450 - уже не работает.

Добавлено after 2 minutes 52 seconds:
roman.com писал(а):на самом деле программа на ПК и программа в Ардуино ничем не отличается))
принцип работы везде одинаковый))
:tea:
и это именно то что я нифига пока не понимаю

Добавлено after 1 minute 22 seconds:
пробовал что-то искать на ютубе что бы популярно объяснили эту тему. У канала Narod stream есть хороший ролик как зарядить sd card под Atmega8, но его просмотр пока не дал нужного результата.

Добавлено after 1 minute 57 seconds:
было бы неплохо если бы ко-то подробно прокоментировал строки из моего кода , касающиеся накопления байт в буфере и сброса их на карту. Тогда бы у меня появилось хоть какое то представления на нужном мне примере.
Реклама
Друг Кота
Сообщения: 19496
Зарегистрирован: Чт фев 20, 2014 18:57:55

Сообщение Morroc »

Это как принцип рыбалки. "Чего там уметь - наливай да пей" :) Если бы библиотеке ардуины можно было скормить поток данных и пофиг как она его там пишет в фоне, то и тут проблемы не было бы.

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

Сообщение 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 КБ) 129 скачиваний
1.
Библиотека SdFat поддерживает файловые системы FAT16, FAT32 и exFAT на стандартных картах SD, SDHC и SDXC."
Об этом я писал выше...

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

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

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

Сообщение Morroc »

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

Сообщение 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 КБ) 111 скачиваний
браузеры... или любые плееры... сначала читают заголовки... а потом читают wav поток...
заголовок_wav.jpg
(81.6 КБ) 67 скачиваний
теперь разберём код из Ардуино...

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

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

а моему самодельному плееру...
2.jpg
(84.78 КБ) 60 скачиваний
не нужны никакие заголовки 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 КБ) 70 скачиваний
Ардуина на Ассемблере !!!
Это круто!!! ))
:)

Добавлено 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;
}
Собутыльник Кота
Аватара пользователя
Сообщения: 2977
Зарегистрирован: Сб май 21, 2016 11:04:52
Откуда: Беларусь

Сообщение 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 байт?
Друг Кота
Сообщения: 19496
Зарегистрирован: Чт фев 20, 2014 18:57:55

Сообщение Morroc »

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

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

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

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

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

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

Сообщение 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 битного числа)
не сразу понял, но прикольно
Друг Кота
Аватара пользователя
Сообщения: 7083
Зарегистрирован: Пт ноя 11, 2016 05:48:09
Откуда: Сердце Пармы

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

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

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

Сообщение olegue »

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

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

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

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

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

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

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

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

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

// настройки 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 КБ) 63 скачивания
мега328.jpg
(49.68 КБ) 62 скачивания
далее устанавливаем частоту преобразования 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:
Собутыльник Кота
Аватара пользователя
Сообщения: 2977
Зарегистрирован: Сб май 21, 2016 11:04:52
Откуда: Беларусь

Сообщение olegue »

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

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

Сообщение 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 КБ) 78 скачиваний
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 КБ) 59 скачиваний
Временная диаграмма для режима CTC
CTC.jpg
(16.81 КБ) 73 скачивания
В режиме 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;
}
:)
Ответить

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