Get Dressed Motivator (Max’s Stopwatch)

Dumb Intro

This was my first experiment with mind control using an Arduino. My 4-year-old inherited his dad’s ability to become completely sluggish and relentlessly useless when he doesn’t give a crap about the task at hand. Unfortunately, my kid’s passions do not extend to getting dressed in the morning. So, I did what any aspiring engineer would do. I tapped in this incessant need to win. I build what amounts to a stop watch.

The Stopwatch

This is a good meat-n-taters project that everyone should do once. I was going to power this with a battery, but decided that a 5V switching power supply (aka cell phone charger) does just fine. An Arduino Nano runs the show. A cheapo 7-segment display from eBay with a Max 7219 displays the numbers. I had scored some oversized momentary buttons from eBay (yes, the switches AND the caps are huge).

The good news is this is a “product” that’s been in use for months and actually works. That’s a rare thing in DIY land…at least for me.

Challenges

I wanted to debounce the switch. If you haven’t learned about switch debouncing, Google it. It’s essential. I considered doing the debouncing in hardware, but decided I wanted to do in code for whatever reason. Arduino comes with a debounce for switches that stay open or closed, but I didn’t find anything for a momentary switch. When a momentary switch is pushed, the usual nasty “bouncing” occurs and then when it is let go, yet another bouncing occurs. This adds a little bit of interest to the debouncing problem.

AutoCAD Files

Max Stopwatch AutoCAD Export
I was excited about getting the presentation right. Since my target audience was a 4-year old, it wouldn’t take much. I wanted him to see the electronics but when he inevitably shoved his greasy, chocolate-covered fingers in there, I didn’t want him tearing it up (or getting shocked). I put the thing together in AutoCAD, printed it out at a perfect 1:1 ratio on the printer, and went out to my wood shop to perfectly nail it. The only problem was I did a terrible job measuring my already-soldered buttons. I’m not so good at measuring 3D stuff. Oh well. It didn’t turn out like I was wanting, but I decided to spend my summers hacking satellite positioning systems and opted not to focus on the plexiglass of this project too much.

The Code

There is nothing too special here. I stole this code from previous projects I had done, but those projects may have involved stealing code from someone else. I hope I’ve mangled it enough so that it is, indeed, mine. If the code looks stolen, email me so I can give credit to the original source.



// include the library for MAX72XX
#include "LedControl.h"
#include <avr/sleep.h>

int v = 0;
int runningFlag, thingon, pushed8;
int debounce8;
int count8;
long unsigned lasttime, timebrando, lastbeep, count8offset, buttonhottime8, activetime, offset8time;
volatile int kickthingon;
//LedControl lc=LedControl(12,11,10,1);
//LedControl lc=LedControl(Din,Clock,Load/CS,# of devices);

LedControl lc=LedControl(3, 4, 6, 1);
unsigned long delaytime=100;// v*75
void setup() {
/*
The MAX72XX is in power-saving mode on startup, we have to do a wakeup call */
// ADCSRA = ADCSRA & B01111111;
// ACSR = B10000000;
// DDRB = B00000000; // set pins 8 to 13 as inputs
// PORTB |= B11111111; // enable pullups on pins 8 to 13
// DIDR0 = DIDR0 | B00111111;
lc.shutdown(0,false);
/* Set the brightness to a medium values */
lc.setIntensity(0,8);
/* and clear the display */
lc.clearDisplay(0);
lastbeep = timebrando;
Serial.begin(57600);
pinMode(8, INPUT); // start / stop
pinMode(9, INPUT); // reset
pinMode(2, INPUT); // on / off
activetime = millis();
thingon = 1;
displayzeros();
//attachInterrupt(0, wakeUpNow, LOW); // use interrupt 0 (pin 2) and run function wakeUpNow when pin 2 gets LOW
}
void loop()
{

if (kickthingon == 1){
turnon();
kickthingon = 0;
}

 

// TURN OFF
if (digitalRead(2) == 1 and thingon == 1){
turnoff();

}

// TURN ON
if (digitalRead(2) == 1 and thingon == 0){
turnon();
}

// RESET
if (digitalRead(9) == 1 and runningFlag == 0){
v=0;
displayzeros();
activetime = millis();
}

 

// START STOP
//if (digitalRead(8) == 1 and buttonhottime8==0){
if (digitalRead(8) == 1){
buttonhottime8 = millis();
activetime = millis();
}
if (digitalRead(8) == 0){
buttonhottime8 = 0;
}
if (millis() - offset8time > 1 and count8offset > 0) {
count8offset--;
offset8time = millis();
}

if (count8offset == 0){
// tone(12, 200, 5); //tone(pin, frequency, duration)
}

Serial.println(count8offset);

//if ( buttonhottime8 < millis() - 30 - count8offset){
if ( buttonhottime8 + 20 < millis() and digitalRead(8) == 1 and count8offset==0 ){
runningFlag= !runningFlag;
count8offset=200;
buttonhottime8 = 1;

}

 

// IF INACTIVE, TURN OFF DISPLAY AND GO TO SLEEP
if (millis() - activetime > 60000) {

// turnoff();

}

 

 

if (runningFlag ==1)
{

timebrando = millis();
activetime = millis();

if (timebrando - lasttime > 100)
{
printNumber(v); // call printNumber function
// Serial.print ("running");
v=v+1;
lasttime=timebrando;
}
// THIS IS A GOOD NORMAL BEEP
if (timebrando - lastbeep > 1000) {
tone(12, 200, 5); //tone(pin, frequency, duration)
lastbeep = timebrando;
// Serial.println("beep");
}

// HUNDRED MINUTE TIME LIMIT
if (v > 60000){
turnoff();
}

}

}

// function to send digits to 7 seg led

void printNumber(int v)
{
int ones;
int tens;
int hundreds;
int thousands;
boolean zero;

ones=v%10;
v=v/10;
tens=v%10;
v=v/10;
hundreds=v%10;
v=v/10;
thousands=v%10;

lc.setDigit(0,3,(byte)thousands,false);
lc.setDigit(0,2,(byte)hundreds,false);
lc.setDigit(0,1,(byte)tens,true);
lc.setDigit(0,0,(byte)ones,false);
}

void turnoff(){
thingon = 0;
runningFlag = 0;
lc.shutdown(0,true);

delay(1000);

// PUT ARDUINO TO SLEEP
sleepNow(); // sleep function called here

}

void turnon(){
lc.shutdown(0,false);
displayzeros();
thingon = 1;
v = 0;
runningFlag = 0;
delay(300);
}

void displayzeros(){
lc.setDigit(0,3,0,false);
lc.setDigit(0,2,0,false);
lc.setDigit(0,1,0,true);
lc.setDigit(0,0,0,false);
}

void wakeUpNow() {
// execute code here after wake-up before returning to the loop() function
// timers and code using timers (serial.print and more...) will not work here.
// we don't really need to execute any special functions here, since we
// just want the thing to wake up
volatile int kickthingon = 1;
//turnon();
}

void sleepNow() {
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here
sleep_enable(); // enables the sleep bit in the mcucr register
attachInterrupt(0,wakeUpNow, LOW); // use interrupt 0 (pin 2) and run function
// digitalWrite(led, LOW);
sleep_mode(); // here the device is actually put to sleep!!
// THE PROGRAM CONTINUES FROM HERE AFTER WAKING UP
sleep_disable(); // first thing after waking from sleep: disable sleep...
detachInterrupt(0); // disables interrupt 0 on pin 2 so the wakeUpNow code will not be executed during normal running time.
}

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.