#include #include #include #include #include "sounddata.h" #define SAMPLE_RATE 8000 // скорость воспроизведения int speakerPin = 11; volatile uint16_t sample; byte lastSample; // далее идут команды не использующие Ардуиновскую оболочку, особо не вникайте. // Это называется на 8000 Гц для загрузки следующего образца. ISR(TIMER1_COMPA_vect) { if (sample >= sounddata_length) { if (sample == sounddata_length + lastSample) { stopPlayback(); } else { // Рампа вниз до нуля, чтобы уменьшить щелчок в конце воспроизведения. OCR2A = sounddata_length + lastSample - sample; } } else { OCR2A = pgm_read_byte(&sounddata_data[sample]); } ++sample; } void startPlayback() { // Настраиваем 2-ой таймер для использования широтно-импульсной модуляции на динамике // Используем внутренние часы ASSR &= ~(_BV(EXCLK) | _BV(AS2)); // Устанавливаем быстрый режим PWM TCCR2A |= _BV(WGM21) | _BV(WGM20); TCCR2B &= ~_BV(WGM22); // Не используйте ШИМ на контакте OC2A // На Arduino это вывод 11. TCCR2A = (TCCR2A | _BV(COM2A1)) & ~_BV(COM2A0); TCCR2A &= ~(_BV(COM2B1) | _BV(COM2B0)); // Не используем предварительный делитель TCCR2B = (TCCR2B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10); // Задаем начальную ширину импульса для первого образца. OCR2A = pgm_read_byte(&sounddata_data[0]); // Настраиваем Таймер 1, чтобы отправить образец каждого прерывания. cli(); // Устанавливаем режим CTC (Очистить таймер на совпадении) // Необходимо установить OCR1A * после * ( *after*), иначе он будет сброшен на 0! TCCR1B = (TCCR1B & ~_BV(WGM13)) | _BV(WGM12); TCCR1A = TCCR1A & ~(_BV(WGM11) | _BV(WGM10)); // Не используем предварительный делитель TCCR1B = (TCCR1B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10); // Устанавливаем регистр сравнения (OCR1A). // OCR1A - это 16-разрядный регистр, поэтому мы должны сделать это с помощью // отключенный прерываний, чтобы быть в безопасности. OCR1A = F_CPU / SAMPLE_RATE; // 16e6 / 8000 = 2000 // Включаем прерывание, когда TCNT1 == OCR1A (p.136) TIMSK1 |= _BV(OCIE1A); lastSample = pgm_read_byte(&sounddata_data[sounddata_length-1]); sample = 0; sei(); } void stopPlayback() { // Отключаем прерывание воспроизведения на выборку. TIMSK1 &= ~_BV(OCIE1A); // Полностью отключаем таймер за выборку. TCCR1B &= ~_BV(CS10); // Отключаем таймер PWM. TCCR2B &= ~_BV(CS10); digitalWrite(speakerPin, LOW); } void setup() { // проигрываем наш аудиофайл startPlayback(); } void loop() { }