Simple Pixel Watch (Update to version 6)

Simple Pixel Watch (Update to version 6)
This is a simple watch using two pixel rings, a Flora and a real time clock (RTC). I wanted a less expensive and lower power consumption alternative to the NeoGeo watch. So I dropped the GPS and positioning boards in favor of a RTC. Construction is easy and fairly quick. You should have some soldering and leather working skills but this is definitely a beginner's level project.


Parts List

  • Flora (Adafruit PRODUCT ID: 659)
  • NeoPixel Ring - 12 x 5050 RGBW LEDs (Adafruit any variant)
  • NeoPixel Jewel - 7 x 5050 RGB LED (Adafruit any variant but it is best to match the pixel ring. IE. they should both be cool white or both be natural white.)
  • Real time clock (Adafruit PCF8523 Real Time Clock Assembled Breakout Board)
  • Battery and charger (Adafruit Micro Lipo w/MicroUSB Jack - USB LiIon/LiPoly charger - v1)
  • Assorted leather strips 2 ¼  to 2 ½ inches wide. (One will need to be long enough to go around your wrist and overlap 2-3 inches.)
  • 3 small push button momentary switches (I used Amazon Icstation 12 Type Mini Panel Mount Momentary Tactile Push Button Switch Assortment Kit DIP (Pack of 120))
  • Small piece of perfboard (Mine is 1 ¾ by ¾ inches)

Tools

  • Soldering iron
  • Wire cutters/strippers
  • Leather cutting scissors or a sharp knife
  • Leather hole punch
  • Optional: Thonging chisel (Makes stitching a lot easier.)

Schematic

Construction

Step 1: Glue the two pixel rings together, I couldn’t find a mark showing pixel 0 on the 12 ring so I just lined up the silk screened text on the back and then did a fine adjustment aligning the pixel LEDs on the front. Glue them together. I used hot glue but any good glue should work.
Don’t worry if pixel LED numbers don’t line up. The software has a routine to fix that. It is important that the pixel LEDs line up or your watch will look crooked.
Step 2: Solder wires to the Pixel LED array. I used 22 gauge solid wire for the connects between the pixel LED boards because I wanted the strength. I used 26 gauge stranded wire (cut from an old PBX cable) for the leads for flexibility. Do not connect the pixel LED array to the Flora yet.
Step 3: Take a small piece of perfboard and solder a 22 gauge solid wire along one side. Then add four leads, again using the 26 gauge stranded wire. The arrangement of wires should match the location where the switches will be mounted. Do not mount the switches yet.
Step 4: Punch 3 holes in the leather aligned with where the switches will connect to the perfboard.
Slide the leads of the switches through the leather into the appropriate holes in the perfboard. Bend them over and solder them into place.


Step 5: Cut a thicker piece of leather to hold your circuits.


Stitch around your perfboard, sandwiching it between the two leather pieces. I found it sufficient to only stitch above and below the perfboard. Be careful to not damage any of the leads coming from the perfboard.


Step 6: Using the 26 gauge stranded wire, attach the RTC to the Flora. Attach the leads from the perfboard to the Flora. I attached the left button to pin 12 of the Flora, middle switch to pin 6 of the Flora and the right button to pin 9 of the Flora.


Step 7: Punch a hole in the light leather arm band where you want the pixel array to be. Pass the leads from the pixel array through the hole and attach them to the Flora. Do not glue down the pixel array yet.


Step 8: Attach the Flora, RTC and LiPo battery to the heavy leather piece. I used a combination of heavy cotton twine, copper wire and hot glue.
Step 9: Connect the Flora to your PC and instal the sketch. The default time on startup is 11:05.
Press the middle button. If everything is correct you should see the hour hand (red led) should be to the left of 12 and the minute hand (blue led) should be to the right of 12 on the outer ring. The blue led on the inner ring should also be at the 12 position. Quickly take note of the actual locations so we can adjust them in the code.


Step 10: Align the 12 position of the inner ring (where you noted the blue led in step 9) toward the top of your watch and glue the pixel array in place. Optionally you can add a bezel around the pixel array. I used a piece of luan.


Step 11: Add snaps, buckles, velcro or whatever closure you have decided to use to the ends of the thin leather strap. I used snaps. The physical construction is complete.


Sketch (Software)

#include <RTClib.h> #include <Adafruit_NeoPixel.h> #include <Time.h> #include <TimeLib.h> #define timePIN 6 #define menuPIN 9 #define advPIN 12 #define pixPIN 10 Adafruit_NeoPixel pixels = Adafruit_NeoPixel(19, pixPIN); const int pressed = 0; const int outerRingOffset = 3; RTC_PCF8523 rtc; bool inmenu = false, inBrite = false; int mode = 0, ssec = 0, esec = 10, showFlash = 0, menuDelay = 0, flashMode = 0, dispMode = 0; DateTime currTime = 0, dispTime = 0, syncTime = 0; uint32_t hColor = 0x700000, mColor = 0x000070, bColor = 0x400040, sColor = 0x404000, noColor = 0x000000, wColor = 0x202020; ///////////////////////////////////////////////////// Functions void clearHands() { uint8_t i; for (i = 0; i < 19; i++) { pixels.setPixelColor(i, noColor); } pixels.show(); } int adjustOuter(int raw) { int ptr = raw + outerRingOffset; if (ptr > 11) { ptr = ptr - 12; } return ptr; } void showSecOuter(DateTime showTime) { pixels.setPixelColor(adjustOuter(showTime.second() / 5), sColor); } void showHrMnOuter(DateTime showTime) { int hr = showTime.hour(); if (hr > 11) { pixels.setPixelColor(12, mColor); hr = hr - 12; } else { pixels.setPixelColor(12, sColor); } int mn = (showTime.minute() / 5); if (hr == mn) { pixels.setPixelColor(adjustOuter(hr), bColor); } else { pixels.setPixelColor(adjustOuter(hr), hColor); pixels.setPixelColor(adjustOuter(mn), mColor); } } void showCardinal() { pixels.setPixelColor(adjustOuter(3), wColor); pixels.setPixelColor(adjustOuter(6), wColor); pixels.setPixelColor(adjustOuter(9), wColor); pixels.setPixelColor(adjustOuter(0), wColor); } void showMnInner(DateTime showTime) { int mn = (showTime.minute() % 5) + 12; pixels.setPixelColor(mn, mColor); } void showNum(int theNumber, uint32_t pixNum) { clearHands(); pixels.setPixelColor(17 - pixNum, 0x00000f); pixels.setPixelColor(theNumber / 12 + 13, sColor); pixels.setPixelColor(adjustOuter(theNumber % 12), sColor); pixels.show(); } int getNum(int startNum, int limit, uint32_t pixNum, int adj) { if (startNum > 2000) { startNum = startNum - 2000; } showNum(startNum, pixNum); do { if (digitalRead(menuPIN) == pressed) { do { } while (digitalRead(menuPIN) == pressed); delay(1000); return startNum; } if (digitalRead(advPIN) == pressed) { do { } while (digitalRead(advPIN) == pressed); delay(1000); startNum = (startNum + 1); if (startNum > limit) { startNum = 1; } showNum(startNum, pixNum); } if (digitalRead(timePIN) == pressed) { do { } while (digitalRead(timePIN) == pressed); delay(1000); startNum = (startNum + adj); if (startNum > limit) { startNum = 1; } showNum(startNum, pixNum); } } while (1 == 1); } //////////////////////////////////////////////////// Faces void caFlash() { uint8_t i; clearHands(); pixels.setPixelColor(12, hColor); //Center pixels.show(); delay(500); for (i = 13; i < 19; i += 2) { // Odd Inner On pixels.setPixelColor(i, wColor); } pixels.show(); delay(500); for (i = 13; i < 19; i += 2) { // Odd Inner Off pixels.setPixelColor(i, noColor); } for (i = 14; i < 19; i += 2) { // Even Inner On pixels.setPixelColor(i, wColor); } pixels.show(); delay(500); for (i = 13; i < 19; i++) { // All Inner pixels.setPixelColor(i, wColor); } pixels.show(); delay(500); for (i = 1; i < 12; i += 2) { // Odd Outer On pixels.setPixelColor(i, mColor); } pixels.show(); delay(500); for (i = 1; i < 12; i += 2) { // Odd Outer Off pixels.setPixelColor(i, noColor); } for (i = 0; i < 12; i += 2) { // Even Outer On pixels.setPixelColor(i, mColor); } pixels.show(); delay(500); for (i = 0; i < 12; i++) { // All Outer pixels.setPixelColor(i, mColor); } pixels.show(); delay(1000); } void cosmicFlash() { uint8_t i, j; for (j = 0; j < 3; j++) { for (i = 2; i < 12; i++) { clearHands(); pixels.setPixelColor(i, 0x707000); pixels.setPixelColor(i - 1, 0x404000); pixels.setPixelColor(i - 2, 0x101000); pixels.show(); delay(50); } } for (j = 0; j < 3; j++) { for (i = 13; i < 19; i++) { clearHands(); pixels.setPixelColor(i, 0x707000); pixels.setPixelColor(i - 1, 0x404000); pixels.show(); delay(50); } } clearHands(); pixels.setPixelColor(12, 0xf0f000); pixels.show(); delay(100); } void showFace0(DateTime showTime) { clearHands(); int hr = showTime.hour(); if ((hr>6) && (hr<18)) { pixels.setBrightness(9); } else { pixels.setBrightness(3); showCardinal(); } showSecOuter(showTime); showHrMnOuter(showTime); showMnInner(showTime); pixels.show(); } void showCalendar(DateTime showTime) { clearHands(); int hr = showTime.hour(); if ((hr>6) && (hr<18)) { pixels.setBrightness(9); } else { pixels.setBrightness(3); showCardinal(); } int mo = showTime.month(); int dy = showTime.day() % 12; int dmy = (showTime.day() / 12) + 12; int wk = showTime.dayOfTheWeek() + 12; if (mo == dy) { pixels.setPixelColor(adjustOuter(mo), bColor); } else { pixels.setPixelColor(adjustOuter(mo), hColor); pixels.setPixelColor(adjustOuter(dy), mColor); } pixels.setPixelColor(dmy, mColor); pixels.setPixelColor(wk, sColor); pixels.show(); } ///////////////////////////////////////////////////////////////// Menus and display void setRTC() { pixels.setBrightness(20); if (rtc.initialized()) { currTime = rtc.now(); int yr = getNum(currTime.year(), 72, 0, 12); int mo = getNum(currTime.month(), 12, 1, 12); int dy = getNum(currTime.day(), 31, 2, 12); int hr = getNum(currTime.hour(), 24, 3, 12); int mn = getNum(currTime.minute(), 60, 4, 12); rtc.adjust(DateTime(yr, mo, dy, hr, mn, currTime.second())); } else { int yr = getNum(2018, 72, 0, 12); int mo = getNum(1, 12, 1, 0); int dy = getNum(14, 31, 2, 12); int hr = getNum(9, 24, 3, 12); int mn = getNum(35, 60, 4, 12); rtc.adjust(DateTime(yr, mo, dy, hr, mn, 0)); } dispMode = 0; displayWatch(); } void setMin() { pixels.setBrightness(20); currTime = rtc.now(); int yr = currTime.year(); int mo = currTime.month(); int dy = currTime.day(); int hr = currTime.hour(); int mn = getNum(currTime.minute(), 60, 4, -1); rtc.adjust(DateTime(yr, mo, dy, hr, mn, currTime.second())); dispMode = 0; displayWatch(); } void flashMenu() { do { switch (flashMode) { case 0: pixels.setPixelColor(12, 0x0f0000); pixels.setPixelColor(13, 0x000000); pixels.setPixelColor(14, 0x000000); break; case 1: pixels.setPixelColor(13, 0x0f0000); pixels.setPixelColor(12, 0x000000); pixels.setPixelColor(14, 0x000000); break; case 2: pixels.setPixelColor(14, 0x0f0000); pixels.setPixelColor(12, 0x000000); pixels.setPixelColor(13, 0x000000); break; } pixels.show(); if (digitalRead(advPIN) == pressed) { // Select flash do { } while (digitalRead(advPIN) == pressed); delay(500); flashMode = (flashMode + 1) % 3; } // Select flash end } while (digitalRead(menuPIN) != pressed); dispMode = 0; displayWatch(); } // end flashMenu void mainMenu() { do { pixels.setPixelColor(dispMode + 13, 0x00f000); pixels.show(); if (digitalRead(advPIN) == pressed) { // Select menu do { } while (digitalRead(advPIN) == pressed); delay(500); pixels.setPixelColor(dispMode + 13, 0x000000); dispMode = (dispMode + 1) % 4; pixels.setPixelColor(dispMode + 13, 0x00f000); pixels.show(); } // Select menu end } while (digitalRead(menuPIN) != pressed); do{ } while (digitalRead(menuPIN) == pressed); clearHands(); switch (dispMode) { case 0: displayWatch(); break; case 1: flashMenu(); break; case 2: setMin(); break; case 3: setRTC(); break; } // Initiate main menu end } void displayWatch() { if (rtc.initialized()) { } do { switch (flashMode) { // Show Flash case 1: if (showFlash == 1) { caFlash(); showFlash = 0; } break; case 2: if (showFlash == 1) { cosmicFlash(); showFlash = 0; } break; } // Show flash end currTime = rtc.now(); showFace0(currTime); delay(5000); } while (digitalRead(timePIN) == pressed); // Show watch end clearHands(); showFlash = 1; } // Clear all leds, reset flash end void displayCalendar() { do { switch (flashMode) { // Show Flash case 1: if (showFlash == 1) { caFlash(); showFlash = 0; } break; case 2: if (showFlash == 1) { cosmicFlash(); showFlash = 0; } break; } // Show flash end currTime = rtc.now(); showCalendar(currTime); delay(5000); } while (digitalRead(advPIN) == pressed); // Show calendar end clearHands(); showFlash = 1; } // Clear all leds, reset flash end ///////////////////////////////////////////////////////////// Setup void setup() { // put your setup code here, to run once: if (! rtc.initialized()) { rtc.adjust(DateTime(2018, 1, 14, 9, 43, 0)); //setRTC(); } rtc.begin(); currTime = rtc.now(); pinMode(timePIN, INPUT); pinMode(menuPIN, INPUT); pinMode(advPIN, INPUT); digitalWrite(timePIN, HIGH); // activate pullup digitalWrite(menuPIN, HIGH); // activate pullup digitalWrite(advPIN, HIGH); // activate pullup pixels.begin(); } //////////////////////////////////////////////////////////////// Main Loop void loop() { if (digitalRead(menuPIN) == pressed) // Main menu on/off { dispTime = rtc.now(); menuDelay = dispTime.minute() * 60 + dispTime.second() + 3; do { } while (digitalRead(menuPIN) == pressed); delay(500); dispTime = rtc.now(); if (menuDelay < (dispTime.minute() * 60 + dispTime.second())) { clearHands(); mainMenu(); } } //Main menu on/off end if (digitalRead(advPIN) == pressed) //Calendar { mode = 0; displayCalendar(); } if (digitalRead(timePIN) == pressed) //Time { mode = 0; displayWatch(); } } 
Adjusting the outer ring 12 o’clock position
To move where the 12 o’clock appears on the outer ring you need to change the line:


const int outerRingOffset = 3;


The “3” is the number of spaces to move the 12 led to the right (clockwise) I needed to rotate 3 spaces so I set it to 3. You can set it from 0 (No adjustments) to 11. Once you have set the adjustment you need to reload the sketch.


Operation

This is an outline of the buttons, their use and functions

advPIN (Left button) timePIN (Middle button) menuPIN (Right button) menuPIN -&gt; Show menu 0: Show time 1: Flash menu advPIN -&gt; Advance flash 0: None 1: Captain America 2: Cosmic menuPIN -&gt; Exit menu 2: Set minutes advPIN -&gt; Minutes + 1 timePIN -&gt; Minutes - 1 menuPIN -&gt; Exit menu 3: Set RTC 0: Year - Indicator, Blue 5; Value, Yellow timePIN -&gt; Year + 12 1: Month - Indicator, Blue 4; Value, Yellow timePIN -&gt; No change 2: Day - Indicator, Blue 3; Value, Yellow timePIN -&gt; Day + 12 3: Hour - Indicator, Blue 2; Value, Yellow timePIN -&gt; Hour + 12 4: Minute - Indicator, Blue 1; Value, Yellow timePIN -&gt; Minutes + 12 advPIN -&gt; Value + 1 menuPIN -&gt; Next value/Exit menu

advPIN -&gt; Advances through the menu options advPIN -&gt; Show date timePIN -&gt; Show time

Comments

Popular posts from this blog

How I Met God in the Middle of the Night

The blessing of the food for Easter