Here you go, guys.

I converted my Peter Jensen IN-14 clock (tubeclock.com) from a PIC to an Electric Imp.

The clock (scroll down): http://store.tubeclock.com/index.php/nixie-tube-clocks/clocks

The Imp: http://electricimp.com/

I built a small daughtercard that plugs into the PIC socket and itself has a socket for an April, which is the minimum breakout board for the Imp. It's really just a power supply and the socket for the imp.

April: http://www.adafruit.com/products/1130


The schematic of the daughtercard is extraordinary simple:

April Pin              PIC PIN
1 -------- Button 1 --- 4
2 -------- Button 2 --- 12
5 -------- SCLK ------- 8
7 -------- DATA ------- 6
8 -------- LATCH ------ 7
9 -------- BLANK ------ 5
Vin ------ 12V -------------------- To fuse
GND ------ GND -------- 14

The Imp has pretty high instantaneous current requirements. The average power consumption is quite low, but the worst-case WiFi transmit event can require 400mA. The tubeclock 5V supply is just a 5.1V Zener with a 1k resistor, so it's not up to the task. Fortunately the April power supply can take up to 17V input, so I just ran a wire to the load side of the fuse. I added a 100uF cap across the 12V input to help soak up those transients.

The SD form factor Imp gives you six pins to play with, and they can be configured in many ways. It's easy to add an i2c I/O expander if you need one, but we don't in this case.

Pins 1 and 2 are configured as digital inputs connected to the buttons. I'm not using them for anything yet, right now they just log events to the server.

Pins 5 and 7 are configured as SPI, and are used to write to the HV5622 shift registers. Pin 8 is a simple digital out connected to the Latch Enable on the HV5622s. This gives you direct control of the display. The code below has a function that takes a 6-digit string and two booleans for the colon bulbs, and creates the bitmapped blob to send to the HV5622s.

Pin 9 is configured as a PWM output, and is connected to the blanking input on the HV5622s. This gives a brightness control.

That's all there is to the hardware.

I've included the code for a very simple clock, it's just pulling time from the built-in RTC (which is synched at connect), has a hardcoded timezone offset, and crossfades the digits.

My next step is to use the Imp agent to create a web control panel for timezones, and update the clock more frequently (it drifts by a couple of seconds a day, but corrects if you reboot it)

Here's the device code so far:

// Button Class from github.com/electricimp
// ----------------------------------------------------------------------------
// Name: Button
// Purpose: Show the right way to debounce a button press
// ----------------------------------------------------------------------------

class button{
    static NORMALLY_HIGH = 1;
    static NORMALLY_LOW = 0;
    _pin = null;
    _pull = null;
    _polarity = null;
    _pressCallback = null;
    _releaseCallback = null;

    constructor(pin, pull, polarity, pressCallback, releaseCallback){
        _pin = pin; //Unconfigured IO pin, eg hardware.pin2
_pull = pull; //DIGITAL_IN_PULLDOWN, DIGITAL_IN or DIGITAL_IN_PULLUP _polarity = polarity; //Normal button state, ie 1 if button is pulled up and the button shorts to GND _pressCallback = pressCallback; //Function to call on a button press (may be null) _releaseCallback = releaseCallback; //Function to call on a button release (may be null)

        _pin.configure(_pull, debounce.bindenv(this));
    }

    function debounce(){
        _pin.configure(_pull);
imp.wakeup(0.020, getState.bindenv(this)); //Based on googling, bounce times are usually limited to 10ms
    }

    function getState(){
        if( _polarity == _pin.read() ){
            if(_releaseCallback != null){
                _releaseCallback();
            }
        }else{
            if(_pressCallback != null){
                _pressCallback();
            }
        }
        _pin.configure(_pull, debounce.bindenv(this));
    }
}

//Example Instantiation
minuteButton <- button(hardware.pin1, DIGITAL_IN, button.NORMALLY_HIGH,
            function(){server.log("Minutes Button Pressed")},
            function(){server.log("Minutes Button Released")}
            );
hourButton <- button(hardware.pin2, DIGITAL_IN, button.NORMALLY_HIGH,
            function(){server.log("Hours Button Pressed")},
            function(){server.log("Hours Button Released")}
            );


/* Hardware Configuration
This code is designed to support a tubeclock.com IN-14 clock.
There are two SuperTex HV5622 driver chips, nominally SPI with
latch (!LE) and blanking (!BL) lines. There is a polarity line,
tied high on the tubeclock.com board.
There are also two buttons on the board, currently NC because
they are connected to the 5V supply on the clock.
*/

// SPI to the HV drivers
display <- hardware.spi257;
display.configure(SIMPLEX_TX | MSB_FIRST | CLOCK_2ND_EDGE , 5000);
displaywriter <- display.write.bindenv(display);

// Latch Enable
latch <- hardware.pin8;
latch.configure(DIGITAL_OUT);
latchwriter <- latch.write.bindenv(latch);
latchwriter(1);

// Display Blanking (PWM for brightness control)
blank <- hardware.pin9;
blank.configure(PWM_OUT,(1.0/120.0),0.9);

function displayBuffer (buffer) {
    latchwriter(0);
    displaywriter(buffer);
    latchwriter(1);
}

function renderBuffer(string, colon_left, colon_right) {
    local offbits = [0,2,5,0,3,5];
    local offbytes = [0,1,2,4,5,6]
    local buffer = blob(8);
    for (local index=0;index<6;index++) {
        local digit = string.slice(index,index+1).tointeger();
        local byte0 = (0x80>>(digit+(offbits[index])));
        local byte1 = (0x80>>((digit-8)+(offbits[index])));
        buffer[(offbytes[index])] = buffer[(offbytes[index])] | byte0;
        buffer[(offbytes[index])+1] = buffer[(offbytes[index])+1] | byte1;
    }
    if (colon_left)
        buffer[2] = buffer[2] | 0x08;
    if (colon_right)
        buffer[5] = buffer[5] | 0x20;
    return buffer;
}

imp.configure("Nixie Clock", [], []);
server.log(format("impeeID %s", hardware.getimpeeid()));
server.log(format("Voltage %f", hardware.voltage()));
server.log(format("MAC address %s", imp.getmacaddress()));
server.log(format("WiFi %d dBm", imp.rssi()));
server.log(format("Software Version %s", imp.getsoftwareversion()));

function crossfade (old_buffer, new_buffer, steps) {
    for (local i=0;i<steps;i++) {
        displayBuffer(old_buffer);
        imp.sleep((steps - i)*0.0001);
        displayBuffer(new_buffer);
        imp.sleep(i * 0.0001);
    }
}

function nixieClock() {
    local tzoffset = (-8*3600);
    local t;
    local prev_t=time();
    while ((t = time()) == prev_t);         // Synchronize seconds
    local prev_d = date(((prev_t) + tzoffset),'u');
local prev_d_buffer = renderBuffer(format("%02d%02d%02d", prev_d.hour, prev_d.min, prev_d.sec) , true, true);
    local d = date((t + tzoffset),'u');
local d_buffer = renderBuffer(format("%02d%02d%02d", d.hour, d.min, d.sec) , true, true);
    crossfade(prev_d_buffer,d_buffer,50);
// displayBuffer( renderBuffer(format("%02d%02d%02d", d.hour, d.min, d.sec) , true, true));
    imp.wakeup(0.70, nixieClock);
}

nixieClock();






--
You received this message because you are subscribed to the Google Groups 
"neonixie-l" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send an email to [email protected].
To view this discussion on the web, visit 
https://groups.google.com/d/msgid/neonixie-l/5277EE2A.1070509%40milewski.org.
For more options, visit https://groups.google.com/groups/opt_out.

Reply via email to