For my friend's birthday, I made her a theater-themed electronic card that sings happy birthday. The outside looks like a theater announcement, and the inside looks like a movie marquee. My girlfriend printed both graphics on a Cricut machine, and they look much better than what I could have come up with myself.
The hardware is pretty simple. The top part, which flips up to show the marquee, is a simple 3D-printed box. My original plan was to use the box as the bottom part to hold the battery and electronics. After waiting six hours for the part to print, I realized it wasn't tall enough to hold the LEDs of the marquee, so the part became the lid instead of the base. For the bottom part, I cut a piece of plexiglass from the hardware store and printed standoffs to attach it to the circuit board. This was my first time working with plexiglass, which turned out to be very easy to crack or break while working with. It's neat to have some experience with it in case another project needs a plexiglass case.
The movie marquee inside has 20 LEDs in total around the edge. They are arranged in five groups of four LEDs with an NPN transistor controlling each group. The groups are interspersed so that each fourth LED is in the same group and shares the same brightness. The blinking pattern rotates clockwise with the brightest LEDs in the front of the pattern so the other LEDs look like they are fading and trailing the brightest one. This looks better than just lighting up one group at a time. The brightness is controlled by simple software PWM running on an MSP430. A timer fires every 1,000 cycles giving 16,000 steps per second since the microcontroller runs at 16MHz. Every time through the loop, the code to adjust the PWM executes then blocks on a while loop waiting for the timer to finish it's 1,000 cycles. This keeps the brightness uniform since a step always takes the same amount of time regardless of how long the PWM code needs.
16,000 steps per second is way more than needed to adjust LED brightness. The extra granularity is useful for controlling the small piezo buzzer that plays happy birthday. The music consists of simple beeps from the speaker, which only takes a few dozen bytes to store and has no problem fitting in the MSP430's flash. The music notes start out as raw frequency values beginning with A at 440Hz. A series of C macros let me calculate how many steps each note needs including a short bit of silence at the end of each one. While I try to avoid overreliance on macros, in this case they really helped list everything in a clear way. Specifying the notes to be played was then very easy:
const unsigned int music_notes[]={
NOTE(NOTE_C,EIGTH),
NOTE(NOTE_C,EIGTH),
NOTE(NOTE_D,QUARTER),
NOTE(NOTE_C,QUARTER),
NOTE(NOTE_F,QUARTER),
NOTE(NOTE_E,HALF),
...
MUSIC_END};
My first try at playing notes in a scale was noticeably off, and two of the notes had the same tone. It took some investigating to figure out that the way I had the timer calculations listed based on the frequency was rounding the highest frequency notes down to a small integer which was between two recognizable notes. This is what lead to the two notes sounding the same since they'd been rounded to the same value. One helpful thing I've started to do since getting interested in assembly language is turning on listing files in the compiler to see what assembly is generated. This showed that the values calculated where way too small, which I double checked with
Compiler Explorer. Listing files are a great tool that have helped me solve several bugs like this. After adjusting the calculation macros, the notes sounded just right, and happy birthday played correctly.
Soldering everything together was a bit of a challenge. The top PCB with the LEDs has the paper with the happy birthday graphic attached to it, so none of the wiring for the LEDs could go completely through the board since they would have to penetrate the paper too. Instead, all of the wires and resistors are soldered flat on the back. This is a technique that might come in handy someday for something else.
The MSP430, transistors, and buzzer are on a small separate PCB sandwiched between the top PCB and a piece of plexiglass. The battery pack and on/off switch are attached to the plexiglass with hot glue. Although I've never been very impressed with the durability of hot glue, whatever type I got from the craft store this time is absurdly strong and was more than good enough for this project.