Introduction: DIY Arduino Dot Matrix Wrist Watch

About: I like to learn, like to make, like to share.

Wrist watches are amazing and fancy fashion accessories for men and women. Makers always like to use something different. My diy arduino dot matrix wrist watch is the final output after one month working. The watch shows time, date and temperature in two different form, BCD binary format and digital format. BCD binary is dedicated to maker and tech people as it is not understandable to common folks. Two button is used to adjust time and changing display mode.

For making the project you need some experience of soldering of surface mount (SMD) components.

Step 1: Stuffs You Need

  • Crazyflie Nano Quadcopter - Spare battery (Seeed Studio)

  • 100R SMD Resistor (8pcs) (R1-R8 in schematic)
  • 10K SMD Resistor (3pcs) (RST, RSDA, RSCL in schematic)
  • 16 MHz Crystal
  • Tactile Button (2pcs)
  • 1.5 inch X 1.3 inch PCB board
  • Plastic Wrist Band

Tools needed

  • Soldering Iron
  • Soldering Paste
  • Tweezer
  • Wire Cutter
  • Hand Drill
  • Safety Glasses

Step 2: Making the Circuit

I used Atmel’s high performance, low power 8-bit AVR ATMega328 TQFP package as the main controller of my clock. A high precision DS3231-based real-time clock module is used for time keeping. The DS3231 is a low-cost, extremely accurate I2C real-time clock (RTC) with an integrated temperature- compensated crystal oscillator (TCXO) and crystal. So, no need to used external crystal oscillator and its operate from 2.3 to 5.5 V.

As a display a single color 1.25 inch 8x8 dot-matrix display is used. Both common anode or common cathode display can be used. You have to adjust the program accordingly.

Two right angle tactile button is used for time adjustment and clock mode changing. If you carefully check the circuit diagram you will notice that one button is connected to Atmega328 INT0 pin and another to PB1 pin. You can connect the second button to any other pin but should not change the first button. Because I used the button one to wake up the controller from sleep mode. For wake up the IC you must use external interrupt and for this reasons I used INT0 (external interrupt) pin for first button. 2-pin header is connected for charger and battery connection.

Eight 100 ohm current limiter resistors are connected to the row pins of the dot-matrix.

I designed the schematic in Eagle CAD. Eagle schematic file, image file and pdf file of the schematic are attached here.

Step 3: Designing the PCB Layout

I have tried to keep the PCB size as same as the matrix display. Two buttons position is kept to the right side of the board. I tried to keep the bottom route minimum because I used single side PCB and connect the bottom route by jumper wire.

Eagle board file and a pdf version is attached here. From the schematic you see two capacitor is connected to the crystal but not present in pcb. Without these the circuit works well without any problem.

Step 4: Making the PCB

I used Toner transfer DIY method to make the PCB. Some image are attached. If you want to make your own PCB you may follow this instructables: DIY Customized Circuit Board (PCB Making).

For double sided PCB you may follow: Two sided PCB using toner method

DIY PCBs double sided toner transfer,

Step 5: Drilling the PCB Board

After etching and cleaning the PCB board you have to drill the pad of matrix display and button. I used mini hand drill to drill the PCB and image is attached.

Step 6: Soldering the Components

After drilling the PCB we are now ready to solder the components. Carefully solder ATMega328 first to the pcb. It has smaller pad compare to other parts of our project. Then solder the matrix-display, then RTC and then Resistor. Three 10K resistor is used in the project. Two are used for pull up of RTC SDK and SCL pin and another another is for pullup the reset pin of ATMega328. All other eight resistors are 100 ohm.

If you used one side PCB board like me, now connect the bottom routes by thick insulated jumper wire.

If you are new in SMD soldering I recommend you to watch the video before you start soldering.

Video: EEVblog #186 - Soldering Tutorial Part 3 - Surface Mount

Sparkfun: SMD How To - 2

Step 7: Arduino Program for Binary Clock

All program is written in arduino environment and uploaded to ATMega328 by using arduino uno. ISP programming protocol is used for programming. I have divided the program into two part and each can be used independently. One for binary clock and another for digital mode of the clock.

Following program is only for binary mode of the watch and used Button library:

 #include "Wire.h"
 #define DS3231_I2C_ADDRESS 0x68
 
 #include <Button.h>          //https://github.com/JChristensen/Button

 #define BUTTON_PIN_1 2       //Connect a tactile button switch (or something similar)
 #define BUTTON_PIN_2 9       //from Arduino pin 2 to ground.
 #define PULLUP true          //To keep things simple, we use the Arduino's internal pullup resistor.
 #define INVERT true          //Since the pullup resistor will keep the pin high unless the
                              //switch is closed, this is negative logic, i.e. a high state
                              //means the button is NOT pressed. (Assuming a normally open switch.)
 #define DEBOUNCE_MS 20       //A debounce time of 20 milliseconds usually works well for tactile button switches.


 #define LONG_PRESS 1000      //We define a "long press" to be 1000 milliseconds.
 
 #define msec  1              //for brightness control of LED


 Button myBtn1(BUTTON_PIN_1, PULLUP, INVERT, DEBOUNCE_MS);    //Declare the button
 Button myBtn2(BUTTON_PIN_2, PULLUP, INVERT, DEBOUNCE_MS); 

// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val)
{
  return( (val/10*16) + (val%10) );
}
// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
  return( (val/16*10) + (val%16) );
}


byte second_unit, second_tens, minute_unit, minute_tens, hour_unit, hour_tens, 
     date_unit, date_tens, month_unit, month_tens, year_unit, year_tens, year_remain;
    
byte _second = 0, _minute = 10, _hour = 12, _day = 1, _date = 1, _month = 1, _year = 15;


long lastPressTime;

// you have to adjust pin number according to your connection 
byte colPin[8] = {4, 15, 14, 7, 12, 6, 3, 0}; //-ve pin
byte rowPin[8] = {8, 1, 10, 5, 17, 11, 16, 13}; //+ve


byte buttonStateOne = 0, buttonLongStateOne = 0, buttonStateTwo = 0, buttonLongStateTwo = 0;

byte clockMode = 0;



void setup() {
 Wire.begin();
  
 for (byte i = 3; i <= 17; i++) {
    if(i==9) continue;     //ignore pin 9 
    pinMode(i, OUTPUT);
  }
  
 pinMode(0, OUTPUT);
 pinMode(1, OUTPUT);
 pinMode(2, INPUT);       // button one
 pinMode(9, INPUT);       // button two
 digitalWrite(2, HIGH);   // enable internal pullup
 digitalWrite(9, HIGH);
   
    // set up cols and rows
 for (byte i = 1; i <= 8; i++) {
    digitalWrite(colPin[i - 1], HIGH);
  }

 for (byte i = 1; i <= 8; i++) {
    digitalWrite(rowPin[i - 1], LOW);
  }

}

void loop() {
    calculateDateTime();    
 if(buttonLongStateTwo == 0)   
    binaryClock();
 else
    editDisplay();
        
}

void setDS3231time(byte second, byte minute, byte hour, byte dayOfWeek, byte
dayOfMonth, byte month, byte year)
{
  // sets time and date data to DS3231
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0); // set next input to start at the seconds register
  Wire.write(decToBcd(second)); // set seconds
  Wire.write(decToBcd(minute)); // set minutes
  Wire.write(decToBcd(hour | 0x40)); // set hours
  Wire.write(decToBcd(dayOfWeek)); // set day of week (1=Sunday, 7=Saturday)
  Wire.write(decToBcd(dayOfMonth)); // set date (1 to 31)
  Wire.write(decToBcd(month)); // set month
  Wire.write(decToBcd(year)); // set year (0 to 99)
  Wire.endTransmission();
}

void readDS3231time(byte *second,
byte *minute,
byte *hour,
byte *dayOfWeek,
byte *dayOfMonth,
byte *month,
byte *year)
{
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0); // set DS3231 register pointer to 00h
  Wire.endTransmission();
  Wire.requestFrom(DS3231_I2C_ADDRESS, 7);
  // request seven bytes of data from DS3231 starting from register 00h
  *second = bcdToDec(Wire.read() & 0x7f);
  *minute = bcdToDec(Wire.read());
  *hour = bcdToDec(Wire.read() & 0x1f);
  *dayOfWeek = bcdToDec(Wire.read());
  *dayOfMonth = bcdToDec(Wire.read());
  *month = bcdToDec(Wire.read());
  *year = bcdToDec(Wire.read());
}

void calculateDateTime(){
  byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
  // retrieve data from DS3231
  readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month,
  &year);
  
  if(hour > 12){
    hour = hour - 24;   
  }
  
  second_unit = second % 10;
  second_tens = second / 10;
  
  minute_unit = minute % 10;
  minute_tens = minute / 10;
  
  hour_unit = hour % 10;
  hour_tens = hour / 10;
  
  date_unit = dayOfMonth % 10;
  date_tens = dayOfMonth / 10;
  
  month_unit = month % 10;
  month_tens = month / 10;
  
  year_unit = year % 10;
  year_tens = year / 10;
}

void time_zero(int pos){
  delay(msec);  
}

void time_one(int pos){
  digitalWrite(colPin[pos], LOW);
  digitalWrite(rowPin[7], HIGH);
  delay(msec);
  digitalWrite(colPin[pos], HIGH);
  digitalWrite(rowPin[7], LOW);
}

void time_two(int pos){
  digitalWrite(colPin[pos], LOW);
  digitalWrite(rowPin[6], HIGH);
  delay(msec);
  digitalWrite(colPin[pos], HIGH);
  digitalWrite(rowPin[6], LOW);
}

void time_three(int pos){
  digitalWrite(colPin[pos], LOW);
  digitalWrite(rowPin[6], HIGH);
  digitalWrite(rowPin[7], HIGH);
  delay(msec);
  digitalWrite(colPin[pos], HIGH);
  digitalWrite(rowPin[6], LOW);
  digitalWrite(rowPin[7], LOW);
}

void time_four(int pos){
  digitalWrite(colPin[pos], LOW);
  digitalWrite(rowPin[5], HIGH);
  delay(msec);
  digitalWrite(colPin[pos], HIGH);
  digitalWrite(rowPin[5], LOW);
}

void time_five(int pos){
  digitalWrite(colPin[pos], LOW);
  digitalWrite(rowPin[5], HIGH);
  digitalWrite(rowPin[7], HIGH);
  delay(msec);
  digitalWrite(colPin[pos], HIGH);
  digitalWrite(rowPin[5], LOW);
  digitalWrite(rowPin[7], LOW);
}

void time_six(int pos){
  digitalWrite(colPin[pos], LOW);
  digitalWrite(rowPin[5], HIGH);
  digitalWrite(rowPin[6], HIGH);
  delay(msec);
  digitalWrite(colPin[pos], HIGH);
  digitalWrite(rowPin[5], LOW);
  digitalWrite(rowPin[6], LOW);
}

void time_seven(int pos){
  digitalWrite(colPin[pos], LOW);
  digitalWrite(rowPin[5], HIGH);
  digitalWrite(rowPin[6], HIGH);
  digitalWrite(rowPin[7], HIGH);
  delay(msec);
  digitalWrite(colPin[pos], HIGH);
  digitalWrite(rowPin[5], LOW);
  digitalWrite(rowPin[6], LOW);
  digitalWrite(rowPin[7], LOW);
}

void time_eight(int pos){
  digitalWrite(colPin[pos], LOW);
  digitalWrite(rowPin[4], HIGH);
  delay(msec);
  digitalWrite(colPin[pos], HIGH);
  digitalWrite(rowPin[4], LOW);
}

void time_nine(int pos){
  digitalWrite(colPin[pos], LOW);
  digitalWrite(rowPin[4], HIGH);
  digitalWrite(rowPin[7], HIGH);
  delay(msec);
  digitalWrite(colPin[pos], HIGH);
  digitalWrite(rowPin[4], LOW);
  digitalWrite(rowPin[7], LOW);
}

void date_zero(int pos){
  delay(msec);  
}

void date_one(int pos){
  digitalWrite(colPin[pos], LOW);
  digitalWrite(rowPin[7-4], HIGH);
  delay(msec);
  digitalWrite(colPin[pos], HIGH);
  digitalWrite(rowPin[7-4], LOW);
}

void date_two(int pos){
  digitalWrite(colPin[pos], LOW);
  digitalWrite(rowPin[6-4], HIGH);
  delay(msec);
  digitalWrite(colPin[pos], HIGH);
  digitalWrite(rowPin[6-4], LOW);
}

void date_three(int pos){
  digitalWrite(colPin[pos], LOW);
  digitalWrite(rowPin[6-4], HIGH);
  digitalWrite(rowPin[7-4], HIGH);
  delay(msec);
  digitalWrite(colPin[pos], HIGH);
  digitalWrite(rowPin[6-4], LOW);
  digitalWrite(rowPin[7-4], LOW);
}

void date_four(int pos){
  digitalWrite(colPin[pos], LOW);
  digitalWrite(rowPin[5-4], HIGH);
  delay(msec);
  digitalWrite(colPin[pos], HIGH);
  digitalWrite(rowPin[5-4], LOW);
}

void date_five(int pos){
  digitalWrite(colPin[pos], LOW);
  digitalWrite(rowPin[5-4], HIGH);
  digitalWrite(rowPin[7-4], HIGH);
  delay(msec);
  digitalWrite(colPin[pos], HIGH);
  digitalWrite(rowPin[5-4], LOW);
  digitalWrite(rowPin[7-4], LOW);
}

void date_six(int pos){
  digitalWrite(colPin[pos], LOW);
  digitalWrite(rowPin[5-4], HIGH);
  digitalWrite(rowPin[6-4], HIGH);
  delay(msec);
  digitalWrite(colPin[pos], HIGH);
  digitalWrite(rowPin[5-4], LOW);
  digitalWrite(rowPin[6-4], LOW);
}

void date_seven(int pos){
  digitalWrite(colPin[pos], LOW);
  digitalWrite(rowPin[5-4], HIGH);
  digitalWrite(rowPin[6-4], HIGH);
  digitalWrite(rowPin[7-4], HIGH);
  delay(msec);
  digitalWrite(colPin[pos], HIGH);
  digitalWrite(rowPin[5-4], LOW);
  digitalWrite(rowPin[6-4], LOW);
  digitalWrite(rowPin[7-4], LOW);
}

void date_eight(int pos){
  digitalWrite(colPin[pos], LOW);
  digitalWrite(rowPin[4-4], HIGH);
  delay(msec);
  digitalWrite(colPin[pos], HIGH);
  digitalWrite(rowPin[4-4], LOW);
}

void date_nine(int pos){
  digitalWrite(colPin[pos], LOW);
  digitalWrite(rowPin[4-4], HIGH);
  digitalWrite(rowPin[7-4], HIGH);
  delay(msec);
  digitalWrite(colPin[pos], HIGH);
  digitalWrite(rowPin[4-4], LOW);
  digitalWrite(rowPin[7-4], LOW);
}


void show(int digit, int pos){
  switch(digit){
     case 0:
     time_zero(pos);
     break;
     
     case 1:
     time_one(pos);
     break;
     
     case 2:
     time_two(pos);
     break;
     
     case 3:
     time_three(pos);
     break;
     
     case 4:
     time_four(pos);
     break;
     
     case 5:
     time_five(pos);
     break;
     
     case 6:
     time_six(pos);
     break;
     
     case 7:
     time_seven(pos);
     break;
     
     case 8:
     time_eight(pos);
     break;
     
     case 9:
     time_nine(pos);
     break;  
  }

}

void date_show(int digit, int pos){
  switch(digit){
     case 0:
     date_zero(pos);
     break;
     
     case 1:
     date_one(pos);
     break;
     
     case 2:
     date_two(pos);
     break;
     
     case 3:
     date_three(pos);
     break;
     
     case 4:
     date_four(pos);
     break;
     
     case 5:
     date_five(pos);
     break;
     
     case 6:
     date_six(pos);
     break;
     
     case 7:
     date_seven(pos);
     break;
     
     case 8:
     date_eight(pos);
     break;
     
     case 9:
     date_nine(pos);
     break;  
  }

}

void binaryClock(){
  FrequencyTimer2::setOnOverflow(0);
  show(second_unit, 7);
  show(second_tens, 6);
  
  show(minute_unit, 4);
  show(minute_tens, 3);
  
  show(hour_unit, 1);
  show(hour_tens, 0); 
 
  date_show(date_unit, 7);
  date_show(date_tens, 6);
 
  date_show(month_unit, 4);
  date_show(month_tens, 3);
 
  date_show(year_unit, 1);
  date_show(year_tens, 0); 
}

void showMinute(){
  int _minute_unit = _minute % 10;
  int _minute_tens = _minute / 10;
  show(_minute_unit, 4);
  show(_minute_tens, 3);
}

void showHour(){
  int _hour_unit = _hour % 10;
  int _hour_tens = _hour / 10;
  show(_hour_unit, 1);
  show(_hour_tens, 0); 
}
void showDate(){
  int _date_unit = _date % 10;
  int _date_tens = _date / 10;
  date_show(_date_unit, 7);
  date_show(_date_tens, 6);
}

void showMonth(){
  int _month_unit = _month % 10;
  int _month_tens = _month / 10;
  date_show(_month_unit, 4);
  date_show(_month_tens, 3);
}
void showYear(){
  int _year_unit = _year % 10;
  int _year_tens = _year / 10;
  date_show(_year_unit, 1);
  date_show(_year_tens, 0); 
}

 void button(){
    myBtn1.read();                //Read the button
    myBtn2.read();                //Read the button
                 
    if (myBtn1.wasReleased()){
         lastPressTime = millis();
         if(buttonLongStateTwo == 0){}
         else if((buttonLongStateTwo == 1) && (buttonStateTwo == 1))   
            {
              showMinute();
              _minute++;
              delay(20);
              if(_minute > 59)
              _minute = 0;
            //Serial.println(minute);
            }
         else if((buttonLongStateTwo == 1) && (buttonStateTwo == 2))   
           {
              showHour();
              _hour++;
              delay(20);
              if(_hour > 12)
              _hour = 1;
            //Serial.println(hour);
            }
         else if((buttonLongStateTwo == 1) && (buttonStateTwo == 3))   
            {
              showDate();
              _date++;
              delay(20);
              if(_date > 31)
              _date = 1;
            //Serial.println(date);
            }
         else if((buttonLongStateTwo == 1) && (buttonStateTwo == 4))   
            {
              showMonth();
              _month++;
              delay(20);
              if(_month > 12)
              _month = 1;
           // Serial.println(month);
            }
         else if((buttonLongStateTwo == 1) && (buttonStateTwo == 5))   
            {
              showYear();
              _year++;
              if(_year > 99)
              _year = 15;
              delay(20);
             //Serial.println(year);
            }
        
       }
         
    else if (myBtn1.pressedFor(LONG_PRESS)){
         lastPressTime = millis();
         setDS3231time(_second,_minute,_hour,1,_date,_month,_year);
         
         //Serial.println("date set");
         buttonLongStateTwo = 0;
         //Serial.println(buttonLongStateTwo);
         delay(100);
       }
         
   else if (myBtn2.wasReleased()){
        lastPressTime = millis();
        if(buttonLongStateTwo == 0){
         
          }
         else if(buttonLongStateTwo == 1){ 
            buttonStateTwo++;
            if(buttonStateTwo > 5)
             buttonStateTwo = 1;
         }
          if((buttonStateTwo == 1)&&(buttonLongStateTwo == 1)){
            showMinute();
            delay(20);
            //Serial.println("display minute");
            }
          if((buttonStateTwo == 2)&&(buttonLongStateTwo == 1)){
            //Serial.println("display hour");
            showHour();
            delay(20);
            }
          if((buttonStateTwo == 3)&&(buttonLongStateTwo == 1)){
            //Serial.println("dispaly date");
            showDate();
            delay(20);
          }
          if((buttonStateTwo == 4)&&(buttonLongStateTwo == 1)){
            //Serial.println("display month");
            showMonth();
            delay(20);
          }
          if((buttonStateTwo == 5)&&(buttonLongStateTwo == 1)){
            //Serial.println("display year");
            showYear(); 
            delay(20);   
          }
        
       }
    else if (myBtn2.pressedFor(LONG_PRESS)){
         lastPressTime = millis();
         readDS3231time(&_second, &_minute, &_hour, &_day, &_date, &_month,
     &_year);
         buttonLongStateTwo = 1;
         //Serial.println("editing mode");
         delay(10);
   }


}

void editDisplay(){
         if((buttonStateTwo == 1)&&(buttonLongStateTwo == 1)){
            showMinute();
            
            //Serial.println("display minute");
            }
        if((buttonStateTwo == 2)&&(buttonLongStateTwo == 1)){
            //Serial.println("display hour");
            showHour();
          
            }
        if((buttonStateTwo == 3)&&(buttonLongStateTwo == 1)){
            //Serial.println("dispaly date");
            showDate();
           
          }
        if((buttonStateTwo == 4)&&(buttonLongStateTwo == 1)){
           //Serial.println("display month");
            showMonth();
            
          }
        if((buttonStateTwo == 5)&&(buttonLongStateTwo == 1)){
            //Serial.println("display year");
            showYear(); 
          
          }
        
  }

Step 8: Arduino Sketch for Digital Clock

Digital Mode use Frequency Timer 2 library.You can download library from here.

 #include <FrequencyTimer2.h>
 #include "Wire.h"
 #define DS3231_I2C_ADDRESS 0x68
 
 
// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val)
{
  return( (val/10*16) + (val%10) );
}
// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
  return( (val/16*10) + (val%16) );
}


byte second_unit, second_tens, minute_unit, minute_tens, hour_unit, hour_tens, 
    date_unit, date_tens, month_unit, month_tens, year_unit, year_tens, year_remain;
    
byte _second = 0, _minute = 10, _hour = 12, _day = 1, _date = 1, _month = 1, _year = 15;


byte tMSB, tLSB;
float temp3231;
long lastPressTime;

#define space { \
    {0, 0, 0, 0, 0, 0, 0, 0},  \
    {0, 0, 0, 0, 0, 0, 0, 0}, \
    {0, 0, 0, 0, 0, 0, 0, 0}, \
    {0, 0, 0, 0, 0, 0, 0, 0}, \
    {0, 0, 0, 0, 0, 0, 0, 0}, \
    {0, 0, 0, 0, 0, 0, 0, 0}, \
    {0, 0, 0, 0, 0, 0, 0, 0}, \
    {0, 0, 0, 0, 0, 0, 0, 0} \
}

#define slash { \
    {0, 0, 0, 0, 0, 0, 0, 0},  \
    {0, 0, 0, 0, 0, 1, 0, 0}, \
    {0, 0, 0, 0, 1, 0, 0, 0}, \
    {0, 0, 0, 1, 0, 0, 0, 0}, \
    {0, 0, 1, 0, 0, 0, 0, 0}, \
    {0, 1, 0, 0, 0, 0, 0, 0}, \
    {0, 0, 0, 0, 0, 0, 0, 0}, \
    {0, 0, 0, 0, 0, 0, 0, 0} \
}

#define A { \
    {0, 0, 1, 1, 1, 0, 0, 0},  \
    {0, 1, 0, 0, 0, 1, 0, 0}, \
    {0, 1, 0, 0, 0, 1, 0, 0}, \
    {0, 1, 0, 0, 0, 1, 0, 0}, \
    {0, 1, 1, 1, 1, 1, 0, 0}, \
    {0, 1, 0, 0, 0, 1, 0, 0}, \
    {0, 1, 0, 0, 0, 1, 0, 0}, \
    {0, 0, 0, 0, 0, 0, 0, 0} \
}

#define M { \
    {0, 1, 0, 0, 0, 1, 0, 0},  \
    {0, 1, 1, 0, 1, 1, 0, 0}, \
    {0, 1, 0, 1, 0, 1, 0, 0}, \
    {0, 1, 0, 1, 0, 1, 0, 0}, \
    {0, 1, 0, 0, 0, 1, 0, 0}, \
    {0, 1, 0, 0, 0, 1, 0, 0}, \
    {0, 1, 0, 0, 0, 1, 0, 0}, \
    {0, 0, 0, 0, 0, 0, 0, 0} \
}

#define P { \
    {0, 1, 1, 1, 1, 0, 0, 0},  \
    {0, 1, 0, 0, 0, 1, 0, 0}, \
    {0, 1, 0, 0, 0, 1, 0, 0}, \
    {0, 1, 1, 1, 1, 0, 0, 0}, \
    {0, 1, 0, 0, 0, 0, 0, 0}, \
    {0, 1, 0, 0, 0, 0, 0, 0}, \
    {0, 1, 0, 0, 0, 0, 0, 0}, \
    {0, 0, 0, 0, 0, 0, 0, 0} \
}

#define zero { \
    {0, 0, 1, 1, 1, 0, 0, 0}, \
    {0, 1, 0, 0, 0, 1, 0, 0}, \
    {0, 1, 0, 0, 1, 1, 0, 0}, \
    {0, 1, 0, 1, 0, 1, 0, 0}, \
    {0, 1, 1, 0, 0, 1, 0, 0}, \
    {0, 1, 0, 0, 0, 1, 0, 0}, \
    {0, 0, 1, 1, 1, 0, 0, 0}, \
    {0, 0, 0, 0, 0, 0, 0, 0}  \
}

#define one { \
    {0, 0, 0, 1, 0, 0, 0, 0}, \
    {0, 0, 1, 1, 0, 0, 0, 0}, \
    {0, 0, 0, 1, 0, 0, 0, 0}, \
    {0, 0, 0, 1, 0, 0, 0, 0}, \
    {0, 0, 0, 1, 0, 0, 0, 0}, \
    {0, 0, 0, 1, 0, 0, 0, 0}, \
    {0, 0, 1, 1, 1, 0, 0, 0}, \
    {0, 0, 0, 0, 0, 0, 0, 0}  \
}

#define two { \
    {0, 0, 1, 1, 1, 0, 0, 0}, \
    {0, 1, 0, 0, 0, 1, 0, 0}, \
    {0, 0, 0, 0, 0, 1, 0, 0}, \
    {0, 0, 0, 0, 1, 0, 0, 0}, \
    {0, 0, 0, 1, 0, 0, 0, 0}, \
    {0, 0, 1, 0, 0, 0, 0, 0}, \
    {0, 1, 1, 1, 1, 1, 0, 0}, \
    {0, 0, 0, 0, 0, 0, 0, 0}  \
}

#define three { \
    {0, 1, 1, 1, 1, 1, 0, 0}, \
    {0, 0, 0, 0, 1, 0, 0, 0}, \
    {0, 0, 0, 1, 0, 0, 0, 0}, \
    {0, 0, 0, 0, 1, 0, 0, 0}, \
    {0, 0, 0, 0, 0, 1, 0, 0}, \
    {0, 1, 0, 0, 0, 1, 0, 0}, \
    {0, 0, 1, 1, 1, 0, 0, 0}, \
    {0, 0, 0, 0, 0, 0, 0, 0}  \
}

#define four { \
    {0, 0, 0, 0, 1, 0, 0, 0}, \
    {0, 0, 0, 1, 1, 0, 0, 0}, \
    {0, 0, 1, 0, 1, 0, 0, 0}, \
    {0, 1, 0, 0, 1, 0, 0, 0}, \
    {0, 1, 1, 1, 1, 1, 0, 0}, \
    {0, 0, 0, 0, 1, 0, 0, 0}, \
    {0, 0, 0, 0, 1, 0, 0, 0}, \
    {0, 0, 0, 0, 0, 0, 0, 0}  \
}

#define five { \
    {0, 1, 1, 1, 1, 1, 0, 0}, \
    {0, 1, 0, 0, 0, 0, 0, 0}, \
    {0, 1, 1, 1, 1, 0, 0, 0}, \
    {0, 0, 0, 0, 0, 1, 0, 0}, \
    {0, 0, 0, 0, 0, 1, 0, 0}, \
    {0, 1, 0, 0, 0, 1, 0, 0}, \
    {0, 0, 1, 1, 1, 0, 0, 0}, \
    {0, 0, 0, 0, 0, 0, 0, 0}  \
}

#define six { \
    {0, 0, 0, 1, 1, 0, 0, 0}, \
    {0, 0, 1, 0, 0, 0, 0, 0}, \
    {0, 1, 0, 0, 0, 0, 0, 0}, \
    {0, 1, 1, 1, 1, 0, 0, 0}, \
    {0, 1, 0, 0, 0, 1, 0, 0}, \
    {0, 1, 0, 0, 0, 1, 0, 0}, \
    {0, 0, 1, 1, 1, 0, 0, 0}, \
    {0, 0, 0, 0, 0, 0, 0, 0}  \
}

#define seven { \
    {0, 1, 1, 1, 1, 1, 0, 0}, \
    {0, 0, 0, 0, 0, 1, 0, 0}, \
    {0, 0, 0, 0, 1, 0, 0, 0}, \
    {0, 0, 0, 1, 0, 0, 0, 0}, \
    {0, 0, 1, 0, 0, 0, 0, 0}, \
    {0, 0, 1, 0, 0, 0, 0, 0}, \
    {0, 0, 1, 0, 0, 0, 0, 0}, \
    {0, 0, 0, 0, 0, 0, 0, 0}  \
}

#define eight { \
    {0, 0, 1, 1, 1, 0, 0, 0}, \
    {0, 1, 0, 0, 0, 1, 0, 0}, \
    {0, 1, 0, 0, 0, 1, 0, 0}, \
    {0, 0, 1, 1, 1, 0, 0, 0}, \
    {0, 1, 0, 0, 0, 1, 0, 0}, \
    {0, 1, 0, 0, 0, 1, 0, 0}, \
    {0, 0, 1, 1, 1, 0, 0, 0}, \
    {0, 0, 0, 0, 0, 0, 0, 0}  \
}

#define nine { \
    {0, 0, 1, 1, 1, 0, 0, 0}, \
    {0, 1, 0, 0, 0, 1, 0, 0}, \
    {0, 1, 0, 0, 0, 1, 0, 0}, \
    {0, 0, 1, 1, 1, 1, 0, 0}, \
    {0, 0, 0, 0, 0, 1, 0, 0}, \
    {0, 0, 0, 0, 1, 0, 0, 0}, \
    {0, 0, 1, 1, 0, 0, 0, 0}, \
    {0, 0, 0, 0, 0, 0, 0, 0}  \
}

#define colon { \
    {0, 0, 0, 0, 0, 0, 0, 0}, \
    {0, 0, 1, 1, 0, 0, 0, 0}, \
    {0, 0, 1, 1, 0, 0, 0, 0}, \
    {0, 0, 0, 0, 0, 0, 0, 0}, \
    {0, 0, 1, 1, 0, 0, 0, 0}, \
    {0, 0, 1, 1, 0, 0, 0, 0}, \
    {0, 0, 0, 0, 0, 0, 0, 0}, \
    {0, 0, 0, 0, 0, 0, 0, 0}  \
}

#define DEGC { \
    {1, 1, 0, 0, 1, 1, 1, 0}, \
    {1, 1, 0, 1, 0, 0, 0, 1}, \
    {0, 0, 0, 1, 0, 0, 0, 0}, \
    {0, 0, 0, 1, 0, 0, 0, 0}, \
    {0, 0, 0, 1, 0, 0, 0, 0}, \
    {0, 0, 0, 1, 0, 0, 0, 1}, \
    {0, 0, 0, 0, 1, 1, 1, 0}, \
    {0, 0, 0, 0, 0, 0, 0, 0}  \
}

#define T { \
    {0, 1, 1, 1, 1, 1, 0, 0}, \
    {0, 0, 0, 1, 0, 0, 0, 0}, \
    {0, 0, 0, 1, 0, 0, 0, 0}, \
    {0, 0, 0, 1, 0, 0, 0, 0}, \
    {0, 0, 0, 1, 0, 0, 0, 0}, \
    {0, 0, 0, 1, 0, 0, 0, 0}, \
    {0, 0, 0, 1, 0, 0, 0, 0}, \
    {0, 0, 0, 0, 0, 0, 0, 0}  \
}

#define smallm { \
    {0, 0, 0, 0, 0, 0, 0, 0}, \
    {0, 0, 0, 0, 0, 0, 0, 0}, \
    {0, 1, 1, 0, 1, 0, 0, 0}, \
    {0, 1, 0, 1, 0, 1, 0, 0}, \
    {0, 1, 0, 1, 0, 1, 0, 0}, \
    {0, 1, 0, 0, 0, 1, 0, 0}, \
    {0, 1, 0, 0, 0, 1, 0, 0}, \
    {0, 0, 0, 0, 0, 0, 0, 0}  \
}

#define smallp { \
    {0, 0, 0, 0, 0, 0, 0, 0}, \
    {0, 0, 0, 0, 0, 0, 0, 0}, \
    {0, 1, 1, 1, 1, 0, 0, 0}, \
    {0, 1, 0, 0, 0, 1, 0, 0}, \
    {0, 1, 1, 1, 1, 0, 0, 0}, \
    {0, 1, 0, 0, 0, 0, 0, 0}, \
    {0, 1, 0, 0, 0, 0, 0, 0}, \
    {0, 0, 0, 0, 0, 0, 0, 0}  \
}


byte col = 0;
byte leds[8][8];

byte rows[8] = {0, 3, 6, 12, 7, 14, 15, 4};
byte cols[8] = {8, 1, 10, 5, 17, 11, 16, 13};

const byte numPatterns = 14;
byte patterns[numPatterns][8][8] = {

  zero, one, two, three, four, five, six, seven, eight, nine, colon, space, slash, DEGC

};
int pattern = 0;


void setup() {
 Wire.begin();
 
 
 for (byte i = 3; i <= 17; i++) {
    if(i==9) continue;
    pinMode(i, OUTPUT);
  }
  
 pinMode(0, OUTPUT);
 pinMode(1, OUTPUT);
 

    // set up cols and rows
 for (byte i = 1; i <= 8; i++) {
    digitalWrite(rows[i - 1], LOW);
  }

 for (byte i = 1; i <= 8; i++) {
    digitalWrite(cols[i - 1], LOW);
  }

  clearLeds();


  // Turn off toggling of pin 11

  FrequencyTimer2::disable();

  // Set refresh rate (interrupt timeout period)

  FrequencyTimer2::setPeriod(2000);

  // Set interrupt routine to be called

  FrequencyTimer2::setOnOverflow(display);


  setPattern(pattern);

}

void loop() {
    calculateDateTime();
   
    
    digitalClock();
          
       
}

void clearLeds() {
  // Clear display array
  for (int i = 0; i < 8; i++) {
    for (int j = 0; j < 8; j++) {
      leds[i][j] = 0;
    }
  }
}


void setPattern(int pattern) {
  for (int i = 0; i < 8; i++) {
    for (int j = 0; j < 8; j++) {
      leds[i][j] = patterns[pattern][i][j];
    }
  }
}


void slidePattern(int pattern, int del) {
  for (int l = 0; l < 8; l++) {
    for (int i = 0; i < 7; i++) {
      for (int j = 0; j < 8; j++) {
        leds[j][i] = leds[j][i+1];
         }
    }
    for (int j = 0; j < 8; j++) {
      leds[j][7] = patterns[pattern][j][0 + l];
    }
    delay(del);
  }
}


// Interrupt routine

void display() {
  digitalWrite(cols[col], LOW);  // Turn whole previous column off
  col++;
  
  //digitalWrite(rows[row], LOW);  // Turn whole previous column off
  //row++;
  
  if (col == 8) {
    col = 0;
  }

  for (int row = 0; row < 8; row++) {
    if (leds[col][7 - row] == 1) {
      digitalWrite(rows[row], LOW);  // Turn on this led
    }
    else {
      digitalWrite(rows[row], HIGH); // Turn off this led
    }
  }
  digitalWrite(cols[col], HIGH); // Turn whole column on at once (for equal lighting times)
}


void setDS3231time(byte second, byte minute, byte hour, byte dayOfWeek, byte
dayOfMonth, byte month, byte year)
{
  // sets time and date data to DS3231
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0); // set next input to start at the seconds register
  Wire.write(decToBcd(second)); // set seconds
  Wire.write(decToBcd(minute)); // set minutes
  Wire.write(decToBcd(hour | 0x40)); // set hours
  Wire.write(decToBcd(dayOfWeek)); // set day of week (1=Sunday, 7=Saturday)
  Wire.write(decToBcd(dayOfMonth)); // set date (1 to 31)
  Wire.write(decToBcd(month)); // set month
  Wire.write(decToBcd(year)); // set year (0 to 99)
  Wire.endTransmission();
}

void readDS3231time(byte *second,
byte *minute,
byte *hour,
byte *dayOfWeek,
byte *dayOfMonth,
byte *month,
byte *year)
{
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0); // set DS3231 register pointer to 00h
  Wire.endTransmission();
  Wire.requestFrom(DS3231_I2C_ADDRESS, 7);
  // request seven bytes of data from DS3231 starting from register 00h
  *second = bcdToDec(Wire.read() & 0x7f);
  *minute = bcdToDec(Wire.read());
  *hour = bcdToDec(Wire.read() & 0x1f);
  *dayOfWeek = bcdToDec(Wire.read());
  *dayOfMonth = bcdToDec(Wire.read());
  *month = bcdToDec(Wire.read());
  *year = bcdToDec(Wire.read());
}

void calculateDateTime(){
  byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
  // retrieve data from DS3231
  readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month,
  &year);
  
  if(hour > 12){
    hour = hour - 24;   
  }
  
  second_unit = second % 10;
  second_tens = second / 10;
  
  minute_unit = minute % 10;
  minute_tens = minute / 10;
  
  hour_unit = hour % 10;
  hour_tens = hour / 10;
  
  date_unit = dayOfMonth % 10;
  date_tens = dayOfMonth / 10;
  
  month_unit = month % 10;
  month_tens = month / 10;
  
  year_unit = year % 10;
  year_tens = year / 10;
}

void digitalClock(){
  FrequencyTimer2::setOnOverflow(display);
  slidePattern(hour_tens, 80);
  slidePattern(hour_unit, 80);
  slidePattern(10, 80);
  slidePattern(minute_tens, 80);
  slidePattern(minute_unit, 80);
  slidePattern(10, 80);
  slidePattern(second_tens, 80);
  slidePattern(second_unit, 80);
  //slidePattern(11, 80);
  slidePattern(11, 80);
  
  slidePattern(date_tens, 80);
  slidePattern(date_unit, 80);
  slidePattern(12, 80);
  slidePattern(month_tens, 80);
  slidePattern(month_unit, 80);
  slidePattern(12, 80);
  slidePattern(2, 80);
  slidePattern(0, 80);
  slidePattern(year_tens, 80);
  slidePattern(year_unit, 80);

  slidePattern(11, 80);
  int tempC = get3231Temp();
  int tempC_unit = tempC % 10;
  int tempC_tens = tempC / 10;
  
  slidePattern(tempC_tens, 80);
  slidePattern(tempC_unit, 80);
  slidePattern(13, 80);
  
  slidePattern(11, 80);
  slidePattern(11, 80);
}
    
int get3231Temp()
 {
  //temp registers (11h-12h) get updated automatically every 64s
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0x11);
  Wire.endTransmission();
  Wire.requestFrom(DS3231_I2C_ADDRESS, 2);
 
  if(Wire.available()) {
    tMSB = Wire.read(); //2's complement int portion
    tLSB = Wire.read(); //fraction portion
   
    temp3231 = (tMSB & B01111111); //do 2's math on Tmsb
    
  }
  else {
    //oh noes, no data!
  }
   
  return temp3231;
}


Step 9: Arduino Sketch for Sleep Mode

Power management is one of the most important thing for wearable and portable electronics. If power consumption is very high the the device may be useless and very difficult to maintain. So, I tried to maintain the power consumption as low as possible. For that I used arduino sleep mode which required very low current (only 100nA) for Atmeg328P. For AVR sleep mode to work, you have to include avr interrupt and sleep library in your sketch. Interrupt is used because only interrupt can wake up ATmega chip from sleep mode. If you remember a button is connected to the INT0 pin of ATmega328. I used this button to controlling the sleep mode. Following code snippet is used for enabling the sleep mode:

#include 
#include 

void setup(){
// first parameter is interrupt number and 0 for INT0 pin
// second pin is the function to call after interrupt
attachInterrupt(0,wakeUpNow, LOW);

}

void sleepNow()         // here we put the arduino to sleep
{
      
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);   // sleep mode is set here

    sleep_enable();              // enables the sleep bit in the mcucr register
                                 // so sleep is possible. just a safety pin 

    attachInterrupt(0,wakeUpNow, LOW); // use interrupt 0 (pin 2) and run function
                                       // wakeUpNow when pin 2 gets LOW 
                            
    sleep_mode();                // here the device is actually put to sleep!!
                                 // 


    sleep_disable();             // first thing after waking from sleep:
                                 // disable sleep...
    lastPressTime = millis();    // keep track how long the device is in active mode
    
    detachInterrupt(0);          // disables interrupt 0 on pin 2 so the 
                                 // wakeUpNow code will not be executed 
                                 // during normal running time.
                                 
}

void wakeUpNow()        // here the interrupt is handled after wakeup
{
  //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.
 
}


Step 10: Uploading the Program

Our program is ready. It is the time to upload the program. I used ISP programming mode to program ATmega328 chip. After soldering the IC to the PCB board temporarily solder six jumper wires to MISO, MOSI, SCK, RESET, VCC and GROUND pin (Fig. 1). All pins are marked in the PCB layout. Connect Reset, MOSI, MISO and SCK pin of the board to Arduino pin 10, 11, 12 and 13 respectively through jumper wire. Connect VCC and Ground pin to Arduino 5V and GND pin respectively.

Now, upload Arduino ISP program from example to your arduino uno board (Fig. 2). Now arduino uno will act as ISP programmer.

Open the watch sketch and select Upload Using Programmer from the File menu (Fig. 3). Wait for a while, your program will be uploaded to the ATmega328 chip.

The complete sketch is attached here.

Zip file includes complete-sketch and required library.

Step 11: Adjusting With the Wrist Band

Our works is almost completed. We built the hardware and uploaded the program. Now we should fix it with wrist band. Images show the steps of the work. Battery is separated from the circuit by insulator. I used hot glue to fix the bottom frame to the band.

Step 12: Power Consumption

In sleep mode the overall current draw by the watch is around 5uA. In active mode the current draw may vary from 100mA to over 250mA, though 150mA is the typical current draw.

After wake up watch remain active for 1 minute. If someone press the wake up button 15 times in a day then watch remain in active mode for an average of 15 minutes. If average current drawn is 50mA then by a 170mAh battery watch will live for 170/150 = 1.13 hours. Taking 15 minutes active time watch will serve 1.13 / .25 = 4.5 days for single charge of the battery.

ATMega328P draws 100nA in sleep mode.

DS3231 RTC draws 2.5uA for normal operating condition.

There small amount of leakage current can flow. Considering all the watch may be draw approximately 5uA current in sleep mode. In sleep mode the watch can serve more than 2 years by single charge of the battery.

Current draw breakdown table:

PartMinimum
(sleep mode)
Typical
(active mode)
ATmega328P100nA150mA
DS32312.5uA2.5uA
Leakage (app.)2uA2uA
Total5uA150mA

Step 13: The Final Project

Congratulation! You have completed every step and your cool DIY watch is ready to wear. Enjoy it!!!

English is my second language. I apologize for any kind of mistakes.

Wearable Tech Contest

Second Prize in the
Wearable Tech Contest

Time Contest

Participated in the
Time Contest

Tech Contest

Participated in the
Tech Contest