#define __AVR_ATmega2560__ #define F_CPU 16000000UL #include #include #include #include volatile uint16_t tick_timer_start = 0xffff - (F_CPU / 1024 / 1000); volatile bool speaker_disabled = true; 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 } 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; } 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() { DDRK = 0b00000001; PORTB = 0b10000000; // Start with LED enabled ADC_Setup(); TIMER_Setup(); long rows = sizeof(notes) / sizeof(notes[0]); while (true) { for (int i = 0; i < rows; i++) { play_note(notes[i][0], notes[i][1], notes[i][2]); } //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); } }