Skip to content

Instantly share code, notes, and snippets.

@dagon666
Last active November 27, 2022 00:07
Show Gist options
  • Save dagon666/6769476 to your computer and use it in GitHub Desktop.
Save dagon666/6769476 to your computer and use it in GitHub Desktop.
generating tones with Atmega328p's timer
#include <stdint.h>
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/power.h>
// system clock frequency
#define F_CPU 16000000UL
// global variable to determine the beep duration
static volatile uint32_t duration = 0x00;
ISR(TIMER0_COMPA_vect) {
if (!duration) {
// mask the interrupt
TIMSK0 &= ~_BV(OCIE0A);
// disable clock
TCCR0B = 0x00;
// set the port state to low, when generation is finished
PORTD &= _BV(PORTD6);
}
else {
duration--;
}
}
static void timer_freq_prescale(uint32_t a_freq, uint8_t *a_ocr, uint8_t *a_prescaler) {
// prescaler table for timer 0
uint8_t prescalers[] = { 0x00, 0x03, 0x06, 0x08, 0x0a, 0x00 };
uint16_t ocr = 0x00;
uint8_t prescaler = 0x00;
do {
ocr = (uint16_t) (F_CPU / ((a_freq << 1) * (0x01 << prescalers[prescaler])));
++prescaler;
} while ((ocr > 255) && (prescalers[prescaler]));
--ocr;
if (ocr > 255) ocr = 255;
*a_ocr = ocr & 0xff;
*a_prescaler = prescaler;
}
void beep(uint16_t a_freq, uint16_t a_duration) {
uint8_t prescaler = 0x00,
ocr = 0x00;
sei();
power_timer0_enable();
// configure the COMP0A pin as output
DDRD |= _BV(PORTD6);
// calculate the frequency
timer_freq_prescale(a_freq, &ocr, &prescaler);
// COM0A1/COM0A0 = 0x01 - toggle OC0A on Compare Match, mode = CTC
TCCR0A = 0x42;
OCR0A = ocr;
TCNT0 = 0x00;
// configure the prescaler, now the timer is running and the tone is being generated
TCCR0B = prescaler & 0x07;
// calculate the amount of cycles
duration = (uint32_t)((a_freq * a_duration)/500);
// unmask the interrupt
TIMSK0 |= _BV(OCIE0A);
// block until the tone fades out
while(duration);
}
int main(void)
{
uint16_t freq = 100;
while (1) {
for(uint8_t i = 0; i < 64; i++) {
// 100 ms beep of increasing frequency
beep(freq + (10 * i), 100);
}
}
return 0;
}
TARGET=beeper
SOURCES=beeper.c
DEPS=
COBJ=$(SOURCES:.c=.o)
CC=avr-gcc
OBJC=avr-objcopy
MCU=atmega328p
CFLAGS=-I. -Wall -Os -DF_CPU=16000000UL -std=c99
LDFLAGS=
ISPPORT=/dev/ttyACM0
ISPDIR=/usr/share/arduino/hardware/tools
ISP=$(ISPDIR)/avrdude
ISPFLAGS=-c arduino -p $(MCU) -P $(ISPPORT) -b 115200 -C $(ISPDIR)/avrdude.conf
all: $(TARGET)
%.o: %.c $(DEPS)
@echo -e "\tCC" $<
@$(CC) -mmcu=$(MCU) -c -o $@ $< $(CFLAGS)
$(TARGET): $(COBJ)
@echo -e "\tLINKING CC" $<
@$(CC) -mmcu=$(MCU) -o $(TARGET) $(COBJ) $(LDFLAGS)
$(OBJC) -O ihex -R .eeprom $(TARGET) $(TARGET).hex
$(OBJC) -O binary -R .eeprom $(TARGET) $(TARGET).bin
clean:
$(MAKE) -C $(PCA_PREFIX) clean
@echo ========== cleanup ==========
rm -rf *.o *.bin *.hex $(TARGET)
read:
$(ISP) $(ISPFLAGS) -U flash:r:$(TARGET)_backup.hex:i
install:
$(ISP) $(ISPFLAGS) -U flash:w:$(TARGET).hex
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment