106 lines
2.7 KiB
C
106 lines
2.7 KiB
C
#define __AVR_ATmega2560__
|
|
#define F_CPU 16000000UL
|
|
|
|
#include <avr/io.h>
|
|
#include <util/delay.h>
|
|
#include <stdbool.h>
|
|
#include <avr/interrupt.h>
|
|
|
|
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);
|
|
}
|
|
}
|