Close

Applications, part 2 (Halloween prop)

A project log for Storing and playing back lofi audio on an MCU

Software and hardware for storing 8-kHz, 8-bit (or less) audio on an AVR MCU, and playing it back

johan-carlssonJohan Carlsson 11/01/2022 at 00:110 Comments

My son and I found a well-preserved deer skull on a nature walk a while ago and immediately decided to bring it home and turn it into a Halloween prop. As usual, I got started too late and we just barely managed to get it done in time. We found a piece of scrap plywood in the garage to mount it on:

We're using an Arduino Uno clone and a HC-SR501 PIR sensor to make it cackle demonically and blink its red LED eyes. The power source is a 1.3 Ah 12 V lead-acid battery:

Left to right: battery shelf, Arduino shelf, back of speaker, PIR sensor and skull peg.

The deer skull seems really brittle, so I will just let it hang from a peg that enters the skull where the spine used to connect.

The PCB on the back of the PIR sensor has a pretty high profile, so we used some thick cardboard to protect it:

Wiring on the back is finished:

The power-amp shield and the speaker are connected with alligator clips. The deadline is looming, so it'll have to do. We'll do better next Halloween. 

Speaker, Arduino Uno clone with the Mk 2 power-amp shield, and the 12 V lead-acid battery:

The speaker has a 4" cone and is old enough to be made in Taiwan and to have an Alnico magnet, so it's quite heavy. So is the battery.

Here's a wider view of the whole shebang, with some impromptu rain proofing:

A close up during early Halloween dusk:

The evil cackling is done by the pcm-avr library I developed from scratch for this project. The sound byte is 6 s long so with 8-bit samples and 8 kHz sampling rate it would require 48 kB of flash, 50% more than the available 32 kB. So 4-bit audio it is! Here's the source code:

/* Code to make a deerskull blink its red LED eyes and cackle creepily when a PIR sensor drives the reset pin high
 *
 * Build command:
 * avr-gcc -c deerskull.c -mmcu=atmega328p -Os -o deerskull.o && avr-gcc -mmcu=atmega328p deerskull.o -o deerskull.elf && avr-objcopy -O ihex -R .eeprom deerskull.elf deerskull.hex && avrdude -v -p atmega328p -c arduino -P /dev/ttyUSB0 -b 115200 -U flash:w:deerskull.hex:i
 *
 * Copyright 2022 Johan Carlsson
 *
 */

#include "pcm-avr.h"
#include "cackle.h"

int main()
{
    /* put unused peripherals to sleep to save power */
    PRR |= (1 << PRTWI) | (1 << PRTIM1) | (1 << PRSPI) | (1 << PRUSART0) | (1 << PRADC);

    /* make PB1 an output pin (Pin 9 on ATmega328p Arduino Uno clone) */
    DDRB |= (1 << DDB1);
    /* drive PB1 high */
    PORTB |= (1 << PORTB1);

    /* cackle creepily */
    pcm_init();
    pcm_play(raudio_data, raudio_length, raudio_bitdepth);
    pcm_exit();

    /* blink once after cackling */
    PORTB &= ~(1 << PORTB1); /* drive PB1 low */
    _delay_ms(7.5e2);
    PORTB |= (1 << PORTB1); /* drive PB1 high */

    /* stare at traumatized trick-or-treaters until the PIR turns off */
    while (1);

    return 0;
}

As can be seen, the code is super simple. The microcontroller doesn't know that its reset pin is directly connected to the output pin of the HC-SR501 PIR sensor. I set the sensor to "Single Trigger", minimized the sensitivity and set the delay time to about 15 s, long enough to start the microcontroller, play back the 6 s audio clip, and turn the LED eyes on-off-on.

We were going to shoot a video of this awesomeness in action, but it just started raining, so I'll add it in an edit in a couple of days.

Edit: Here's the promised video

Some parting thoughts: the eyes are two red LEDs in series with a 47 Ohm ballast resistor (dialed in for about 20 mA current). The Mk 2 power amp (Class AB made from two TO-92 transistors, putting 0.25 W into an 8-Ohm speaker) is loud enough for outdoor use. For this kind of intermittent use a heatsink might not even be needed. A topic for future experimentation.

I think I'm now ready to declare this project successfully completed, and move on the next one! Thanks for reading!

Discussions