Introduction: Minidot 2 - the Holoclock

About: update later
Well maybe holoclock is a little bit inaccurate....it does use holographic dispersion film on the front to give a bit of depth.

Basicaly this instructable is an update to my previous Minidot located here:
https://www.instructables.com/id/EEGLXQCSKIEP2876EE/
and re-using a lot of code and circuitry from my Microdot located here:
https://www.instructables.com/id/EWM2OIT78OERWHR38Z/

EagleCAD files and Sourceboost code is included in the zip files attached.

Why? The previous Minidot was overly complex, from the Microdot I learned how to do an RTC on a PIC using only a 32.768 crystal and didn't need to use a special RTC chip. Also I wanted to get rid of the display chips from the previous Minidot. So now there is only a power regulator chip and a PIC16F88....just two chips.
The other reasons for an update were my Minidot was getting a bit un-reliable because of the seperate switch board and I wanted a soft fade between dot patterns as well as some sort of ambient light sensor to dim the display at night. The other Minidot was fixed brightness, and illuminated a room at night.

The device was constructed with the aid of the EagleCad software package and Sourceboost compiler. You'll need to have some experience with electronics and programming PIC controllers to start this project. Please note this isn't an instructable on either electronics or PIC programming, so please keep questions relevant to the Miniclock design. Refer to the instructables above or many other instructables on this site for advice on using EagleCad or programming PICs.

So here it is.....Minidot 2, The Holoclock......or Minidot The Next Generation.............


Step 1: The Circuit

This circuit is very simliar to the Microdot. Note the charlieplex array is virtually identical...only a few pins have been moved.

A 20Mhz crystal has been added to the Microdot circuit to clock the PIC much faster, this allows the array to be scanned faster and enables the implementation of a dimming algorithm. The dimming algorithm was very important to getting a cross pattern fade and ambient light function to work. This would have been impossible with the Microdot, because of the slower clock speed as some scan cycles needed to be spent on dimming. See next section for a description of the Dimming functionality.

The other things to note are the use of a MCP1252 charge pump regulator to supply 5V, my favourite chip at the moment. If you modified the circuit you could use a plain old 7805......I just have a number of these handy chips hanging around.

I've now moved the switches to the front, saves fiddling round the back of the clock after power dropouts to reset the time and now everything is only one PCB....no cabling issues.

Also of note is the inclusion of an LDR. This is used in a voltage divider which is sensed by the A/D pin on the PIC. When the PIC senses the ambient light level is low (ie night time) the dimming algorithm keeps the charlieplex array dark for more cycles than when the light level is high. I couldn't find an LDR symbol in the Eaglecad library, so I just used an LED symbol.....don't be fooled it's an LDR. See actual picture of the PCB below.

One thing to note when using multi-coloured LEDs in a charliplex array. You need to make sure the forward voltage of the LEDs are more or less the same. If not, then stray current paths may occur and multiple LEDs will light. Thus using 5mm or higher power LEDs for this configuration will not work as there is usually quite a difference between the green/blue LEDs and the red/yellow LEDs. In this case I used 1206 SMD leds and high efficiency green/blue LEDs in particular. The forward voltages were not an issue here though. If you wanted to use a mix of green/blue and red/yellow higher power LEDs in a charlieplex array you'd need to seperate out the different colours into two charliplex arrays.

There are numerous explanations of charlieplexing that can be googled......I'll not go into details here. I'll leave it to you to do some research.
(Press the little 'i' icon in the corner of the pic below to see a larger version)

Step 2: The Dimming Algorithm - Charliplexed Pulse Width Modulation

As mentioned earlier, I wanted to have the different dot patterns for the time fade smoothly rather than jerking from one pattern to another.

See the video for a demonstration. In the middleis the new Minidot clock, on the right is the older Minidot. Notice how much nicer the new one is.


(FYI the other displays in the background are my Minicray supercomputer status display and my captured Nebulon particle which powers the Minicray in an antimatter magnetic confinement field. See here:
http://www.youtube.com/watch?v=bRupDulR4ME
for a demonstration of the nebulon confinement chamber)

If you look in the code, open the display.c file. Note there are four arrays for mapping the tris/port values to illuminate any particular array and two arrays (one more than the Microdot code) for defining which LEDs should be illuminated for any particular pattern of LEDs.
eg:
//                              LED1  LED2  LED3  ...unsigned char LEDS_PORTA[31] = { 0x10, 0x00, 0x00, ...unsigned char LEDS_TRISA[31] = { 0xef, 0xff, 0xff, ...unsigned char LEDS_PORTB[31] = { 0x00, 0x02, 0x04, ...unsigned char LEDS_TRISB[31] = { 0xfd, 0xf9, 0xf9, ...unsigned char nLedsA[30];unsigned char nLedsB[30];

To light up LED1 for example, you need to set the TRIS registers TRISA:B = 0xef:0xfd and PORT registers PORTA:B=0x10:0x00 and so on. If you write out the tris values in binary you'll note that at any one time, there are only two outputs enabled. The others are all set to Tri-state (hence TRIS register). This is central to charlieplexing. You'll also note that one output is always a logical '1' and the other is always a logical '0'....the direction of which turns on whichever LED is between these two output lines.
The last value in the port/tris arrays is a null value to turn on no LED at all.

In the Microdot, the update_display function cycled continuously through another array (nLeds[]) to see if that particular LED was to be illuminated. If it was, then the corresponding tris/port values were set and the LED illuminated for a period of time. Otherwise the null value was sent to the PICs TRIS/PORT registers and no LED was illuminated for a period of time. When done fast enough this gave a pattern. The rest of the program would periodically read the RTC values and make up a nice random pattern in that array....and so the display changed.

To make a dimming function, this was slightly extended so that after the 30 LEDs were either illuminated (or not) then extra periods would be spent on sending null values if the display was to be dimmed.....for full brightness then no extra periods would be spent. When repeated if there were a lot of null periods to the illuminated LEDs, the display would be dim. In effect this is multiplexed pulse width modulation.....or because the hardware is configured in a charlieplex arragement, then charlieplexed pulse width modulation.

The second diagram below shows the basic setup for this. I call this a scan frame. The first 30 periods to the frame are used to go through the LEDs.....and a variable number of extra periods define how dim the display will be. This cycle repeats. More null periods means less time for an LED to be on per frame (because the number of periods increased). Note the vertical axis doesn't mean voltage level. The actual state of the pins going to the LEDs varies depending on it's position in the charlieplex array.....in the diagram it just means on or off.

This also meant the total length of the frame in time also increased, thus decreasing the refresh rate. As the LEDs got dimmer, they would start to flicker in other words. So this method is useful only to an extent. For the clock, it was OK.

A function is called intermittantly that reads the A/D converter on the PIC and sets this brightness level. If you read the code, it also checks to see if the LED nearest the LDR is on, and doesn't do any level setting if so, this stops the display unexpectedly brighting when the pattern changed.

Next the cross fade function.

Step 3: Dimming Algorithm - the Cross Fade Effect and Double Buffering

The transition between one pattern and the next was previously immediate. For this clock I wanted to show one pattern gradually decreasing in brightness and the next pattern gradually increasing...ie a cross fade.

I didn't need to have individual LEDs to be controlled at seperate brightness levels to do a cross fade. Just needed the first pattern at one brightness and the second at a low brightness. Then over a short period I'd decrease the brightness of the first a little, and increase the second.....this would keep going until the second pattern as at full. Then the clock would wait till the next pattern was due to show and there would be another transition.

Thus I needed to store two patterns. The one currently being displayed and the second pattern which was about to be displayed. These are in arrays nLedsA[] and nLedsB. (note nothing to do with ports in this case). This is the double buffer.

The update_display() function was modified to cycle through eight frames and show a number of frames from first one array, then the other. Changing the number of frames allocated to each buffer throughout the eight cycles defined how bright each pattern would be. When we finished cycling between buffers we switched the 'display' and 'next display' buffers around, so the pattern generating function would then write only to the 'next display' buffer.

The diagram below shows this hopefully. You should be able to see that the transition will take 64 scan frames. In the picture, the little inset shows the scan fram diagram from the previous page artfully scaled down.

A word on re-fresh rate. All this needs to be done very quickly. We have now two levels of extra computation, one for the ambient display dimmness and one for the eight frame cycles spent doing a transition between two buffers. Thus this code was should be written in assembly, but is good enough in 'C'.

Step 4: Construction - the PCB

This is pretty straightforward. Just a double sided PCB with some SMD components on the top. Sorry if you're a through hole person, but it's a lot easier to make SMD projects....less holes to drill. You should have a steady hand, a temperature controlled soldering station and plenty of light and magnification to make things easier.

The only thing of note in the construction of the PCB is the inclusion of a connector for programming the PIC. This connects to the ICSP pins on the PIC and you'll need an ICSP programmer. Again I used a handy to my junkbox connector. You can omit this and just solder wires to the pads if you like.

Alternatively if you only have a socketed programmer, you can make a header that plugs into your socket and then solder that to the ICSP pads. If you do this, then disconnect Rx and connect Ry which are just zero ohm links (I just use a solder blob). This will disconnect the rest of the circuit power from the PIC so it doesn't interfere with the programming. A socketed programmer just uses the ICSP pins like a ICSP programmer, there is no magic involved really.

You also need to do this if by mistake you've forgotten to put a delay in the code before the RTC starts up. For the 16F88 the ICSP programming pins are the same as the pins needed for the 32.768kHz crystal used for the RTC......if the T1 external oscillator (ie the RTC) is running before the ICSP can start it's work, then the programming will fail. Normally if there is a reset on the MCLR pin and there is a delay, then ICSP data can be sent to these pins and programming can start properly.

However by isolating the power to the PIC the ICSP programmer (or socketed programmer with a header) can control power to the device and force a program.

The other things to note are that the crystal pads on the PCB were originally designed for SMD crystals. I couldn't wait for some to be delivered so the 32.768kHz watch crystal was soldered to the top as shown, and the 20MHz crystal was attached by drilling a couple of holesin the pads, poking the crystal in through the bottom and soldering onto the top. You can see the pins just to the right of the PIC16F88.

Step 5: The Holographic Film and Housing

The final construction is simply putting the PCB into the case and after programming affixing it with a dob of hot glue. Three holes allow access to the microswitches from the front.

The notable part of this clock is the use of a holographic diffuser film. This is special film I had lying around that provides a nice depth to the device. You could use plain tracing paper (in which I'd move the PCB closer to the front), or any other diffuser like those used in flourescent light fixtures. Experiement about, the only thing it needs to do is allow you to differentiate between the number of illuminated LEDs, or else counting the dots to tell the time will be difficult. I used holographic dispersion material from the Physical Optics Coorporation (www.poc.com) with a 30 degree circular dispersion, the supercomputer status display shown elsewhere in the instructable used a film with a 15x60degree elliptical dispersion.

You could use some blackout tape to hide the shiny innards during the daytime to get a more mysterious look. You could even leave the display clear and let people see the innards as I did.

The stand was two bits of aluminium 'L' bar with a bit chopped out at the bottom to allow a bend.

Note in these pictures extra lighting was added so you can see the display covers etc. In normal living room lighting, the LEDs are more prominant, even in daylight.

Step 6: Software and User Interface

The operation of the device is very simple, no special pattern modes or flashy stuff. The only thing it does is display the time.

To set the time first press SW1.
The device will flash all LEDs a few times and then the 10s hours group of LEDs
SW3 will increment the selected group
SW2 will move to the next group of LEDs, each time flashing all LEDs in the group briefly.

The code is written for Sourceboost 'C' compiler version 6.70.

The RTC code is in the t1rtc.c/h files, and has an interrupt function on the T1 timer of the PIC. The T1 timer is set to interrupt every 1 second. On each second, the variable for the time are incremented.
Also a tick timer is counted down every second along with the time. This is used to determine when to transition the display.
The interrupt function also uses the T0 timer interrupt to refresh the display, calling a function in display.c


The files display.h/display.c contain the functions to update the display and show the time

The files control.c/h contain the functions to set the time and read the switches

The files holoclock.c/h are the main loops and initialisation.