diff --git a/main.c b/main.c index 70e0f15..ea8d71a 100644 --- a/main.c +++ b/main.c @@ -6,43 +6,100 @@ #include #include -volatile int debounce_int2 = 10; -volatile int debounce_int3 = 10; +volatile uint16_t tick_timer_start = 0xffff - (F_CPU / 1024 / 1000); +volatile bool speaker_disabled = true; -ISR(INT2_vect) { - if (debounce_int2) return; - debounce_int2 = 100; - OCR0A++; +uint16_t notes[][3] = { + { 1000, 200, 30 }, + { 1200, 200, 30 }, + { 1500, 200, 30 }, + { 1600, 200, 30 }, + { 1500, 200, 30 }, + { 1200, 100, 10 }, + { 1000, 300, 100 }, +}; + +void ADC_Setup() { + // AVCC with external capacitor at AREF pin + ADMUX = _BV(REFS0); + + // Enable ADC, set prescaler to 8tick_timer_start + ADCSRA = _BV(ADEN) | _BV(ADPS0) | _BV(ADPS1); + + // Perform dummy readout + ADCSRA |= _BV(ADSC); // Start conversion + while (ADCSRA & _BV(ADSC)); // Await result + (void) ADCW; // Read out result } -ISR(INT3_vect) { - if (debounce_int3) return; - debounce_int3 = 100; - OCR0A--; +uint16_t ADC_Read(uint8_t channel) { + // Select chosen channel + ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F); + // Start conversion + ADCSRA |= _BV(ADSC); + // Await the result + while (ADCSRA & _BV(ADSC)); + // Although it doesn't appear to be documented, ADCW holds the covnersion result + return ADCW; } -ISR(TIMER0_COMPA_vect) { - PORTF ^= 0b00000001; +uint16_t ADC_Read_Avg(uint8_t channel, uint8_t samples) { + uint32_t sum = 0; + for (int i = 0; i < samples; i++) { + sum += ADC_Read(channel); + } + return (uint16_t)(sum / samples); +} + +void TIMER_Setup() { + TCCR1B |= _BV(CS10) | _BV(CS12); // clk/1024 + + // Set the TOIE (Timer Overflow Interrupt Enable) bit + // on TIMSK1 (Timer 1 Interrupt Mask Register). + TIMSK1 |= _BV(TOIE1); + + // Sets the current timer value + TCNT1 = tick_timer_start; + + // Enable interrupts + sei(); +} + +// ISR is used to handle interrupts. TIMER1_OVF_vect +// is triggered whenever timer 1 (16 bit) overflows. +ISR(TIMER1_OVF_vect) { + TCNT1 = tick_timer_start; + PORTB ^= 0b10000000; + + if (speaker_disabled) PORTK &= 0b11111110; + else PORTK ^= 0b00000001; +} + +void play_note(uint16_t freq, uint8_t delay, uint8_t delay_silence) { + speaker_disabled = false; + tick_timer_start = 0xffff - (F_CPU / freq / 1000); + for (int i = 0; i < delay; i++) _delay_ms(1); + speaker_disabled = true; + for (int i = 0; i < delay_silence; i++) _delay_ms(1); } void main() { - DDRF = 0b00000001; - DDRD = 0b00000000; - PORTD |= 0b00001100; + DDRK = 0b00000001; + PORTB = 0b10000000; // Start with LED enabled - // EIMSK controls which ports can trigger interrupts - EIMSK |= _BV(INT2) | _BV(INT3); - // Trigger on falling edge on INT2 and INT3 - EICRA |= _BV(ISC21) | _BV(ISC31); + ADC_Setup(); + TIMER_Setup(); - TCCR0B |= _BV(CS00) | _BV(CS02); // clk/1024 - TIMSK0 |= _BV(OCIE0A); - OCR0A = 0; + long rows = sizeof(notes) / sizeof(notes[0]); - sei(); + while (true) { + for (int i = 0; i < rows; i++) { + play_note(notes[i][0], notes[i][1], notes[i][2]); + } - while(1) { - _delay_ms(10); - OCR0A++; + //uint16_t value = ADC_Read_Avg(0, 4); + //speaker_disabled = value == 0; + //if (value < 100) value = 100; // Anything lower than this causes issues + //tick_timer_start = 0xffff - (F_CPU / value / 1000); } }