After several years of exploring Arduino, I wanted to do something really interesting and useful. It was decided to make a wristwatch. But not just a watch, but really compact, comfortable, outwardly not very scary and most importantly with long battery life hours.
DIY Arduino Watch is a compact and lightweight wrist watch with a 1.3-inch display made using OLED technology. The clock can be easily programmed in the Arduino environment via a micro USB connector, using an external programmer. When programming the clock in the environment settings, you must select the Arduino pro mini 3.3V 8MHz board. The watches have low power consumption, which allows working for more than 6 months from one CR2032 battery (provided that the time is displayed for 3 seconds, and the owner watches the time 12 times a day). The standby current is about 7-8 μA, in the time display mode is 10-12 mA. The clock also allows you to measure the supply voltage using the built-in 1.1V reference voltage source.
For the most economical use of energy all the time while the clock does not display the time the microcontroller is in a state of deep sleep. It can only be awakened by an external interrupt (button 1). The screen also goes to sleep and wake up the microcontroller when the latter wakes up.
1. Atmega328p microcontroller in QFP32 package;
2. OLED Display 128x64 1.3 ”(SH1106);
3. DS1337 Real Time Clock in SOP-8;
4. Clock buttons;
5. Micro usb connectors mom and dad;
6. CR2032 battery;
7. SMD capacitors, resistors and quartz at 8MHz and 32kHz;
8. Double-sided PCB;
9. The body, consisting of 3 parts, printed on a 3D-printer.
When you have all the necessary parts, you can begin to manufacture the printed circuit board. I made the board using the LUT method, but with only one caveat - instead of glossy paper, I used transparent (it is possible and color, just with transparent is more convenient) Oracl self-adhesive vinyl film, which allows you to perfectly transfer all toner to textolite. The technology is as follows. First, on a plain paper, print a board drawing, then cut out a vinyl film that is slightly larger than the drawing itself and paste on the printed board drawing on paper. Then again, on the same sheet of paper, print the drawing of the board, so that the print would turn out on the vinyl film itself. Well, then follow the established scheme. Keep the picture under the iron for about a minute - as a rule, during this time the toner has time to stick to the PCB, and the film has time to soften, so that the toner is completely behind the vinyl. The result is an excellent transfer of the image without the villi and white bloom.
There are dots in the picture of the printed circuit board at the top and bottom that allow you to precisely align the patterns on different sides of the board.
The next step is flashing the bootloader into the microcontroller. The bootloader is used from Arduino pro mini 3.3V 8MHz with a few changes. In order to make the microcontroller's consumption in sleep mode about 1 µA and also allow the microcontroller to work at a voltage below 1.8V, you must disable Brown-out Detection (BOD). To do this, you need to open the boards.txt file, which lies in the folder with the Arduino in the following path hardware / arduino / avr. Find the line in the file.
below which are the fyuz settings for the bootloader for the Arduino Pro or Pro Mini (3.3V, 8 MHz). Below we find the line:
Save the boards.txt and flashing the bootloader to the microcontroller.
We solder all the details on the printed circuit board according to the pattern with the location of the elements.
The display can be bought both separately and on the board. In the latter case, it will have to be unsoldered, for which you can take the necessary strapping for the display from the board.
The case was printed on a 3D plastic ABS printer. For watches fit any suitable straps 20mm wide.
I give a complete sketch of the program for hours. At the moment, the clock can display the current time and date, as well as make their setting. With the current functionality, the size of the sketch is about 20 kb.
Sketch// Arduino DIY Watch
// Ivan Grishin
// e-mail: arduinowatch@mail.ru
//
//
// Button 1 >>>> 2
// Button 2 >>>> A1
// Button 3 >>>> 3
// Vbat >>>>>>>> A0;
#include "LowPower.h"
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH1106.h>
#include <DS1337.h>
#define OLED_RESET 4
Adafruit_SH1106 display (OLED_RESET);
#include <stdio.h>
DS1337 RTC = DS1337 ();
int val = 0;
const int b1 = 2;
const int b2 = A1;
const int b3 = 3;
const int vb = A0;
int mode = 1;
int modest = 0;
int h = 0;
int m = 0;
int s = 0;
int d = 0;
int mo = 0;
int y = 0;
int lock = 0;
int volt = 0;
float vbat = 0;
int timebat = 1;
int voltTime = 1;
// # define BAT_HEIGHT 16
// # define BAT_GLCD_WIDTH 7
static const unsigned char PROGMEM bat_bmp0 [] =
{B00111111, B11111111,
B00100000, B00000001,
B11100000, B00000001,
B11100000, B00000001,
B11100000, B00000001,
B00100000, B00000001,
B00111111, B11111111,};
static const unsigned char PROGMEM bat_bmp1 [] =
{B00111111, B11111111,
B00100000, B00000011,
B11100000, B00000011,
B11100000, B00000011,
B11100000, B00000011,
B00100000, B00000011,
B00111111, B11111111,};
static const unsigned char PROGMEM bat_bmp2 [] =
{B00111111, B11111111,
B00100000, B00000111,
B11100000, B00000111,
B11100000, B00000111,
B11100000, B00000111,
B00100000, B00000111,
B00111111, B11111111,};
static const unsigned char PROGMEM bat_bmp3 [] =
{B00111111, B11111111,
B00100000, B00001111,
B11100000, B00001111,
B11100000, B00001111,
B11100000, B00001111,
B00100000, B00001111,
B00111111, B11111111,};
static const unsigned char PROGMEM bat_bmp4 [] =
{B00111111, B11111111,
B00100000, B00011111,
B11100000, B00011111,
B11100000, B00011111,
B11100000, B00011111,
B00100000, B00011111,
B00111111, B11111111,};
static const unsigned char PROGMEM bat_bmp5 [] =
{B00111111, B11111111,
B00100000, B00111111,
B11100000, B00111111,
B11100000, B00111111,
B11100000, B00111111,
B00100000, B00111111,
B00111111, B11111111,};
static const unsigned char PROGMEM bat_bmp6 [] =
{B00111111, B11111111,
B00100000, B01111111,
B11100000, B01111111,
B11100000, B01111111,
B11100000, B01111111,
B00100000, B01111111,
B00111111, B11111111,};
static const unsigned char PROGMEM bat_bmp7 [] =
{B00111111, B11111111,
B00100000, B11111111,
B11100000, B11111111,
B11100000, B11111111,
B11100000, B11111111,
B00100000, B11111111,
B00111111, B11111111,};
static const unsigned char PROGMEM bat_bmp8 [] =
{B00111111, B11111111,
B00100001, B11111111,
B11100001, B11111111,
B11100001, B11111111,
B11100001, B11111111,
B00100001, B11111111,
B00111111, B11111111,};
static const unsigned char PROGMEM bat_bmp9 [] =
{B00111111, B11111111,
B00100011, B11111111,
B11100011, B11111111,
B11100011, B11111111,
B11100011, B11111111,
B00100011, B11111111,
B00111111, B11111111,};
static const unsigned char PROGMEM bat_bmp10 [] =
{B00111111, B11111111,
B00100111, B11111111,
B11100111, B11111111,
B11100111, B11111111,
B11100111, B11111111,
B00100111, B11111111,
B00111111, B11111111,};
static const unsigned char PROGMEM bat_bmp11 [] =
{B00111111, B11111111,
B00100111, B11111111,
B11100111, B11111111,
B11100111, B11111111,
B11100111, B11111111,
B00100111, B11111111,
B00111111, B11111111,};
static const unsigned char PROGMEM bat_bmp12 [] =
{B00111111, B11111111,
B00101111, B11111111,
B11101111, B11111111,
B11101111, B11111111,
B11101111, B11111111,
B00101111, B11111111,
B00111111, B11111111,};
static const unsigned char PROGMEM bat_bmp13 [] =
{B00111111, B11111111,
B00111111, B11111111,
B11111111, B11111111,
B11111111, B11111111,
B11111111, B11111111,
B00111111, B11111111,
B00111111, B11111111,};
void wakeUp () {}
void setup () {
display.begin (SH1106_SWITCHCAPVCC, 0x3c);
RTC.start ();
pinMode (b1, INPUT);
pinMode (b2, INPUT);
pinMode (vb, INPUT);
analogReference (INTERNAL);
display.setRotation (2); // image rotation 180 degrees
}
void loop () {
display.SH1106_command (SH1106_DISPLAYOFF);
mode = 1;
attachInterrupt (0, wakeUp, HIGH);
LowPower.powerDown (SLEEP_FOREVER, ADC_OFF, BOD_OFF);
detachInterrupt (0);
display.clearDisplay ();
delay (10);
display.SH1106_command (SH1106_DISPLAYON);
for (val; val <= 150;)
{
RTC.readTime ();
int state1 = digitalRead (b1);
int state2 = digitalRead (b2);
int state3 = digitalRead (b3);
if (state2 == 1 && lock == 0)
{
mode ++;
delay (130);
state2 = 0;
}
if (state3 == 1)
{
display.begin (SH1106_SWITCHCAPVCC, 0x3c);
display.setRotation (2);
display.clearDisplay ();
delay (100);
}
if (mode == 1) {
time ();
battery ();
display.display ();
val ++;
}
// ++++++++++++++++ MODE SET TIME +++++++++++++++++
while (mode == 2)
{
int state1 = digitalRead (b1);
int state2 = digitalRead (b2);
int state3 = digitalRead (b3);
lock = 1;
if (state2 == 1)
{
modest ++;
delay (150);
state2 = 0;
}
// +++++++++++++++++++ Set HOURS ++++++++++++++++++++
if (modest == 1)
{
display.clearDisplay ();
display.setTextSize (3);
display.setTextColor (BLACK, WHITE);
display.setCursor (0.20);
if (h <= 9)
{display.print ("0");}
display.print (h);
display.setTextColor (WHITE);
display.print (":");
if (m <= 9)
{display.print ("0");}
display.print (m);
display.setTextSize (2);
display.setCursor (90,28);
display.print (":");
if (s <= 9)
{display.print ("0"); }
display.print (s);
battery ();
display.setTextSize (1);
display.setCursor (40,50);
display.print (d);
display.print ('/');
display.print (mo);
display.print ('/');
display.print (y);
display.display ();
if (state1 == 1)
{
h ++;
delay (150);
}
if (state3 == 1)
{
h--;
delay (150);
}
if (h> = 24)
{h = 0;}
if (h <0)
{h = 23;}
if (state2 == 1)
{
modest ++;
delay (150);
state2 = 0;
}
}
// ++++++++++++++++++++++++++++ SET MIN +++++++++++++++++ +
if (modest == 2)
{
display.clearDisplay ();
display.setTextSize (3);
display.setTextColor (WHITE);
display.setCursor (0.20);
if (h <= 9)
{display.print ("0");}
display.print (h);
display.print (":");
display.setTextColor (BLACK, WHITE);
if (m <= 9)
{display.print ("0");}
display.print (m);
display.setTextColor (WHITE);
display.setTextSize (2);
display.setCursor (90,28);
display.print (":");
if (s <= 9)
{display.print ("0"); }
display.print (s);
battery ();
display.setTextSize (1);
display.setCursor (40,50);
display.print (d);
display.print ('/');
display.print (mo);
display.print ('/');
display.print (y);
display.display ();
if (state1 == 1)
{
m ++;
delay (100);
}
if (state3 == 1)
{
m--;
delay (150);
}
if (m> = 60)
{m = 0;}
if (m <0)
{m = 59;}
if (state2 == 1)
{
modest ++;
delay (150);
state2 = 0;
}
}
// +++++++++++++++++++++++ SET SEC +++++++++++++++++++++++
if (modest == 3)
{
display.clearDisplay ();
display.setTextSize (3);
display.setTextColor (WHITE);
display.setCursor (0.20);
if (h <= 9)
{display.print ("0");}
display.print (h);
display.print (":");
if (m <= 9)
{display.print ("0");}
display.print (m);
display.setTextSize (2);
display.setCursor (90,28);
display.print (":");
display.setTextColor (BLACK, WHITE);
if (s <= 9)
{display.print ("0"); }
display.print (s);
display.setTextColor (WHITE);
battery ();
display.setTextSize (1);
display.setCursor (40,50);
display.print (d);
display.print ('/');
display.print (mo);
display.print ('/');
display.print (y);
display.display ();
if (state1 == 1)
{
s ++;
delay (100);
}
if (state3 == 1)
{
s--;
delay (150);
}
if (s> = 60)
{s = 0;}
if (s <0)
{s = 59;}
if (state2 == 1)
{
modest ++;
delay (150);
state2 = 0;
}
}
// +++++++++++++++++++++++ END SET SEC ++++++++++++++++++++++
// +++++++++++++++++++++++ SET DAY +++++++++++++++++++++++
if (modest == 4)
{
display.clearDisplay ();
display.setTextSize (3);
display.setTextColor (WHITE);
display.setCursor (0.20);
if (h <= 9)
{display.print ("0");}
display.print (h);
display.print (":");
if (m <= 9)
{display.print ("0");}
display.print (m);
display.setTextSize (2);
display.setCursor (90,28);
display.print (":");
if (s <= 9)
{display.print ("0"); }
display.print (s);
display.setTextColor (WHITE);
battery ();
display.setTextSize (1);
display.setCursor (40,50);
display.setTextColor (BLACK, WHITE);
display.print (d);
display.setTextColor (WHITE);
display.print ('/');
display.print (mo);
display.print ('/');
display.print (y);
display.display ();
if (state1 == 1)
{
d ++;
delay (100);
}
if (state3 == 1)
{
d--;
delay (150);
}
if (d> = 32)
{d = 1;}
if (d <0)
{d = 31;}
if (state2 == 1)
{
modest ++;
delay (150);
state2 = 0;
}
}
// +++++++++++++++++++++++ END SET DAY ++++++++++++++++++++++
// +++++++++++++++++++++++ SET MON +++++++++++++++++++++++
if (modest == 5)
{
display.clearDisplay ();
display.setTextSize (3);
display.setTextColor (WHITE);
display.setCursor (0.20);
if (h <= 9)
{display.print ("0");}
display.print (h);
display.print (":");
if (m <= 9)
{display.print ("0");}
display.print (m);
display.setTextSize (2);
display.setCursor (90,28);
display.print (":");
if (s <= 9)
{display.print ("0"); }
display.print (s);
display.setTextColor (WHITE);
battery ();
display.setTextSize (1);
display.setCursor (40,50);
display.print (d);
display.print ('/');
display.setTextColor (BLACK, WHITE);
display.print (mo);
display.setTextColor (WHITE);
display.print ('/');
display.print (y);
display.display ();
if (state1 == 1)
{
mo ++;
delay (100);
}
if (state3 == 1)
{
mo--;
delay (150);
}
if (mo> = 13)
{mo = 1;}
if (mo <0)
{mo = 12;}
if (state2 == 1)
{
modest ++;
delay (150);
state2 = 0;
}
}
// +++++++++++++++++++++++ END SET DAY ++++++++++++++++++++++
// +++++++++++++++++++++++ SET YEAR +++++++++++++++++++++++
if (modest == 6)
{
display.clearDisplay ();
display.setTextSize (3);
display.setTextColor (WHITE);
display.setCursor (0.20);
if (h <= 9)
{display.print ("0");}
display.print (h);
display.print (":");
if (m <= 9)
{display.print ("0");}
display.print (m);
display.setTextSize (2);
display.setCursor (90,28);
display.print (":");
if (s <= 9)
{display.print ("0"); }
display.print (s);
display.setTextColor (WHITE);
battery ();
display.setTextSize (1);
display.setCursor (40,50);
display.print (d);
display.print ('/');
display.print (mo);
display.print ('/');
display.setTextColor (BLACK, WHITE);
display.print (y);
display.display ();
if (state1 == 1)
{
y ++;
delay (100);
}
if (state3 == 1)
{
y--;
delay (150);
}
if (y> = 2020)
{y = 2000;}
if (state2 == 1)
{
modest ++;
delay (150);
state2 = 0;
}
}
// +++++++++++++++++++++++ END SET YEAR ++++++++++++++++++++++
// ++++++++++++++++++++++ WRITE to DS1337 +++++++++++++++
if (modest == 7)
{
RTC.setSeconds (s);
RTC.setMinutes (m);
RTC.setHours (h);
RTC.setDays (d);
RTC.setMonths (mo);
RTC.setYears (y);
RTC.writeTime ();
delay (1);
lock = 0;
modest = 1;
mode = 1;
val = 0;
}
}
val ++;
}
val = 0;
display.clearDisplay ();
// delay (50);
}
void battery (void)
{
if (voltTime == 1)
{
volt = analogRead (vb);
vbat = volt * 0.0045;
voltTime = 5;
}
voltTime--;
if (2> vbat && vbat> = 1) {display.drawBitmap (0,0, bat_bmp0, 16, 7, 1);}
if (2.1> vbat && vbat> = 2) {display.drawBitmap (0,0, bat_bmp1, 16, 7, 1);}
if (2.2> vbat && vbat> = 2.1) {display.drawBitmap (0,0, bat_bmp2, 16, 7, 1);}
if (2.3> vbat && vbat> = 2.2) {display.drawBitmap (0,0, bat_bmp3, 16, 7, 1);}
if (2.4> vbat && vbat> = 2.3) {display.drawBitmap (0,0, bat_bmp4, 16, 7, 1);}
if (2.5> vbat && vbat> = 2.4) {display.drawBitmap (0,0, bat_bmp5, 16, 7, 1);}
if (2.6> vbat && vbat> = 2.5) {display.drawBitmap (0,0, bat_bmp6, 16, 7, 1);}
if (2.7> vbat && vbat> = 2.6) {display.drawBitmap (0,0, bat_bmp7, 16, 7, 1);}
if (2.8> vbat && vbat> = 2.7) {display.drawBitmap (0,0, bat_bmp8, 16, 7, 1);}
if (2.9> vbat && vbat> = 2.8) {display.drawBitmap (0,0, bat_bmp9, 16, 7, 1);}
if (3> vbat && vbat> = 2.9) {display.drawBitmap (0,0, bat_bmp10, 16, 7, 1);}
if (3.1> vbat && vbat> = 3) {display.drawBitmap (0,0, bat_bmp11, 16, 7, 1);}
if (3.2> vbat && vbat> = 3.1) {display.drawBitmap (0,0, bat_bmp12, 16, 7, 1);}
if (4> vbat && vbat> = 3.2) {display.drawBitmap (0,0, bat_bmp13, 16, 7, 1);}
/ *
if (2> vbat && vbat> = 1) {display.drawRect (0,2,2,4,1); display.drawRect (2,0,14,8,1);}
if (2.1> vbat && vbat> = 2) {display.drawRect (0,2,2,4,1); display.drawRect (2,0,14,8,1); display.fillRect (13,1, 13,1,1);}
if (2.2> vbat && vbat> = 2.1) {display.drawRect (0,2,2,4,1); display.drawRect (2,0,14,8,1); display.fillRect (13,1, 2,6,1);}
if (2.3> vbat && vbat> = 2.2) {display.drawRect (0,2,2,4,1); display.drawRect (2,0,14,8,1); display.fillRect (12,1, 3,6,1);}
if (2.4> vbat && vbat> = 2.3) {display.drawRect (0,2,2,4,1); display.drawRect (2,0,14,8,1); display.fillRect (11,1, 4,6,1);}
if (2.5> vbat && vbat> = 2.4) {display.drawRect (0,2,2,4,1); display.drawRect (2,0,14,8,1); display.fillRect (10,1, 5,6,1);}
if (2.6> vbat && vbat> = 2.5) {display.drawRect (0,2,2,4,1); display.drawRect (2,0,14,8,1); display.fillRect (9,1, 6,6,1);}
if (2.7> vbat && vbat> = 2.6) {display.drawRect (0,2,2,4,1); display.drawRect (2,0,14,8,1); display.fillRect (8,1, 7,6,1);}
if (2.8> vbat && vbat> = 2.7) {display.drawRect (0,2,2,4,1); display.drawRect (2,0,14,8,1); display.fillRect (7,1, 8,6,1);}
if (2.9> vbat && vbat> = 2.8) {display.drawRect (0,2,2,4,1); display.drawRect (2,0,14,8,1); display.fillRect (6,1, 9,6,1);}
if (3> vbat && vbat> = 2.9) {display.drawRect (0,2,2,4,1); display.drawRect (2,0,14,8,1); display.fillRect (5,1, 10,6,1);}
if (3.1> vbat && vbat> = 3) {display.drawRect (0,2,2,4,1); display.drawRect (2,0,14,8,1); display.fillRect (4,1, 11,6,1); }
if (3.2> vbat && vbat> = 3.1) {display.drawRect (0,2,2,4,1); display.drawRect (2,0,14,8,1); display.fillRect (3,1, 12,6,1);}
if (4> vbat && vbat> = 3.2) {display.drawRect (0,2,2,4,1); display.drawRect (2,0,14,8,1); display.fillRect (2,1, 13,6,1);}
* /
display.setTextSize (1);
display.setCursor (90.0);
display.print (vbat);
display.print ("V");
}
void time (void)
{
h = RTC.getHours ();
m = RTC.getMinutes ();
s = RTC.getSeconds ();
d = RTC.getDays ();
mo = RTC.getMonths ();
y = RTC.getYears ();
display.clearDisplay ();
display.setTextSize (3);
display.setTextColor (WHITE);
display.setCursor (0.20);
if (h <= 9)
{display.print ("0");}
display.print (h);
display.print (":");
if (m <= 9)
{display.print ("0");}
display.print (m);
display.setTextSize (2);
display.setCursor (90,28);
display.print (":");
if (s <= 9)
{display.print ("0"); }
display.print (s);
display.setTextSize (1);
display.setTextColor (WHITE);
display.setCursor (40,50);
display.print (d);
display.print ('/');
display.print (mo);
display.print ('/');
display.print (y);
}
void show_time (void)
{
display.clearDisplay ();
display.setTextSize (3);
display.setTextColor (WHITE);
display.setCursor (0.20);
if (h <= 9)
{display.print ("0");}
display.print (h);
display.print (":");
if (m <= 9)
{display.print ("0");}
display.print (m);
display.setTextSize (2);
display.setCursor (90,28);
display.print (":");
if (s <= 9)
{display.print ("0"); }
display.print (s);
display.setTextSize (1);
display.setTextColor (WHITE);
display.setCursor (40,50);
display.print (d);
display.print ('/');
display.print (mo);
display.print ('/');
display.print (y);
}
At the end of the article there will be a link to all the necessary materials for self-made watches. Several changes have been made to these materials, which should correct minor issues found in already made hours. For example, the printed circuit board is fixed and now it does not require additional jumpers, the size of the board itself is also slightly increased, which made it possible to shift the micro USB connector closer to the watch case.
In conclusion, I want to say that on the basis of this device, you can implement many interesting and unusual devices and not all of them should be for hours. But at the same time, the possibility of independent programming opens up wide possibilities for customizing watches and their interface. Those. you can actually use any font or image, various options for the location of elements on the screen, limited only by your imagination.
Video, where you can look at the clock and their work, as well as learn more about their device.
That's all for now. I look forward to your questions and healthy criticism ...
UPD. An added PCB file will be added on Monday February 29th.