microcontrolling/main.c
2023-11-24 10:08:01 +01:00

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);
}
}