diff --git a/lab_2/main.c b/lab_2/main.c new file mode 100644 index 0000000..11d2ebc --- /dev/null +++ b/lab_2/main.c @@ -0,0 +1,151 @@ +/* + * GccApplication1.c + * + * Created: 10/8/2019 2:07:13 PM + * Author : lenfesty + */ + +#include "main.h" + +uint8_t play_flag = 0; +uint8_t button_flag = 0; + +ISR(INT0_vect) { + // Disable interrupts + cli(); + + // Notify of button press + button_flag = 1; +} + +/* + * Pin Definitions: + * PB2 -> OC0A output + * PB3 -> OC1A output + * PB0 -> Switch Input + */ +void gpio_init() { + // Piezo Out + DDRB |= (1 << DDB2) | (1 << DDB3); + + // Switch Input Setup + DDRD &= ~(1 << DDD2); + PORTD |= (1 << PORTD2); + + // Configure Interrupt Stuff + // Set falling edge for INT0 + MCUCR |= (1 << ISC01) | (0 << ISC00); + + // Enable INT0 + GIMSK |= (1 << INT0); +} + +void timer_init( ) { + /* --- Timer 0 (8 bit) --- */ + // Set Compare mode A to toggle, and waveform generation mode to CTC + TCCR0A = (0 << COM0A1) | (1 << COM0A0) | (1 << WGM01) | (0 << WGM00); + // Nothing else relevant here, without setting notes + + /* --- Timer 1 (16 bit) --- */ + // Set compare mode A to toggle + TCCR1A = (0 << COM1A1) | (1 << COM1A0); + // Set waveform gen mode to CTC + TCCR1B = (1 << WGM12); +} + +void play_beat() { + static uint8_t duration_left[2] = {0}; + static uint16_t song_location[2] = {0}; + + // If at end of song, restart + if (song_location[0] == SPEAKER0_LEN) { + song_location[0] = 0; + song_location[1] = 0; + } + + // Set note + for (uint8_t speaker = 0; speaker < 2; speaker++) { + if (duration_left[speaker] == 0) { + // Move to next note + // Read in next note from program memory + uint16_t beat; + beat_t* p_beat; + + // Select from correct song + if (speaker == 0) { + beat = pgm_read_word((PGM_P*) &song_speaker0[song_location[speaker]]); + } else { + beat = pgm_read_word((PGM_P*) &song_speaker1[song_location[speaker]]); + } + + p_beat = (beat_t*) &beat; + + + // Set duration left after this beat + duration_left[speaker] = p_beat->duration - 1; + // Increment song location for next note + song_location[speaker]++; + + // actually set note + play_note(*p_beat, speaker); + } else { + // Keep handling current note + // do nothing, it is set correctly + duration_left[speaker]--; + } + } + _delay_ms(BEAT_LENGTH * (1 - REST_FRACTION)); // Play note + + // Rest note if at the end of the interval + for (uint8_t speaker = 0; speaker < 2; speaker++) { + if (duration_left[speaker] == 0) { + // End of note, pause here + beat_t beat = { + .note = rest, + .duration = 0, + .octave = 0, // octave doesn't matter, its a rest + }; + play_note(beat, speaker); + } else { + // Note does not end, change nothing + } + } + _delay_ms(BEAT_LENGTH * REST_FRACTION); + +} + +int main(void) +{ + gpio_init(); + timer_init(); + + sei(); + + /* Replace with your application code */ + while (1) + { + if (play_flag) { + play_beat(); + } + + if (button_flag) { + button_flag = 0; + + beat_t beat = { + .note = rest, + }; + play_note(beat, 0); + play_note(beat, 1); + _delay_ms(100); + sei(); + } + + if ( bit_is_clear(PIND, PIND2) && (play_flag == 0)) { + cli(); + play_flag = 1; + _delay_ms(100); + sei(); + } + + } +} diff --git a/lab_2/main.h b/lab_2/main.h new file mode 100644 index 0000000..7654702 --- /dev/null +++ b/lab_2/main.h @@ -0,0 +1,42 @@ +#ifndef MAIN_H_ +#define MAIN_H_ + +#define F_CPU 8000000UL + +#include +#include +#include +#include + +#include "notes.h" + +#define TEMPO (120 * 4) // Tempo of song (bpm) +#define REST_FRACTION 0.3 // Fraction of the beat to stay silent between notes +#define BEAT_LENGTH 60000 / TEMPO // Length of each note (ms) + + +#define OCTAVES 2 +#define NOTES_PER_OCTAVE 12 +#define SPEAKER0_LEN 38 +#define SPEAKER1_LEN 96 + +typedef enum { + a = 0, b, c, d, e, f, g, + A, C, D, F, G, + rest +} note_t; + +typedef struct { + note_t note; + uint8_t duration:7; + uint8_t octave:1; +} beat_t; + +extern const uint8_t PROGMEM notes[OCTAVES][NOTES_PER_OCTAVE]; + +extern const beat_t PROGMEM song_speaker0[SPEAKER0_LEN]; +extern const beat_t PROGMEM song_speaker1[SPEAKER1_LEN]; + +void play_note(beat_t note, uint8_t speaker); + +#endif diff --git a/lab_2/notes.c b/lab_2/notes.c new file mode 100644 index 0000000..8a94195 --- /dev/null +++ b/lab_2/notes.c @@ -0,0 +1,58 @@ +#include "main.h" + +/* +const uint8_t PROGMEM notes[OCTAVES][NOTES_PER_OCTAVE] = { + { 140, 62, 118, 106, 94, 88, 79, 64, 112, 98, , 37 }, // 1024 prescaler octave 2 + { 141, 126, 238, 212, 188, 178, 158, 133, 225, 200, 168, 150 } // 64 prescaler octave 4 +}; +*/ + +const uint8_t PROGMEM notes[OCTAVES][NOTES_PER_OCTAVE] = { + { 35, 31, 59, 53, 47, 44, 39, 32, 56, 49, 41, 37 }, // 1024 prescaler octave 2 + { 141, 126, 238, 212, 188, 178, 158, 133, 225, 200, 168, 150 } // 64 prescaler octave 4 +}; + + +void play_note(beat_t note, uint8_t speaker) { + if (note.note == rest) { // Handle special rest case + if (speaker == 0) { + // Turn off timer clock source, disabling + TCCR0B &= ~( (1 << CS02) | (1 << CS01) | (1 << CS00)); + // Turn off output pin + PORTB &= ~(1 << PORTB2); + } else { + // turn off timer clock source, disabling + TCCR1B &= ~( (1 << CS12) | (1 << CS11) | (1 << CS10)); + // turn off output pin + PORTB &= ~(1 << PORTB3); + } + } else { + // Set up so note changes always happen after rests, + // so we know CS[2:0] = 0 + // See pages 86 and 114 + uint8_t prescale = 0; + if (note.octave == 0) { + // set prescaler to 1024 + prescale = 4; + } else { + // set prescaler to 64 + prescale = 3; + } + + // Get value to write to output compare + uint8_t period = pgm_read_byte((PGM_P*) ¬es[note.octave][note.note]); + + // Actually set clock source + if (speaker == 0) { + TCNT0 = 0; // reset counter + OCR0A = period; // set note period + TCCR0B |= prescale; + } else { + TCNT1H = 0; // reset counter + TCNT1L = 0; + OCR1AL = period; // set note period + OCR1AH = period >> 8; + TCCR1B |= prescale; + } + } +} diff --git a/lab_2/song.c b/lab_2/song.c new file mode 100644 index 0000000..3c0c9d7 --- /dev/null +++ b/lab_2/song.c @@ -0,0 +1,141 @@ +#include "main.h" + +const beat_t PROGMEM song_speaker0[SPEAKER0_LEN] = { + {.note = g, .duration = 4, .octave = 0 }, + {.note = g, .duration = 4, .octave = 0 }, + {.note = f, .duration = 4, .octave = 0 }, + {.note = f, .duration = 4, .octave = 0 }, + {.note = d, .duration = 4, .octave = 0 }, + {.note = d, .duration = 4, .octave = 0 }, + {.note = c, .duration = 4, .octave = 0 }, + {.note = c, .duration = 4, .octave = 0 }, + {.note = g, .duration = 4, .octave = 0 }, + {.note = g, .duration = 4, .octave = 0 }, + {.note = f, .duration = 4, .octave = 0 }, + {.note = f, .duration = 4, .octave = 0 }, + {.note = d, .duration = 6, .octave = 0 }, + {.note = c, .duration = 4, .octave = 0 }, + {.note = g, .duration = 4, .octave = 0 }, + {.note = g, .duration = 4, .octave = 0 }, + {.note = f, .duration = 4, .octave = 0 }, + {.note = f, .duration = 4, .octave = 0 }, + {.note = d, .duration = 4, .octave = 0 }, + {.note = d, .duration = 4, .octave = 0 }, + {.note = c, .duration = 4, .octave = 0 }, + {.note = c, .duration = 4, .octave = 0 }, + {.note = g, .duration = 4, .octave = 0 }, + {.note = g, .duration = 4, .octave = 0 }, + {.note = f, .duration = 4, .octave = 0 }, + {.note = f, .duration = 4, .octave = 0 }, + {.note = d, .duration = 4, .octave = 0 }, + {.note = d, .duration = 4, .octave = 0 }, + {.note = c, .duration = 4, .octave = 0 }, + {.note = c, .duration = 4, .octave = 0 }, + {.note = g, .duration = 4, .octave = 0 }, + {.note = g, .duration = 4, .octave = 0 }, + {.note = f, .duration = 4, .octave = 0 }, + {.note = f, .duration = 4, .octave = 0 }, + {.note = d, .duration = 4, .octave = 0 }, + {.note = d, .duration = 4, .octave = 0 }, + {.note = c, .duration = 4, .octave = 0 }, + {.note = c, .duration = 4, .octave = 0 }, +}; + +const beat_t PROGMEM song_speaker1[SPEAKER1_LEN] = { + {.note = d, .duration = 2, .octave = 1 }, + {.note = A, .duration = 2, .octave = 1 }, + {.note = g, .duration = 2, .octave = 1 }, + {.note = g, .duration = 1, .octave = 1 }, + {.note = d, .duration = 2, .octave = 1 }, + {.note = d, .duration = 1, .octave = 1 }, + {.note = a, .duration = 2, .octave = 1 }, + {.note = f, .duration = 2, .octave = 1 }, + {.note = f, .duration = 1, .octave = 1 }, + {.note = d, .duration = 2, .octave = 1 }, + {.note = d, .duration = 1, .octave = 1 }, + {.note = a, .duration = 2, .octave = 1 }, + {.note = f, .duration = 2, .octave = 1 }, + {.note = f, .duration = 1, .octave = 1 }, + {.note = c, .duration = 2, .octave = 1 }, + {.note = c, .duration = 2, .octave = 1 }, + {.note = e, .duration = 2, .octave = 1 }, + {.note = e, .duration = 1, .octave = 1 }, + {.note = f, .duration = 1, .octave = 1 }, + {.note = e, .duration = 1, .octave = 1 }, + {.note = d, .duration = 2, .octave = 1 }, + {.note = A, .duration = 2, .octave = 1 }, + {.note = g, .duration = 2, .octave = 1 }, + {.note = g, .duration = 1, .octave = 1 }, + {.note = d, .duration = 2, .octave = 1 }, + {.note = d, .duration = 1, .octave = 1 }, + {.note = a, .duration = 2, .octave = 1 }, + {.note = f, .duration = 2, .octave = 1 }, + {.note = f, .duration = 1, .octave = 1 }, + {.note = d, .duration = 2, .octave = 1 }, + {.note = d, .duration = 1, .octave = 1 }, + {.note = a, .duration = 3, .octave = 1 }, + {.note = e, .duration = 2, .octave = 1 }, + {.note = e, .duration = 1, .octave = 1 }, + {.note = f, .duration = 1, .octave = 1 }, + {.note = e, .duration = 1, .octave = 1 }, + {.note = d, .duration = 2, .octave = 1 }, + {.note = A, .duration = 2, .octave = 1 }, + {.note = g, .duration = 2, .octave = 1 }, + {.note = g, .duration = 1, .octave = 1 }, + {.note = d, .duration = 2, .octave = 1 }, + {.note = d, .duration = 1, .octave = 1 }, + {.note = a, .duration = 2, .octave = 1 }, + {.note = f, .duration = 2, .octave = 1 }, + {.note = f, .duration = 1, .octave = 1 }, + {.note = d, .duration = 2, .octave = 1 }, + {.note = d, .duration = 1, .octave = 1 }, + {.note = a, .duration = 2, .octave = 1 }, + {.note = f, .duration = 2, .octave = 1 }, + {.note = f, .duration = 1, .octave = 1 }, + {.note = c, .duration = 2, .octave = 1 }, + {.note = c, .duration = 2, .octave = 1 }, + {.note = e, .duration = 2, .octave = 1 }, + {.note = e, .duration = 1, .octave = 1 }, + {.note = f, .duration = 1, .octave = 1 }, + {.note = e, .duration = 1, .octave = 1 }, + {.note = d, .duration = 2, .octave = 1 }, + {.note = A, .duration = 2, .octave = 1 }, + {.note = g, .duration = 2, .octave = 1 }, + {.note = g, .duration = 1, .octave = 1 }, + {.note = d, .duration = 2, .octave = 1 }, + {.note = d, .duration = 1, .octave = 1 }, + {.note = a, .duration = 2, .octave = 1 }, + {.note = f, .duration = 2, .octave = 1 }, + {.note = f, .duration = 1, .octave = 1 }, + {.note = d, .duration = 2, .octave = 1 }, + {.note = d, .duration = 1, .octave = 1 }, + {.note = a, .duration = 2, .octave = 1 }, + {.note = f, .duration = 2, .octave = 1 }, + {.note = f, .duration = 1, .octave = 1 }, + {.note = c, .duration = 2, .octave = 1 }, + {.note = c, .duration = 2, .octave = 1 }, + {.note = e, .duration = 2, .octave = 1 }, + {.note = e, .duration = 1, .octave = 1 }, + {.note = f, .duration = 1, .octave = 1 }, + {.note = e, .duration = 1, .octave = 1 }, + {.note = d, .duration = 2, .octave = 1 }, + {.note = A, .duration = 2, .octave = 1 }, + {.note = g, .duration = 2, .octave = 1 }, + {.note = g, .duration = 1, .octave = 1 }, + {.note = d, .duration = 2, .octave = 1 }, + {.note = d, .duration = 1, .octave = 1 }, + {.note = a, .duration = 2, .octave = 1 }, + {.note = f, .duration = 2, .octave = 1 }, + {.note = f, .duration = 1, .octave = 1 }, + {.note = d, .duration = 2, .octave = 1 }, + {.note = d, .duration = 1, .octave = 1 }, + {.note = a, .duration = 2, .octave = 1 }, + {.note = f, .duration = 2, .octave = 1 }, + {.note = f, .duration = 1, .octave = 1 }, + {.note = c, .duration = 2, .octave = 1 }, + {.note = c, .duration = 2, .octave = 1 }, + {.note = e, .duration = 2, .octave = 1 }, + {.note = e, .duration = 1, .octave = 1 }, + {.note = f, .duration = 1, .octave = 1 }, + {.note = e, .duration = 1, .octave = 1}, +};