Schnaps Song Player

This is a simple circuit to play a song with ATtiny85. It plays the hardcoded song one time at start-up, then stops. To play the song again, you need to press the Restart button.

The specific song used in the example code is a traditional Danish Schnaps song. This project was built to fit into a Schnaps train that brings glasses of Schnaps around the table.

The Circuit

This circuit is powered by a standard 9V battery. The voltage regulator makes sure the ATtiny85 microcontroller gets 3.3V.

PB0 (pin 5) of the microntroller is configured as an output. The output controls a transistor that turns a buzzer on and off. This is because the output pin of the microcontroller can't drive the buzzer directly.

The pushbutton is connected to the reset pin of the microcontroller so that it restarts whenever the button is pushed.

Parts List

R1
1000Ω
Battery
9V
U2
ATtiny85
Buzzer
Active Buzzer
Q1
BC547
Button
Pushbutton
U1
Voltage Regulator

How To Build

The code was written and uploaded to the microcontroller using the Arduino IDE. Here's the code to play a danish Schnapps song:

#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/sleep.h>

#define NOTE_D4 294
#define NOTE_FS4 370
#define NOTE_G4 392
#define NOTE_A4 440
#define NOTE_B4 494
#define NOTE_C5 523
#define NOTE_D5 587

// Define the pin to output the tone
#define TONE_PIN PB0


// notes in start and stop of the melody stored in PROGMEM
const uint16_t melody[] PROGMEM = {
    NOTE_G4, NOTE_B4, NOTE_D5, 0, NOTE_D5, NOTE_C5, NOTE_B4, NOTE_A4, NOTE_G4, 0, 0,
    NOTE_A4, NOTE_A4, NOTE_FS4, NOTE_D4, NOTE_D5, NOTE_D5, NOTE_B4, NOTE_G4, NOTE_A4, NOTE_A4, 
    NOTE_FS4, NOTE_D4, NOTE_D5, NOTE_D5, NOTE_B4, NOTE_G4, NOTE_G4, NOTE_B4, NOTE_D5, 0, 
    NOTE_D5, NOTE_C5, NOTE_B4, NOTE_A4, NOTE_G4
};

// note durations stored in PROGMEM
const uint8_t noteDurations[] PROGMEM = {
    2, 2, 2, 2, 4, 4, 4, 4, 4, 2, 2,
    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 
    4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 
    4, 4, 4, 4, 4
};

void myDelayMicroseconds(uint32_t us) {
    while (us--) {
        _NOP();
        //_NOP();
    }
}

void myTone(uint16_t frequency, uint32_t duration) {
    if (frequency == 0) {
        // Delay for `duration` milliseconds when frequency is 0
        myDelayMicroseconds(100*duration);  // Convert milliseconds to microseconds
        return;
    }
    uint16_t delayValue = (uint16_t)(1000000L / frequency / 2);
    uint32_t numCycles = frequency * duration / 5000;

    DDRB |= (1 << TONE_PIN);

    for (uint32_t i = 0; i < numCycles; i++) {
        PORTB ^= (1 << TONE_PIN);
        myDelayMicroseconds(delayValue);
    }

    PORTB &= ~(1 << TONE_PIN);
}

void setup() {
  for (int thisNote = 0; thisNote < 37; thisNote++) {
      uint16_t thisMelody = 16*pgm_read_word(&melody[thisNote]);
      uint16_t thisDuration = pgm_read_byte(&noteDurations[thisNote]);
      int noteDuration = 500 / thisDuration;
      myTone(thisMelody, noteDuration);

      int pauseBetweenNotes = noteDuration;
      myDelayMicroseconds(100*pauseBetweenNotes);
  }

  // Initialize sleep mode
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);  // Use the most power-efficient mode
  sleep_enable();  // Enable sleep mode
}

void loop() {
  // Enter power-saving mode
  sleep_mode();  // This will put the microcontroller to sleep
}

To solder this up on a stripboard, the only thing you need to do is to cut the strips underneath the ATtiny85 so that the pins on the left side does not connect to the pins on the right side: