Here’s the situation, boys. There aren’t many win-win situations when it comes to relationships so when you see one you need to take note. Chicks love it when you make them crap (from the heart) on Valentine’s Day. When you invest your particular whatever-it-is into the greatest waste of all-time – No, not World War 2 – the chicks go bonkers. The trick is to only apply the facade of your craft towards the actual Valentine’s Day thing. The rest should simply be a masturbatory experience as you do what you do. The girl won’t care as long as it has a heart on it.
I call this creation “Love Machine”. It’s a simple LED dot matrix with a MAX7219 that you can get from eBay for a couple of bucks powered by an Arduino Mini Pro (another couple eBay bucks) and modify pre-existing code to knock down the inhibitions of your loved one. I stole my code from Beating heart with Arduino and a MAX7219 8×8 LED matrix and modified it a bit.
The big mess for me was I wanted this one to be battery powered. This meant I had to go down the rabbit hole of interrupts and low-power Arduino malarkey.
Arduino Low Power Tips
1) Find a way to bypass the voltage regulator and toss your voltage straight into VCC. That voltage regulator is a disaster for chewing up current when the Arduino isn’t even awake. I’ve had great luck with running 4 rechargeable LiPO batteries. When fully charged, mine are running at 5.3V. I do want to figure out a LDO voltage regulator-type solution or maybe just use a 5V Zener to make sure voltage doesn’t go over 5V. Regardless, irresponsibly using 5.3V has caused no problems thus far. Another huge benefit is when you screw up your design, you can simply recharge the batteries and cuss the thing the next day.
2) Use a button press to get this booger to wake up from sleep. I didn’t find too many tutorials that covered this in a learn-it-in-4-seconds kind of way, but it turned out the code is quite straight forward.
I put this towards the top of my main loop. I’m using the Low Power library from Rocketscream.
attachInterrupt(0, wakeUp, LOW);
LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); // SLEEP_8S
detachInterrupt(0);
This basically put the Arduino to sleep until Pin #2 was grounded. (Interrupt #0 is Pin #2 on Arduino. Don’t ask.)
3) Destroy the power-on LED on the Arduino. This LED sucks current no matter if the Arduino is asleep or not. (Technically, we are putting the ATMEGA328P to sleep and a good chunk of the extra Arduino crap is probably still running.) I used solder whick and desoldered a side just enough to kill the LED.
4) After you have the Arduino asleep and have ditched the voltage regulator and power-on LED, the rest of the low-power mods cross the point of diminishing return. I may be missing a thing or two, but if turning off X feature on the Arduino only saves me a nanoamp, I really don’t care for this project. Maybe someday I’ll do something more mission-critical.
The Code
Again, 95% of this code was stolen from Beating heart with Arduino and a MAX7219 8×8 LED matrix.
#include <LowPower.h>
int wakeUpPin = 2; // choose the input pin (for PIR sensor)
int ANIMDELAY = 100; // animation delay, deafault value is 100
int INTENSITYMIN = 0; // minimum brightness, valid range [0,15]
int INTENSITYMAX = 8; // maximum brightness, valid range [0,15]
int DIN_PIN = 5; // data in pin
int CS_PIN = 3; // load (CS) pin
int CLK_PIN = 4; // clock pin
// MAX7219 registers
byte MAXREG_DECODEMODE = 0x09;
byte MAXREG_INTENSITY = 0x0a;
byte MAXREG_SCANLIMIT = 0x0b;
byte MAXREG_SHUTDOWN = 0x0c;
byte MAXREG_DISPTEST = 0x0f;
const unsigned char heart[] =
{
B01100110,
B11111111,
B11111111,
B11111111,
B01111110,
B00111100,
B00011000,
B00000000
};
void setup ()
{
pinMode(DIN_PIN, OUTPUT);
pinMode(CLK_PIN, OUTPUT);
pinMode(CS_PIN, OUTPUT);
pinMode(wakeUpPin, INPUT_PULLUP); // declare sensor as input
Serial.begin(57600);
Serial.print("whatever");
delay(1000);
// initialization of the MAX7219
setRegistry(MAXREG_SCANLIMIT, 0x07);
setRegistry(MAXREG_DECODEMODE, 0x00); // using an led matrix (not digits)
setRegistry(MAXREG_SHUTDOWN, 0x00); // in shutdown mode setRegistry(MAXREG_SHUTDOWN, 0x01); // not in shutdown mode
setRegistry(MAXREG_DISPTEST, 0x00); // no display test
setRegistry(MAXREG_INTENSITY, 0x0f & INTENSITYMIN);
// draw hearth
setRegistry(1, heart[0]);
setRegistry(2, heart[1]);
setRegistry(3, heart[2]);
setRegistry(4, heart[3]);
setRegistry(5, heart[4]);
setRegistry(6, heart[5]);
setRegistry(7, heart[6]);
setRegistry(8, heart[7]);
}
void loop ()
{
Serial.print("1");
digitalWrite(13, LOW); // turn the LED on (HIGH is the voltage level)
delay(1000);
attachInterrupt(0, wakeUp, LOW);
LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); // SLEEP_8S
detachInterrupt(0);
setRegistry(MAXREG_SHUTDOWN, 0x01); // not in shutdown mode
digitalWrite(13, HIGH); // turn the LED on (HIGH is the voltage level)
heart_blink();
heart_blink();
heart_blink();
heart_blink();
setRegistry(MAXREG_SHUTDOWN, 0x00); // shutdown mode
delay(1000);
}
void heart_blink ()
{
// second beat
setRegistry(MAXREG_INTENSITY, 0x0f & INTENSITYMAX);
delay(ANIMDELAY);
// switch off
setRegistry(MAXREG_INTENSITY, 0x0f & INTENSITYMIN);
delay(ANIMDELAY);
// second beat
setRegistry(MAXREG_INTENSITY, 0x0f & INTENSITYMAX);
delay(ANIMDELAY);
// switch off
setRegistry(MAXREG_INTENSITY, 0x0f & INTENSITYMIN);
delay(ANIMDELAY*6);
}
void setRegistry(byte reg, byte value)
{
digitalWrite(CS_PIN, LOW);
putByte(reg); // specify register
putByte(value); // send data
digitalWrite(CS_PIN, LOW);
digitalWrite(CS_PIN, HIGH);
}
void putByte(byte data)
{
byte i = 8;
byte mask;
while (i > 0)
{
mask = 0x01 << (i - 1); // get bitmask
digitalWrite( CLK_PIN, LOW); // tick
if (data & mask) // choose bit
digitalWrite(DIN_PIN, HIGH); // send 1
else
digitalWrite(DIN_PIN, LOW); // send 0
digitalWrite(CLK_PIN, HIGH); // tock
--i; // move to lesser bit
}
}
void wakeUp()
{
// Just a handler for the pin interrupt.
}