Wednesday, September 30, 2020

Gadgets - An Octal Clock

 

I have always been fascinated with using colors to represent numeric data, and finally brought this idea to fruition with a four "digit" clock. Why octal? Because I haven't been able to reliably distinguish ten colors. The colors used - representing zero through seven -  are white, red, orange, yellow, green, aqua (cyan), blue, and magenta, rendered on neopixels. The image above shows orange-aqua : magenta-white, ie 25:70 in octal, which is (2x7)+5: 7x7 in decimal ie 19:49 (7.49 for 12 hour folk).

The container is 3D printed. The front face has a series of thick cones printed into the back of it, preventing light bleed to the adjacent spots, each of which is a seat for a neopixel. The back contains a USB power inlet and buttons to set hours and minutes. The processor is an arduino nano, conveniently getting the power, and it is connected to a real time clock as well as the neopixels. 

 

Code and hookup details below:


// Octal clock. Hours and minutes each represented by two color lights hhmm
// digits represented by colors 0=white, 1=red, 2=orange, 3=yellow, 4= green
// 5=aqua, 6=blue, 7 = magenta
// Date and time functions using a DS3231 RTC connected via I2C and Wire lib
#include <Wire.h>
#include "RTClib.h"
RTC_DS3231 rtc;
// adafruit neopixel 4 pixels
// wiring: d8 to hour button, NO to ground; d5 to neopixel; d9 to minute button NO to ground
// wiring: a5 to SCL; a4 to SDA on 3231
#include <Adafruit_NeoPixel.h>
#define PIN 5
Adafruit_NeoPixel strip = Adafruit_NeoPixel(12, PIN, NEO_GRB + NEO_KHZ800);
#define HOUR_PIN 8
#define MINUTE_PIN 9
//#define SET_PIN 7
#define DEBOUNCE_DELAY 10
#define MAX_BUTTONS_INPUT 20
// 3 one dimensional arrays to hold color values
//numbers 0   1   2  3   4   5   6   7
// colors w   r   o  y   g   c   b   m
int r[]={40 ,110,100,70 ,0  ,0  ,0  ,70 };
int g[]={36 ,0  ,15 ,60 ,90 ,60 ,0  ,0  };
int b[]={20 ,0  ,0  ,0  ,0  ,15 ,100,60 };

void setup () {
  Serial.begin(9600);
  rtc.begin();
  rtc.adjust(DateTime(2014, 1, 21, 21, 57, 30)); //Plug in clock at correct time, no need for resets
  strip.begin();
  strip.show(); // Initialize all pixels to 'off'

  pinMode(HOUR_PIN, INPUT_PULLUP);
  pinMode(MINUTE_PIN, INPUT_PULLUP);
  //pinMode(SET_PIN, INPUT_PULLUP);
}

  int lastButtonValue[MAX_BUTTONS_INPUT];
  int currentButtonValue[MAX_BUTTONS_INPUT];


void loop () {
 
  //int set_button = debounce(SET_PIN);not used in this implementation
  int hour_button = debounce(HOUR_PIN);
  int minute_button = debounce(MINUTE_PIN);
 
 
  if(hour_button && hasChanged(HOUR_PIN))
  {
    DateTime newTime = DateTime(rtc.now().unixtime()+3600);//blocks of 1 hour
    rtc.adjust( newTime );
  }
  if(minute_button && hasChanged(MINUTE_PIN))
  {
    DateTime newTime = DateTime(rtc.now().unixtime()+60);//blocks of 1 minute
    rtc.adjust( newTime );
  }
 
 
    DateTime now = rtc.now();
    
 
    //int s=now.second();
    int m=d2o(now.minute());//get octal value of minutes
    int h=d2o(now.hour());//get octal value of hours

    //split into individual digits
    
    int m1=(m/10);
    int m0=(m-10*(m/10));
    int h1=(h/10);
    int h0=(h-10*(h/10));
    int c[]={h1,h0,m1,m0};
    
//    Serial.println (h0);
//    Serial.println (m1);
//    Serial.println (m0);

    strip.setPixelColor(0, r[h1],g[h1],b[h1]); //h1, hour 10s
    strip.setPixelColor(1, r[h0],g[h0],b[h0]); //h0, hour 1s
    strip.setPixelColor(2, r[m1],g[m1],b[m1]); // m1, min 10s
    strip.setPixelColor(3, r[m0],g[m0],b[m0]); //mo, min 1s

   
    strip.show();

    delay(300);
    
    //cleanup (not needed in this implementation)
   
//    strip.setPixelColor(0, 0,0,0);
//    strip.setPixelColor(1, 0,0,0);
//    strip.setPixelColor(2, 0,0,0);
//    strip.setPixelColor(3, 0,0,0);
//    
    //strip.show();
}

//end of main loop

//functions

int debounce(int pin) //inverting output for internal pullup
{
  int val = !digitalRead(pin);
  if( val == lastButtonValue[pin] )
  {
    currentButtonValue[pin] = val;
    return val;
  }
    
  delay(DEBOUNCE_DELAY);
 
  val = !digitalRead(pin);
  if( val != lastButtonValue[pin] )
  {
    currentButtonValue[pin] = val;
    return val;
  }
 
  currentButtonValue[pin] = lastButtonValue[pin];
  return lastButtonValue[pin];
}

boolean hasChanged(int pin)
{
  return lastButtonValue[pin] != currentButtonValue[pin];
}

int d2o(int decimalnum) //decimal to octal conversion
{
    int octalnum = 0, temp = 1;

    while (decimalnum != 0)
    {
      octalnum = octalnum + (decimalnum % 8) * temp;
      decimalnum = decimalnum / 8;
        temp = temp * 10;
    }

    return octalnum;
}

No comments:

Post a Comment