Объясните работу программы!

greycat9515
Offline
Зарегистрирован: 18.12.2017

Здравствуйте.Недавно начал осваивать ардуино и столкнулся с первыми трудностями.Есть код,который проигрывает wave файл все работает,но хотелось бы понять как это происходит.Вот собственно код:

#include <stdint.h>
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include "sounddata.h"
#define SAMPLE_RATE 8000

int ledPin = 13;
int speakerPin = 11;
volatile uint16_t sample;
byte lastSample;

// This is called at 8000 Hz to load the next sample.
ISR(TIMER1_COMPA_vect) {
    if (sample >= sounddata_length) {
        if (sample == sounddata_length + lastSample) {
            stopPlayback();
        }
        else {
            // Ramp down to zero to reduce the click at the end of playback.
            OCR2A = sounddata_length + lastSample - sample;
        }
    }
    else {
          OCR2A = pgm_read_byte(&sounddata_data[sample]);
          }
    ++sample;
}

void startPlayback()
{
    pinMode(speakerPin, OUTPUT);

    // Set up Timer 2 to do pulse width modulation on the speaker
    // pin.

    // Use internal clock (datasheet p.160)
    ASSR &= ~(_BV(EXCLK) | _BV(AS2));

    // Set fast PWM mode  (p.157)
    TCCR2A |= _BV(WGM21) | _BV(WGM20);
    TCCR2B &= ~_BV(WGM22);

    // Do non-inverting PWM on pin OC2A (p.155)
    // On the Arduino this is pin 11.
    TCCR2A = (TCCR2A | _BV(COM2A1)) & ~_BV(COM2A0);
    TCCR2A &= ~(_BV(COM2B1) | _BV(COM2B0));

    // No prescaler (p.158)
    TCCR2B = (TCCR2B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);

    // Set initial pulse width to the first sample.
    OCR2A = pgm_read_byte(&sounddata_data[0]);


    // Set up Timer 1 to send a sample every interrupt.

    cli();

    // Set CTC mode (Clear Timer on Compare Match) (p.133)
    // Have to set OCR1A *after*, otherwise it gets reset to 0!
    TCCR1B = (TCCR1B & ~_BV(WGM13)) | _BV(WGM12);
    TCCR1A = TCCR1A & ~(_BV(WGM11) | _BV(WGM10));

    // No prescaler (p.134)
    TCCR1B = (TCCR1B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);

    // Set the compare register (OCR1A).
    // OCR1A is a 16-bit register, so we have to do this with
    // interrupts disabled to be safe.
    OCR1A = F_CPU / SAMPLE_RATE;    // 16e6 / 8000 = 2000

    // Enable interrupt when TCNT1 == OCR1A (p.136)
    TIMSK1 |= _BV(OCIE1A);

    lastSample = pgm_read_byte(&sounddata_data[sounddata_length-1]);
    sample = 0;
    sei();
}

void stopPlayback()
{
    // Disable playback per-sample interrupt.
    TIMSK1 &= ~_BV(OCIE1A);

    // Disable the per-sample timer completely.
    TCCR1B &= ~_BV(CS10);

    // Disable the PWM timer.
    TCCR2B &= ~_BV(CS10);

    digitalWrite(speakerPin, LOW);
}

void setup()
{
    pinMode(ledPin, OUTPUT);
    startPlayback();
}

void loop()
{
//if (HIGH == digitalRead(12))
//{
//   for (int i=0; i <= 255; i++)
//   {
     pinMode(ledPin, OUTPUT);
//   } 
//  if (HIGH == digitalRead(12)) startPlayback();
//} 
}

Понятно,что используются прерывания по таймеру,но для чего - нет мыслей.Также интересно:почему динамик воспроизводит только на 11 пине,на остальных молчит(переменную speakerPin я естественно меняю ).

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

greycat9515 пишет:

Также интересно:почему динамик воспроизводит только на 11 пине,на остальных молчит(переменную speakerPin я естественно меняю ).

А Вы сами-то код читали? Комментарий в строках 44-45 ни на какие мысли не навёл?

greycat9515
Offline
Зарегистрирован: 18.12.2017

Не заметил.. Может есть литература или какая нибудь статья по этой теме?куда копать?

greycat9515
Offline
Зарегистрирован: 18.12.2017

Забыл упомянуть,что wave файл хранится в файле sounddata.h в шестнадцатеричном виде

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

greycat9515 пишет:
Не заметил.. Может есть литература или какая нибудь статья по этой теме?куда копать?
Конечно, есть. Надеюсь, номера страниц в комментариях Вы заметили? Так вот это номера как раз в этом тексте. Изучайте.