#include #include #include #include #include "sounddata.h" #define SAMPLE_RATE 8000 // скорость воспроизведения (частота дискретизации, которую вы выбрали при конвертации файла) int speakerPin = 11; // пин на который подключен динамик int sounddata_length; // длина массива с данными для воспроизведения volatile uint16_t sample; byte lastSample; unsigned char *data_it; // указатель на текущий массив данных unsigned int inp = -1; // переменная для ввода числа с клавиатуры компа. -1 для беззнакового типа является бесконечностью void play_trek(byte num){ // функция, воспроизводящая файлы по пришедшему номеру switch(num){ // проверяем локальную переменную num case 1: // если она равна 1 sounddata_length = sounddata_length1; // длинна текущего массива равна длине массива первого файла data_it = &data1[0]; // адрес текущего массива равен адресу массива первого файла Serial.print("one"); // печатем в СОМ - порт название значения num на английском break; // выходим из кострукции switch // остальные случаи аналогично case 2: sounddata_length = sounddata_length2; data_it = &data2[0]; Serial.print("two"); break; case 3: sounddata_length = sounddata_length3; data_it = &data3[0]; Serial.print("three"); break; default: // случай по умолчанию, если ни один случай не сработал return; // выходим из функции play_trek, ничего не воспроизводя так, как полученное число неизвестно } Serial.println(); // переводим строчку startPlayback(); // запускаем воспроизведение текущего аудиофайла } // действия при срабатывании прирывания по таймеру 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(&data_it[sample]); } ++sample; } void startPlayback() { // настраиваем второй таймер для работы с динамиком // Используем встроенные часы 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(data_it[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 TIMSK1 |= _BV(OCIE1A); lastSample = pgm_read_byte(data_it[sounddata_length - 1]); // change sample = 0; sei(); } void stopPlayback() { // Отключаем прерывание воспроизведения на выборку. TIMSK1 &= ~_BV(OCIE1A); // Полностью отключаем таймер за выборку. TCCR1B &= ~_BV(CS10); // Отключаем таймер PWM. TCCR2B &= ~_BV(CS10); // выключаем динамик digitalWrite(speakerPin, LOW); } void setup() { Serial.begin(9600); // настраиваем COM - порт на передачу данных со скоростью 9600 // мне было удобнее назначить 10 пин на работу вкачестве земли (GND) pinMode(speakerPin, OUTPUT); // пин для динамика на выход pinMode(10, OUTPUT); digitalWrite(10, LOW); } void loop() { if(Serial.available()){ // если даннные COM - порта доступны inp = int(Serial.read()) - 48; // считываем их и переводим в цифры play_trek(inp); // запускаем соответсвующий трек //Serial.println(inp); // выводим пришедшую цыфру (будет лишнее значение, не заню как его убирать) } }