BBC micro:bit
Neopixel Ring Clock

Introduction

I had a DS1388 RTC board to try and thought it might be nice to display the time on some Neopixel rings. The project uses 2 rings, each containing 12 pixels The image shows 17:35 - the time is displayed to the nearest 5 minutes.

micro:bit circuit

I have tried out a few RTCs with the micro:bit. The most popular microcontroller RTC breakouts are for the DS1307 and need 5V. The DS3231 works at 3V3 and is theoretically very precise. Decent breakouts are not cheap and the cheap ones have let me down a little. The PCF8523 works at 3V3 and appears a lot on Raspberry Pi accessories. It isn't very accurate though. The DS1388 is a drop-in replacement for the DS1307 and works nicely on the micro:bit. The one I used comes from Hobbytronics.

The Circuit

Components are as follows,

  • 12-pixel Neopixel Ring x2
  • 3xAA Battery Box & Batteries
  • Hobbytronics DS1388 Breakout

I started by connecting the battery box terminals to the power rails on a breadboard.

The Neopixel rings I had are not chainable, so they had to be connected separately, which made the programming easier. Each ring needs 3 connections. Power and ground go to the power rails that the batteries are connected to. The Data In of the hours ring was connected to pin13 and the minutes to pin14.

The RTC is connected via I2C. VCC goes to 3V, GND to GND. SCL to pin 19, SDA to pin 20.

The GND of the micro:bit is connected to the GND power rail with the batteries to make a common ground connection.

Programming - RTC

Some code to test the RTC.

from microbit import *

def bcd2bin(value):
    return (value or 0) - 6 * ((value or 0) >> 4)

def bin2bcd(value):
    return (value or 0) + 6 * ((value or 0) // 10)
       
def get_time():
    i2c.write(0x68, b'\x00')
    buf = i2c.read(0x68, 7)
    s = bcd2bin(buf[0] & 0x7F)
    m = bcd2bin(buf[1])
    h = bcd2bin(buf[2])
    w = bcd2bin(buf[3])
    dd = bcd2bin(buf[4])
    mm = bcd2bin(buf[5])
    yy = bcd2bin(buf[6]) + 2000
    return [s,m,h,w,dd,mm,yy]

def set_time(s,m,h,w,dd,mm,yy):
    tm = bytes([0x00] + [bin2bcd(i) for i in [s,m,h,w,dd,mm,yy-2000]])
    i2c.write(0x68,tm)
    
set_time(0,11,17,2,9,4,2018)
while True:
    print(get_time())
    sleep(1000)    

Programming - RTC & Display

The minutes are shown rounded to the nearest 5.

from microbit import *
import neopixel

# Initialise neopixels
h = neopixel.NeoPixel(pin13, 12)
m = neopixel.NeoPixel(pin14, 12)

red = (255,0,0)
lred = (64,0,0)
green = (0,255,0)
lgreen = (0,64,0)

def light_all(ring,colour):
    for pix in range(len(ring)):
        ring[pix] = colour

#RTC functions
def bcd2bin(value):
    return (value or 0) - 6 * ((value or 0) >> 4)

def bin2bcd(value):
    return (value or 0) + 6 * ((value or 0) // 10)
       
def get_time():
    i2c.write(0x68, b'\x00')
    buf = i2c.read(0x68, 7)
    s = bcd2bin(buf[0] & 0x7F)
    m = bcd2bin(buf[1])
    h = bcd2bin(buf[2])
    w = bcd2bin(buf[3])
    dd = bcd2bin(buf[4])
    mm = bcd2bin(buf[5])
    yy = bcd2bin(buf[6]) + 2000
    return [s,m,h,w,dd,mm,yy]

def set_time(s,m,h,w,dd,mm,yy):
    tm = bytes([0x00] + [bin2bcd(i) for i in [s,m,h,w,dd,mm,yy-2000]])
    i2c.write(0x68,tm)
    
#set_time(0,11,17,2,9,4,2018)
lastm = 0
lasth = 0
while True:
    t = get_time()
    vm = t[1]//5
    if t[2]==0 or t[2]==12:
        vh = 0
    elif t[2]>12:
        vh = t[2]-12
    else:
        vh = t[2]   
    light_all(h,lgreen)
    light_all(m,lred)
    h[vh] = red
    m[vm] = green
    h.show()
    m.show()
    sleep(1000)            

Review & Next Steps

It's nice and bright. Red and green provide a nice contrast for me and make the dots easy to see. It's worth experimenting with some other colours.

If the project were portable, it would be worth making the pixels light up to show the time only on a button press. That gives an excuse for a little animation.

An extra strip of Neopixels, in between the two rings, could count up and down the seconds or blink a few of its pixels on and off with the ticking of the seconds. This would make the whole thing more interesting.

The bright lights make this well suited to a more permanent build. Set behind a nice diffuser, with a few buttons and a buzzer or speaker, there is a usable long term clock.