I had a great time making SMD LED Christmas cards (which double as tree ornaments) back in December:
However, I only managed to make 3 out of 13 in time after parts and PCBs finally arrived. My mom's birthday is today so a couple of weeks ago I decided I'd repurpose one of the remaining PCBs to make a musical Birthday card:
I found this card at Walgreens, and it seemed pretty fitting. The speaker was scavenged from a different electronic Hallmark card. I originally tried a couple piezo speakers I had in my parts bin, but it sounded much better. The speaker leads are connected to the pads for one of the LEDs. The board is designed with a series resistor connected to each LED. I only had 390 ohms SMD resistors, and speaker was softer than I wanted with that resistance. So I removed the SMD resistor, shorted that pads with solder, and then soldered a through-hole resistor between one speaker lead and LED pad. I wish I would have taken a picture of the other side of the board as I'm having trouble remembering the value, but I believe it was 82 ohm.
I also soldered 4 LEDs onto the board to give a visual effect beneath the illustrated phone on the front of the card:
The LEDs and speaker are all controlled by the same AVR pin, so the LEDs blink in rhythm with the melody. Unfortunately, only the yellow LED was bright enough to be seen through the card. The tactile switch on the board is positioned under the bottom of the illustrated phone's keypad. The Happy Birthday melody will play once when that switch is pressed, and then the chip will go to sleep until pressed again.
I used this source code from Nerd Kits as the basis for playing Happy Birthday:
However, I had to make some changes as it was written for an AVR ATtiny26 while my board uses a ATtiny13. The challenge was to determine which delay value on the ATtiny13 generated an A5 note which is 880Hz. I set the fuses so that that ATiny13 runs as 9.6MHz on internal RC with no clock divider. If not already set, the fuses can be set via avrdude (note that I am using an Adafruit USBtinyISP programmer):
avrdude -c usbtiny -p attiny13 -i 5 -U hfuse:w:0xFF:m -U lfuse:w:0x7A:m
And, for reference, this is how I would compile the source code and program the AVR:
avr-gcc -mmcu=attiny13 -Os -o happycard.out happycard.c avr-objcopy -O ihex -R .eeprom happycard.out happycard.hex sudo avrdude -c usbtiny -p attiny13 -U flash:w:happycard.hex
The Nerdkits code uses the standard AVR libc delay functions to handle the timing of playing notes. However, when attempting to use them in my ATtiny13 program, I ran into cryptic avr-gcc errors. After some searching, I discovered this was an indication that I had run out of Flash memory to store the program code after linking that library. I was surprised but the ATtiny13 is a minimalist part with only 1K flash memory and 64 bytes internal SRAM.
Thus, I decided would construct my own simple microsecond delay loop. Unfortunately, I couldn't get the duration of my microsecond delay function below 1.23 microseconds (which I observed with my scope, the Rigol DS1052E). While I may have been able to optimize it, I decided I would just modify the note definitions from the Nerd Kit source code to compensate. I did so by copying the #define statements for the notes into a separate text file, processed with this perl one-liner and then copied the adjusted #define's back into the source code:
cat notes.txt | perl -ne 'chomp; ($a, $b, $c) = split(/ /); print "$a $b " . int(($c/.81)) . "\n";'
I then modified the source code to output just a single note, A5, and check the frequency with my scope (a DMM with a Hz function would also work). I was within a few Hz of 880, so I was satisfied.
After adding all the notes back from the Nerd Kits code, I noticed the melody didn't sound quite right. I looked up the sheet music for a happy birthday from a couple sources online and decided to adjust the duration of a couple notes accordingly. I also added a brief break in between playing each note. With these changes, the melody sounded much more accurate.
I've attached the source code, happycard.c, to this blog post.
happycard.c.zip 1.1 KB