Tuesday, April 8, 2014

Micro clock with 7-segment bubble display

Updated Aug 30, 2014: A kit for this clock shield is now offered here.

I am not particularly attracted by 7-segment LED displays, but I liked the HP bubble display that Sparkfun started selling recently. Like with the Nixie tubes, there aren't many things one can build with them, and my obvious choice was a clock. Being one of the smallest 7-segment LED displays out there, the clock had to be miniature as well. It took some thinking and planning to come to this final "design":

This micro clock uses the Pro Mini sandwiched between the LiPo battery undershield and the display shield (that also includes the RTC), both DIY on protoboard.

The LiPo undershield uses a cheap (less than $1 on ebay) USB charger board, which also provides the USB connector for power, since Pro Mini does not have one. The small 180mAh LiPo battery sits on top of the charger, but still allowing the 2 LEDs ("charging" and "charged") to be visible. There is also a switch for turning the battery power on or off. The clock is normally powered from a USB power adapter, but it can also work on battery for about 9 hours (the measured average current draw is around 20mA) when the USB cable is not plugged in. In this latter case, it can be turned on from the power switch to show the time only when needed.

The display shield is oversized to make the clock sit at an angle. This solution also provided enough room to include the RTC chip and the backup battery. Actually, and this will probably be the topic of a future post on DIY miniaturization, I did not have a choice for creating a separate RTC shield. The machined headers I used, not the stacking kind (which would have been disproportionately big), only allowed a top and a bottom shield around the Pro Mini board.

As one can imagine, the sketch is trivial (after reading the excellent Sparkfun tutorial :) and based on the SevenSeg arduino library.
But there is always a little glitch somewhere. In this case, I misinterpreted the datasheet. Normally, digit 1 is the left (most significant) one. My wiring assumed digit 1 is the rightmost (least significant) digit.
I fixed it in software: redefined digit1...digit4, then rotated segments (segA to SegF) 180 degrees.

#include "SevSeg.h"
#include < Wire.h >
#include "DS1307.h"

SevSeg myDisplay;
unsigned long timer;

void setup()
   int displayType = COMMON_CATHODE;

   // arduino pins connected to cathodes;
   int digit1 = 15; //Pin 1
   int digit2 = 13; //Pin 10
   int digit3 =  3; //Pin 4
   int digit4 = 14; //Pin 6

   // arduino pins connected to the segments (anodes);
   int segC =  6; //Pin 3
   int segE =  4; //Pin 2
   int segG =  5; //Pin 7
   int segB = 12; //Pin 11
   int segD =  8; //Pin 8
   int segF = 11; //Pin 9
   int segA =  7; //Pin 12

   // not connected yet;
   int segDP= 10; //Pin 5

   int numberOfDigits = 4; // this display has 4 digits;

   // initialize the 7-segment display object;
   myDisplay.Begin(displayType, numberOfDigits, digit1, digit2, digit3, digit4, segA, segB, segC, segD, segE, segF, segG, segDP);

   myDisplay.SetBrightness(100); // 100% brightness

   timer = millis();

void loop()
  int rtc[7];
  RTC_DS1307.get(rtc, true);
  int minute = rtc[DS1307_MIN];
  int hour   = rtc[DS1307_HR];
  char timeString[10];
  sprintf(timeString, "%02d%02d", hour, minute);
  myDisplay.DisplayString(timeString, 0);

  if (millis() - timer >= 1000)
    timer = millis();

The next version of the bubble clock should use two displays (8 digits), showing the seconds as well.


  1. This brings back memories... I still have the circuit board from the Sinclair Black Watch I built as a kit.

  2. Nice. I only saw that in magazine advertisements, years later. (In this regard, my memories begin not very far though, with Sinclair ZX Spectrum.)

  3. hi florin,
    sorry to bother you (still learning).

    I've been trying to get to work a 7segment -display clock i've been working on and decided to try it with your code.

    unfortunately it gives me the error 'COMMON_ANODE' was not declared in this scope.

    I included the SevSeg library so it should work...

    (PS. btw. whats the difference when including libraries whether you use #include "xyz.h" or #include ?)

    1. In my SevSeg.h I have this definitions (I don't remember if they were there or I added them myself):

      #define COMMON_CATHODE 0
      #define COMMON_ANODE 1

      Not sure I understand the question "whats the difference when including libraries whether you use #include "xyz.h" or #include ?"

      If you mean using double quotes vs angular brackets (less than, greater than), then, for angular brackets it looks in the system folder (arduino core files) for header files rather than just in the current project folder.

    2. Hi Florin,

      I'm getting these errors, wonder how do i clear them. I have saved the library in the library folder but it doesnt work.

      Errs below:

      bubble.cpp:30:20: error: SevSeg.h: No such file or directory
      bubble:32: error: 'SevSeg' does not name a type
      bubble.cpp: In function 'void setup()':
      bubble:41: error: 'COMMON_CATHODE' was not declared in this scope
      bubble:63: error: 'myDisplay' was not declared in this scope
      bubble.cpp: In function 'void loop()':
      bubble:81: error: 'myDisplay' was not declared in this scope

    3. The error says that it cannot find SevSeg.h.
      Did you download the SevSeg library (from http://playground.arduino.cc/Main/SevenSegmentLibrary)?

      If so, make sure the 2 files (cpp and h) are in libraries/SevSeg folder. Or you can just copy them in the folder where your ino file is.

      Also, I noticed that the second line (#include) is missing the second part. It should be

      (I'll fix it in the post too).

  4. Hi Florin,

    Which RTC library are you using?


    1. A very old one, it seems, but suits my needs:
      DS1307.h - library for DS1307 rtc
      Created by matt.joyce@gmail.com, December, 2007.

      It's just 2 files (h, cpp). The interface looks like this:

      class DS1307
      // user-accessible "public" interface
      void get(int *, boolean);
      int get(int, boolean);
      int min_of_day(boolean);
      void set(int, int);
      void start(void);
      void stop(void);
      void get_sram_data(byte *);
      void set_sram_data(byte *);
      byte get_sram_byte(int);
      void set_sram_byte(byte, int);
      // library-accessible "private" interface
      byte rtc_bcd[7]; // used prior to read/set ds1307 registers;
      void read_rtc(void);
      void save_rtc(void);

      extern DS1307 RTC_DS1307;

    2. The libraries and program codes that you shared are giving an error.

    3. It used to compile fine in Arduino 1.0.6.

  5. hi florin my error?
    In function 'void loop()':

    mini_pro_clock_v1:43: error: 'RTC_DS1307' was not declared in this scope

    1. You need this

      extern DS1307 RTC_DS1307;

      in your DS1307.h and this

      DS1307 RTC_DS1307;

      in your DS1307.cpp

    2. hi florin micro clock with 7-segment bubble display v1 full schematic and all pictures you could send it to my e-mail address. nanotech775@gmail.com thanks.

    3. arduino 1.0.6 your program codes complete error given. original ds1307.h ds1307.cpp and sevseg library files shared. thanks.

  6. hi florin error error error arduino 1.0.6
    pro_mini_bubble_clock.ino: In function 'void setup()':
    pro_mini_bubble_clock:33: error: 'class SevSeg' has no member named 'Begin'
    pro_mini_bubble_clock:35: error: 'class SevSeg' has no member named 'SetBrightness'
    pro_mini_bubble_clock.ino: In function 'void loop()':
    pro_mini_bubble_clock:48: error: 'class SevSeg' has no member named 'DisplayString'