Introduction: Office Cube Hour Glass

In my last full time employment I found myself in a nondescript cube counting down the hours to lunch and then till quitting time. There were four hours till lunch, a one hour break and the another four hours till the end of the day. It varied very little from that. There were conference calls to take up some of the time, but I realized I was just counting down four hours and repeating it after lunch. So I devised an animated hour glass. The display is an 8x8 LED matrix representing sand dripping through an hour glass. It takes 4 hours. Then the whole display rotates 180 degrees in a one hour period, after which the animated sand displays again for 4 hours. The Arduino does the counting, displaying and servo control. During development I added a "demo" switch to show the display and servo operation in a shorter time span.
Once the code was worked out with a friend's help, it was wired up on a breakout board.The prototype uses an Arduino Uno; An Adafruit LED matrix and backpack. This way you can use I2C for driving the display with 4 pins; A servo from Parallax as I needed one that could rotate 180 degrees. I tried a simple RC servo, but it did not rotate 180 degrees only 90. To use "Demo" mode, hold down the pushbutton while applying power or pressing the reset on the Arduino board. The Matrix will scroll "DEMO MODE"

Step 1: Obtain Parts

1 x Ardunio Uno
1 x Parallax Servo ( 180 degree rotation)
1 x Adafruit 8x8 LED Matrix with I2C
1 x Momentary pushbutton

The Arduino IDE for loading the software.
Adafruit provides a comprehensive library for handling the LED matrix.
Hour Glass sketch.

For a finished hour glass you could burn an Arduino with the boot code and program code and save money on using a whole Arduino Uno. You will also need a box to hold the components while allowing the servo to rotate the LED Matrix. Make sure the wires are flexible enough to allow the servo to rotate without snags or too much wire tension. You will have to consider batteries or a wall wart supply for power.

Step 2: Wiring

I used a breakout board to test everything out. I also put the diagram into Fritzing. See the diagrams for details. Basically, the LED Matrix is driven from two pins on the Arduino as per the instructions in the Adafruit library A4 and A5. The servo is driven from pin 9. As I mentioned I added a "demo" button. This is connected to pin 2 and ground. I followed the instructions in the Ardunio cookbook for wiring up this switch and the servo information.

Step 3: Software

The software is written in Processing and downloaded through the Arduino IDE. The code contains a loop that takes 9 hours to complete, well 10 to put the display back in to original position. But hopefully, you will be leaving the "Office" after the second four hour loop and power the gadget off. Upon powering on it will reset the servo to the home position. Inside this main loop, which is set to run forever, are two four hour loops, and two one hour loops.

Code breakdown: Actual code in italics, comments in bold. Here is a link to the code so you don't have to cut and paste if you wish to use it.

https://github.com/robboz4/Hour-Glass/tree/July-Entry

If you do decide to use the codes please include all statements regarding the use of Adafruit libraries.



#include
#include

#include


Basis includes for debug statements to the serial port, the Servo library, and the I2C library.

#include "Adafruit_LEDBackpack.h"
#include "Adafruit_GFX.h"


These two are the libraries for the Adafruit LED matrix and backpack. There is a block of text describing the use of these libraries that is listed in the code.

#define MORNING 0
#define AFTERNOON 1
#define MAX_SEQ_NUM 17


Adafruit_8x8matrix matrix = Adafruit_8x8matrix();

Servo myservo;
int pos = 0;
int interval;
const int buttonPin = 2; // the number of the pushbutton pin
const int ledPin = 13; // the number of the LED pin
int buttonState = 0;


Definitions for the use later on in the code.

void setup() {


Serial.begin(9600);


Serial.println("8x8 LED Matrix Test mod by robbo");

matrix.begin(0x70); // pass in the address of the I2C
matrix.setBrightness(2);
matrix.clear();
myservo.attach(9,544,2300); // Set up Servo
myservo.write(pos);

// initialize the LED pin as an output:
pinMode(ledPin, OUTPUT);
// initialize the pushbutton pin as an input:
pinMode(buttonPin, INPUT);
digitalWrite(buttonPin,HIGH);
}


Set up the matrix, the servo, pushbutton and serial port ( for debug statements).

typedef struct _led
{
char order;
int x;
int y;
} led_t;


// An array to define the LED layout (a pin number of 0 means no LED)
// Each array member has a sequence number and a LED pin number.
// The sequence number determines the order in which they switch on or off


const led_t ledArray [8][7] = {
/* elem 0 */ {{6, 0, 0}, {4, 0, 1}, {2, 0, 2}, {1, 0, 3}, {3, 0, 4}, {5, 0, 5}, {7, 0, 6}},
/* elem 1 */ {{0, 1, 0}, {11, 1, 1}, {9, 1, 2}, {8, 1, 3}, {10, 1, 4}, {12, 1, 5}, {0, 1, 6}},
/* elem 2 */ {{0, 2, 0}, {0, 2, 1}, {14, 2, 2}, {13, 2, 3}, {15, 2, 4}, {0, 2, 5}, {0, 2, 6}},
/* elem 3 */ {{0, 3, 0}, {0, 3, 1}, {0, 3, 2}, {16, 3, 3}, {0, 3, 4}, {0, 3, 5}, {0, 3, 6}},
/* elem 4 */ {{0, 4, 0}, {0, 4, 1}, {0, 4, 2}, {16, 4, 3}, {0, 4, 4}, {0, 4, 5}, {0, 4, 6}},
/* elem 5 */ {{0, 5, 0}, {0, 5, 1}, {15, 5, 2}, {9, 5, 3}, {14, 5, 4}, {0, 5, 5}, {0, 5, 6}},
/* elem 6 */ {{0, 6, 0}, {12, 6, 1}, {8, 6, 2}, {4, 6, 3}, {7, 6, 4}, {13, 6, 5}, {0, 6, 6}},
/* elem 7 */ {{11, 7, 0}, {5, 7, 1}, {3, 7, 2}, {1, 7, 3}, {2, 7, 4}, {6, 7, 5}, {10, 7, 6}}
};



// the loop routine runs over and over again forever:
void loop()
{


char interval = MORNING;
int seqNum = 0;
// seqNum of 0 initialise the LED array to have the top half on.
int i, j, k, limit;
int delay_mult = 60; //demo mode option.
matrix.clear();
matrix.blinkRate(0);
matrix.writeDisplay();

//Demo Mode button test
buttonState = digitalRead(buttonPin);

// check if the pushbutton is pressed.
// if it is, the buttonState is HIGH:

if (buttonState == HIGH) {
// turn LED on:
digitalWrite(ledPin, LOW);
Serial.println("Cube Hour Glass!\n"); matrix.setTextSize(1);
matrix.setTextWrap(false); // we dont want text to wrap so it scrolls nicely
matrix.setTextColor(LED_ON);
for (int8_t x=0; x>=-36; x--) {
matrix.clear();
matrix.setCursor(x,0);
matrix.print("Club");
matrix.writeDisplay();
delay(100);
}
// matrix.setRotation(3);
for (int8_t x=7; x>=-36; x--) {
matrix.clear();
matrix.setCursor(x,0);
matrix.print("Robbo");
matrix.writeDisplay();
delay(100);
}
matrix.setRotation(0);
}
else {
// turn LED off:
digitalWrite(ledPin, HIGH);
// delay_mult = 60;
Serial.println("Cube Hour Glass demo!\n");
matrix.setTextSize(1);
matrix.setTextWrap(false); // we dont want text to wrap so it scrolls nicely
matrix.setTextColor(LED_ON);
for (int8_t x=0; x>=-36; x--) {
matrix.clear();
matrix.setCursor(x,0);
matrix.print("DEMO");
matrix.writeDisplay();
delay(100);
}
// matrix.setRotation(3);
for (int8_t x=7; x>=-36; x--) {
matrix.clear();
matrix.setCursor(x,0);
matrix.print("Mode");
matrix.writeDisplay();
delay(100);
}
matrix.setRotation(0);
}

//End of button test. It sets up the display to print a message saying Demo Mode if pressed. I also turned on the on board LED


while (1) //do this bit forever!
{
for (k = 0; k < MAX_SEQ_NUM; k++)
{
if (interval == MORNING)
{
for (i = 0; i < 4; i++)
{
for (j = 0; j < 7; j++)
{
if (ledArray[i][j].order > seqNum)
{
matrix.drawPixel(ledArray[i][j].x, ledArray[i][j].y, LED_ON);
matrix.writeDisplay();
}
else
{
matrix.drawPixel(ledArray[i][j].x, ledArray[i][j].y, LED_OFF);
matrix.writeDisplay();
}
}
}
for (i = 4; i < 8; i++)
{
for (j = 0; j < 7; j++)
{
if (ledArray[i][j].order <= seqNum && ledArray[i][j].order != 0)
{
matrix.drawPixel(ledArray[i][j].x, ledArray[i][j].y, LED_ON);
matrix.writeDisplay();
}
else
{
matrix.drawPixel(ledArray[i][j].x, ledArray[i][j].y, LED_OFF);
matrix.writeDisplay();
}
}
}
}
else
{
for (i = 4; i < 8; i++)
{
for (j = 0; j < 7; j++)
{
if (ledArray[i][j].order > seqNum)
{
matrix.drawPixel(ledArray[i][j].x, ledArray[i][j].y, LED_ON);
matrix.writeDisplay();
}
else
{
matrix.drawPixel(ledArray[i][j].x, ledArray[i][j].y, LED_OFF);
matrix.writeDisplay();
}
}
}
for (i = 0; i < 4; i++)
{
for (j = 0; j < 7; j++)
{
if (ledArray[i][j].order <= seqNum && ledArray[i][j].order != 0)
{
matrix.drawPixel(ledArray[i][j].x, ledArray[i][j].y, LED_ON);
matrix.writeDisplay();
}
else
{
matrix.drawPixel(ledArray[i][j].x, ledArray[i][j].y, LED_OFF);
matrix.writeDisplay();
}
}
}
}

//Depending on morning or afternoon variable, read the array to the sequence number and set the LED in the matrix (x,y position) on or off accordingly.
seqNum++;
if (buttonState == HIGH)
{
// delay((3750 * delay_mult * 4)/16);// Looks close to one minute. Therefore multiple by 60 for an hour ~= 225,000.
delay(900000);
}
else
{
delay(3750); //Demo mode.
}
}


//Rotate the display
interval = (interval == MORNING) ? AFTERNOON : MORNING;

if (interval == AFTERNOON)
{
// pos = 180;
// myservo.write(pos);
// delay(1000);
for(pos = 0; pos < 180; pos += 3) // goes from 0 degrees to 180 degrees
{ // in steps of 3 degree
myservo.write(pos); // tell servo to go to position in variable 'pos'
// waits 1 minute(debug) for the servo to reach the position Use the hour mulitplier 225k
if (buttonState == HIGH)
{
// delay(3750 * delay_mult);// Looks close to one minute. Therefore multiple by 60 for an hour ~= 225,000.
delay(60000);
}
else
{
delay(1000);//demo mode.
}
}
}
else
{


for(pos = 179; pos > 0; pos -= 3) // goes from 180 degrees to 0 degrees
{ // in steps of -3 degree
myservo.write(pos); // tell servo to go to position in variable 'pos'
// waits 1m (debug) for the servo to reach the position Use the hour mulitplier 225k
if (buttonState == HIGH)
{

delay(60000);
}
else
{
delay(1000); //demo mode.
}
}
}

seqNum = 0;
}

}

Step 4: To Do

I need to design a case and mounting hardware for either a desktop or cubicle. That is the next project learning to use my Replicator to print a 3D case. Also looking at the available LED Matrices it might be possible to build an even bigger version. Also there are plenty of pins left on the Arduino for other items to add. Extra displays could be added via the I2C bus if I read the documents correctly. In summary the project is expandable.

Arduino Contest

Participated in the
Arduino Contest