I admit it: I'm a total geek. I love electronics, programming, 3D printing, 3D art, and vintage Apple hardware. I'm always juggling half a dozen projects. I also enjoy documenting it all: my successes, my failures, my experiences... and everything geeky along the way.
The other day I was thinking of some fun little things I could bang out while waiting for my Arduino LCD PCB and parts to come in when I imagined a little box that could sit on your desk.
It’s a very nondescript, innocent looking box with a red button.
What does it do?
I imagine if you had this box sitting on your desk at work and someone was to come along, they’d see it sitting there, wonder what it was, pick it up and press the button. FART!
Yes. It farts. That’s pretty funny.
I thought up a prototype of what I envisioned it would use. It’s simple. All I need is a button and a speaker. I had three buttons on my breadboard already, so I’ll just use them for now. The final build will only have 1 button. I imagine I’ll just randomly pick a different fart with each button press.
I’ve seen all kinds of .mp3 playback solutions on the web, but I want to bang this one out with what I already have. I want it to use the least amount of parts possible, so it fits in the smallest box possible. I don’t want to spend $25 on an .mp3 breakout board for this. This is really a $5 project. I want to see if I can just save an audio file directly to the ATmega without using any external storage or interface boards. I happened across this link that showed me exactly how to do it.
I then Googled for a fart soundboard web site, found it, and captured 3 audio clips. I then pulled the sound clips into Logic and trimmed them down as much as I could to save chip space. Remember, I only have 32K to play with. I then dumped the 3 audio clips into iTunes and converted them to 8 KHz / 8-bit mono samples. One file came out to be 4K with the other two each being 3K.
I then converted them to numeric strings by passing them through the EncodeAudio app. I then pasted them into my sketch:
I compiled it and it fills up 21,406 bytes on the chip. Wow, almost full with 3 seconds of audio. Looks like this chip has just about a 4-fart max. I just might have to add one more!
I uploaded it and tried it out. Works like a charm. The speaker is much bigger than the box I’d like it to be in. We’ll see what I can find. I have a whole bunch of speakers lying around. It’s not that loud though. I might have to put an amplifier on it. At least it works as a proof of concept.
Here’s it in action:
I agree, it’s not very loud. It definitely needs an Op Amp. I dug through my parts and found that I had a few LM386s to spare. I threw together a quick circuit to try things out. It does a good job of making it louder.
Here’s the schematic…
…and a closeup:
Finally, a before and after comparison video:
Not bad. It does what it does. I would however like the Atmel to power down when idle. I don’t want the battery to drain down after a few weeks just sitting on my desk. Actually, the battery could be dead after just a few days.
Next up……sleep mode!
I tweaked my sketch so that after a button press, it plays a fart noise, and then powers down. I figured while I was at it, I’d have it pick a random fart too, so that I can get the circuit down to just one button.
#include "PCM.h" //audio playback library
#include "avr/interrupt.h" //for sleep
#include "avr/power.h" //for sleep
#include "avr/sleep.h" //for sleep
#include "avr/io.h" //optional
int buttonOne = 2; // pushbutton connected to pin 2
long randNumber;
//fart 1
const unsigned char fart1[] PROGMEM = {
///very long string of numbers……
};
//fart 2
const unsigned char fart2[] PROGMEM = {
///very long string of numbers……
};
//fart 3
const unsigned char fart3[] PROGMEM = {
///very long string of numbers...…
};
void setup()
{
pinMode (buttonOne, INPUT);
}
void loop(void)
{
randNumber = random(1, 4); // random fart picker
if ((digitalRead(buttonOne) == HIGH) && (randNumber == 1)) {
playFartOne();
}
if ((digitalRead(buttonOne) == HIGH) && (randNumber == 2)) {
playFartTwo();
}
if ((digitalRead(buttonOne) == HIGH) && (randNumber == 3)) {
playFartThree();
}
if (digitalRead(buttonOne) == LOW) { //no button pressed, wait 1.5 seconds then go to sleep //2 seconds is too long between loops if you want multiple presses
delay(1500);
sleepNow();
}
}
void sleepNow(void)
{
//Set pin 2 as interrupt
attachInterrupt(1, pinInterrupt, HIGH);
delay(100);
//specify sleep mode
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
// Set sleep enable bit
sleep_enable();
// go to sleep
sleep_mode();
// Upon waking up, continues from this point.
sleep_disable();
//main loop resumes
}
void playFartOne()
{
startPlayback(fart1, sizeof(fart1));
}
void playFartTwo()
{
startPlayback(fart2, sizeof(fart2));
}
void playFartThree()
{
startPlayback(fart3, sizeof(fart3));
}
void pinInterrupt(void)
{
detachInterrupt(0);
}
And another demo….. You can see it pick a random fart and then go to sleep. Well, you can’t “see” that it’s gone to sleep, but it has.
I’ll have to think about how I’m going to kill power to the op amp too. Maybe I’ll just throw in a relay. I happen to have a few reed relays in the parts bin. I hooked one up and tried it out.
I thought a PNP transistor would be a more elegant solution, but my 3906s don’t pull enough current to drive the LM386. I cold get fancy with a Darlington pair, but it’s not for all of that. The relay works a treat. I threw an LED in parallel with the op amp so you can see that the supply to the LM386 cuts out when the Arduino powers down.
Here’s the final schematic:
Now, do I etch a board, or just solder it all into a protoboard? I guess it all depends on the box it’s going in. That depends on the batteries I use. Hummmmm…….