Смекни!
smekni.com

Устройство цифровой записи речи цифровой диктофон (стр. 4 из 5)

Если буфер заполнен и остались пустые страницы, то буфер копируется на следующую страницу DataFlash. Так как память была очищена раньше, то данные могут быть записаны без дополнительного стирания.

Если память заполнена, то цикл выполняется, пока нажата кнопка «запись». Любые данные, записанные в то время, когда память уже заполнена, будут потеряны.

Воспроизведение

В процедуре «воспроизведения», содержимое DataFlash считывается и модулируется как 8-разрядная ШИМ на частоте 15.686 Гц. Для достижения большей скорости, данные не читаются напрямую из основной памяти, а передаются в один из двух буферов и затем читаются из буфера. В это время копируется следующая страница памяти в другой буфер. Для ШИМ, 16-разрядный Таймер/Счётчик 1 используется с выходом ШИМ на OC1B. Это описывается в регистре управления Таймера/Счётчика A и B (TCCRA/TCCRB). Для запуска ШИМ с возможной наибольшей частотой, делитель тактовой частоты ШИМ устанавливается в 1.

Когда установка завершена, первая страница копируется в буфер 1, посредством перевода линии #CS в низкое состояние и передачей соответствующих команд в DataFlash. Передача страницы в буфер начинается, когда линия #CS переводится снова в высокое состояние. Когда состояние на выводе Ready/Busy меняется памятью DataFlash на высокое, то это означает, что буфер 1 содержит действительные данные. Затем начинается передача следующей страницы в буфер 2. Так как оба буфера независимы друг от друга, то данные могут всегда читаться из буфера 1, пока DataFlash остаётся занятой копированием данных из второй страницы в буфер 2.

Для чтения байта из буфера, в DataFlash должна быть записана фиктивная величина. Операция записи «ведущего» в SPI «ведомого» приводит к тому, что содержимое его регистра данных SPI (SPDR) будет изменено. После записи фиктивного байта в DataFlash, регистр SPDR микроконтроллера AVR содержит выходные данные из DataFlash.


Рисунок 15. Воспроизведение

Когда значения ШИМ счётчика равно «0», Таймер 1 вызывает прерывание переполнения. Это прерывание используется для синхронизации выходных данных из DataFlash частотой ШИМ. Когда значение из буфера сдвигается в микроконтроллер AVR, цикл выполняется до тех пор, пока Таймер 1 не вызовет прерывание переполнения. Затем данные записываются в выходной регистр сравнения Таймера/Счётчика 1 B (OCR1B), автоматически защёлкивая выход ШИМ, когда счётчик ШИМ достигнет максимального значения (255 для 8-разрядной ШИМ).

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

Если воспроизведена вся память, то все прерывания отключены и Таймер/Счётчик 1 остановлен.


Рисунок 16. Следующая страница в следующий буфер


Рисунок 17. Активный буфер в динамик

Изменение и оптимизация

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

Данные, записанные в DataFlash, полностью соответствуют данным, считанным с АЦП. В случае записи в течение большого промежутка времени или записи стерео сигнала может потребоваться упаковка этих данных.

В этом примере приведены два способа применения флага состояния.

Первый способ – использование глобальной переменной (т.е. переменная «wait» используется в подпрограмме «playback»). Второй способ – использование незадействованного бита в регистре. В подпрограмме «стирания», используется бит ACIS1 (регистра управления и состояния аналогового компаратора (ACSR))для отображения того, что следующими этапом должно быть сохранение новых данных.

Частота выборки равная 15.686 Гц (приблизительно 510 циклов), генерируется с помощью прерывания АЦП и цикла задержки. Она может быть заменена независимым таймером (Таймер/Счётчик 0 или Таймер/Счётчик 2), если он не используется для других целей.

Пример программы на языке C

/* Очистка всех страниц в случае необходимости. Запись данных в буфер 1. Если буфер заполнен,то его содержимое записывается в страницу памяти. Чтение DataFlash через буфер 1 и буфер 2 врегистр данных.*/ #include “io8535.h”#include #include “stdlib.h”#include “dataflash.h” // прототипыvoid setup (void);void erasing (void);void recording (void);void interrupt[ADC_vect] sample_ready (void);void write_to_flash (unsigned char ad_data);void playback (void);void next_page_to_next_buffer (unsigned char active_buffer, unsigned int page_counter);void interrupt[TIMER1_OVF1_vect] out_now(void);void active_buffer_to_speaker (unsigned char active_buffer); // глобальныепеременныеvolatile unsigned char wait = 0; void setup(void){DDRB = 0xBD; // Инициализацияпорта SPI// SCK, MISO, MOSI, CS, LED, WP , RDYBSY, RST// PB7, PB6, PB5, PB4, PB3, PB2 , PB1, PB0// O I O O O O I O// 1 0 1 1 1 1 0 1PORTB = 0xFF; // все выходы в высоком состоянии, на входах нагрузочные резисторы (LED погашен)DDRA = 0x00; // Port A определяется как входPORTA = 0x00;DDRD = 0x10; // Port D определяется как вход (D4: выход) _SEI(); // прерывания разрешены} void erasing(void){unsigned int block_counter = 0;unsigned char temp = 0x80;ACSR |= 0x02; // установка флага, показывающего, что следующим этапом должна быть запись данных // прерывания запрещены, порт SPI включён, «ведущий» режим, первый MSB, 3 режим SPI, Fcl/4SPCR = 0x5C; while (block_counter < 512){PORTB &= ~DF_CHIP_SELECT; // включение DataFlashSPDR = BLOCK_ERASE;while (!(SPSR & temp)); // ожидание завершения передачиSPDR = (char)(block_counter>>3);while (!(SPSR & temp)); // ожиданиезавершенияпередачиSPDR = (char)(block_counter<<5);while (!(SPSR & temp)); // ожидание завершения передачиSPDR = 0x00; // не важноwhile (!(SPSR & temp)); // ожидание завершения передачиPORTB |= DF_CHIP_SELECT; // выключение DataFlash block_counter++;while(!(PINB & 0x02)); // ожиданиеочисткиблока}SPCR = 0x00; //отключение SPI} void recording(void){// прерывания запрещены, порт SPI включён, «ведущий» режим, первый MSB, 3 режим SPI, Fcl/4 SPCR = 0x5C;ADMUX = 0x00; // номер входного вывода АЦП = 0ADCSR = 0xDD; // одиночное АЦ преобразование, fCK/32, старт преобразованияwhile (!(PIND & 8)); // цикл продолжается пока нажата кнопка записи (кнопка 3) ADCSR = 0x00; // выключение АЦПSPCR = 0x00; // выключение SPI} void interrupt[ADC_vect] sample_ready(void){unsigned char count = 0; while (count < 6) count++; // ожиданиевтечениенесколькихцикловADCSR |= 0x40; // стартновогоАЦпреобразованияwrite_to_flash(ADC-0x1D5); // чтение данных, преобразование 8 бит и сохранениевофлэш} void write_to_flash(unsigned char flash_data){static unsigned int buffer_counter;static unsigned int page_counter;unsigned char temp = 0x80; if((ACSR & 0x02)) // если флаг установлен, то новые данные должны быть установлены{buffer_counter = 0;page_counter = 0; // сброс счётчика если должны быть записаны новые данные ACSR &= 0xFD; // очистка флага сигнала} while(!(PINB & 0x02)); // проверка занятости флэша PORTB &= ~DF_CHIP_SELECT; // включение DataFlash SPDR = BUFFER_1_WRITE;while (!(SPSR & temp)); // ожидание завершения передачиSPDR = 0x00; // не важноwhile (!(SPSR & temp)); // ожидание завершения передачи SPDR = (char)(buffer_counter>>8); // не важно + первые два бита буфера адресаwhile (!(SPSR & temp)); // ожидание завершения передачи SPDR = (char)buffer_counter; // буферадреса (макс. 2^8 = 256 страниц)while (!(SPSR & temp)); // ожидание завершения передачиSPDR = flash_data; // запись данных в регистр данных SPIwhile (!(SPSR & temp)); // ожидание завершения передачи PORTB |= DF_CHIP_SELECT; // выключение DataFlash buffer_counter++; if (buffer_counter > 528) // еслибуферзаполнен, тоегосодержимое записывается в страницу памяти {buffer_counter = 0;if (page_counter < 4096) // еслипамятьнезаполнена{PORTB &= ~DF_CHIP_SELECT; // включить DataFlash SPDR = B1_TO_MM_PAGE_PROG_WITHOUT_ERASE; // записатьданные из буфера 1 в страницуwhile (!(SPSR & temp)); // ожидание завершения передачиSPDR = (char)(page_counter>>6);while (!(SPSR & temp)); // ожидание завершения передачиSPDR = (char)(page_counter<<2);while (!(SPSR & temp)); // ожиданиезавершенияпередачиSPDR = 0x00; // не важноwhile (!(SPSR & temp)); // ожидание завершения передачи PORTB |= DF_CHIP_SELECT; // выключение DataFlash page_counter++;}else{PORTB |= 0x08; // погасить LED while (!(PIND & 8)); // ждать пока кнопка записи не отпущена (кнопка 3)}}} void playback(void){unsigned int page_counter = 0;unsigned int buffer_counter = 0;unsigned char active_buffer = 1; // активныйбуфер = буфер 1unsigned char temp = 0x80; TCCR1A = 0x21; // 8 битШИМ, используется COM1BTCNT1 = 0x00; // обнуление счётчика 1TIFR = 0x04; // сброс флага превышения счётчика 1 TIMSK = 0x04; // разрешение прерывания переполнения счётчика 1 TCCR1B = 0x01; // коэф. Пересчёта счётчика 1 = 1OCR1B = 0x00; // обнуление выходного регистра сравнения B // прерывания запрещены, порт SPI включён, «ведущий» режим, первый MSB, 3 режим SPI, Fcl/4 SPCR = 0x5C; next_page_to_next_buffer (active_buffer, page_counter); // чтениестраницы 0 в буфер 1while (!(PINB & 0x02)); // ожидание завершения передачи данных из страницы 0 в буфер 1while ((page_counter < 4095)&(!(PIND & 2))) // пока кнопка воспроизведения (кнопка 1) нажата{page_counter++; // теперь берём следующую страницу next_page_to_next_buffer (active_buffer, page_counter);active_buffer_to_speaker (active_buffer); if (active_buffer == 1) // если буфер 1 является активным буфером{active_buffer++; // то устанавливаем буфер 2 в качестве активного}else // иначе{active_buffer--; // устанавливаем буфер 1 в качестве активного}}TIMSK = 0x00; // запрещаем все прерыванияTCCR1B = 0x00; // останавливаем счётчик 1SPCR = 0x00; // отключаем SPI} void next_page_to_next_buffer (unsigned char active_buffer, unsigned int page_counter){unsigned char temp = 0x80;while(!(PINB & 0x02)); // ждём, покафлэшнеосвободится PORTB &= ~DF_CHIP_SELECT; // включаем DataFlash if (active_buffer == 1) // если буфер 1 активный{SPDR = MM_PAGE_TO_B2_XFER; // то передаём следующую страницу в буфер 2}else // иначе{SPDR = MM_PAGE_TO_B1_XFER; // передаём следующую страницу в буфер 1 }while (!(SPSR & temp)); // ожидаем завершения передачиSPDR = (char)(page_counter >> 6);while (!(SPSR & temp)); // ожидаемзавершенияпередачиSPDR = (char)(page_counter << 2);while (!(SPSR & temp)); // ожидаемзавершенияпередачиSPDR = 0x00; // записываем не имеющий значения байтwhile (!(SPSR & temp)); // ожидаем завершения передачиPORTB |= DF_CHIP_SELECT; // выключаем DataFlash и начинаем передачу} void interrupt[TIMER1_OVF1_vect] out_now(void){wait = 0; // возникновениепрерывания} void active_buffer_to_speaker (unsigned char active_buffer){// пока активный буфер не очистится воспроизводим его содержимое на динамикеunsigned int buffer_counter = 0;unsigned char temp = 0x80; PORTB &= ~DF_CHIP_SELECT; // включение DataFlash if (active_buffer == 1) // если буфер 1 активный буфер{SPDR = BUFFER_1_READ; // то читаем из буфера 1}else // иначе{SPDR = BUFFER_2_READ; // читаем из буфера 2} while (!(SPSR & temp)); // ожидаем завершения передачи SPDR = 0x00; // запись не имеющего значения байтаwhile (!(SPSR & temp)); // ожидаем завершения передачиSPDR = 0x00; // запись не имеющего значения байтаwhile (!(SPSR & temp)); // ожидаем завершения передачиSPDR = 0x00; // начать с адреса 0 буфераwhile (!(SPSR & temp)); // ожидаем завершения передачиSPDR = 0x00; // запись не имеющего значения байтаwhile (!(SPSR & temp)); // ожидаем завершения передачи while (buffer_counter < 528){SPDR = 0xFF; // записываем фиктивное значение в начало сдвигового регистраwhile (!(SPSR & temp)); // ожидаем завершения передачиwhile(wait); // ожидаем прерывание переполнения таймера 1OCR1B = SPDR; // воспроизводим данные из сдвигового регистраwait = 1; // сбросфлагасигнала buffer_counter++;} PORTB |= DF_CHIP_SELECT; // выключение DataFlash} void main(void){setup(); for(;;){if (!(PIND & 8)) // если кнопка записи нажата (кнопка 3){PORTB &= 0xF7; // зажигаем LEDrecording();}if (!(PIND & 4)) // если нажата кнопка очистки (кнопка 2){PORTB &= 0xF7; // зажигаем LEDerasing();while (!(PIND & 4)); // ждём пока кнопка очистки не отпущена (кнопка 2)}if (!(PIND & 2)) //если нажата кнопка воспроизведения(кнопка 1){PORTB &= 0xF7; // зажигаем LEDplayback();while (!(PIND & 2)); // ждём пока кнопка воспроизведения не отпущена (кнопка 1) }PORTB |= 0x08; // гасим LED во время «холостой» работы}} DataFlash.h // изменён 19.04.1999// для использования 8535 #include “ina90.h”#pragma language=extended // DataFlash вывод сброса порта (PB 0)#define DF_RESET 0x01 // DataFlash вывод состояния порта готов/занят (PB 1)#define DF_RDY_BUSY 0x02 // DataFlash защита от записи загрузочного сектора (PB 2)#define DF_WRITE_PROTECT 0x04 // DataFlash выводпортавыборамикросхемы (PB 4)#define DF_CHIP_SELECT 0x10 // буфер 1#define BUFFER_1 0x00 // буфер 2#define BUFFER_2 0x01 // определение всех кодов операций // запись буфера 1#define BUFFER_1_WRITE 0x84 // записьбуфера 2#define BUFFER_2_WRITE 0x87 // чтениебуфера 1#define BUFFER_1_READ 0x54 // чтениебуфера 2#define BUFFER_2_READ 0x56 // Буфер 1 в основную страницу памяти программы с встроенным стиранием#define B1_TO_MM_PAGE_PROG_WITH_ERASE 0x83 // Буфер 2 в основную страницу памяти программы с встроенным стиранием#define B2_TO_MM_PAGE_PROG_WITH_ERASE 0x86 // Буфер 1 в основную страницу памяти программы без встроенного стирания#define B1_TO_MM_PAGE_PROG_WITHOUT_ERASE 0x88 // Буфер 2 в основную страницу памяти программы без встроенного стирания#define B2_TO_MM_PAGE_PROG_WITHOUT_ERASE 0x89 // Основная страница памяти программы сквозь буфер 1#define MM_PAGE_PROG_THROUGH_B1 0x82 // Основная страница памяти программы сквозь буфер 2#define MM_PAGE_PROG_THROUGH_B2 0x85 // автоматическая перезапись страницы через буфер 1#define AUTO_PAGE_REWRITE_THROUGH_B1 0x58 // автоматическая перезапись страницы через буфер 2#define AUTO_PAGE_REWRITE_THROUGH_B2 0x59 // сравнение основной страницы памяти с буфером 1#define MM_PAGE_TO_B1_COMP 0x60 // сравнение основной страницы памяти с буфером 2#define MM_PAGE_TO_B2_COMP 0x61 // передача основной страницы памяти в буфер 1#define MM_PAGE_TO_B1_XFER 0x53 // передача основной страницы памяти в буфер 2#define MM_PAGE_TO_B2_XFER 0x55 // регистр состояния DataFlash для чтения плотности, сравнения состояний,// и состояния готов/занят#define STATUS_REGISTER 0x57 // чтение основной страницы памяти#define MAIN_MEMORY_PAGE_READ 0x52 // очистка 528 байт страницы#define PAGE_ERASE 0x81 // очистка 512 страниц#define BLOCK_ERASE 0x50 #define TRUE 0xff#define FALSE 0x00

РАСЧЕТ ВРЕМЕНИ НАРАБОТКИ НА ОТКАЗ