A PIC16F84A single-digit nixie clock with DCF-77 atomic clock support and a high voltage power supply built with only 4 components.
Overview
This project features a PIC16F84A driving a single-digit nixie tube as a clock. It supports DCF-77 atomic clock synchronization for automatic time setting. The high voltage power supply uses only 4 components. 24-hour programmable extinction saves tube life. No MikroC licence is needed as the firmware fits within the demo limit.
Powering the Nixie
Nixie tubes require approximately 170V at about 1.5mA. A DC/DC converter generates this from the +5V supply using software PWM driving a MOSFET. The components are: an IRF830 MOSFET, a 330uH coil, a fast recovery diode, and a 2.2uF 250V capacitor.
WARNING: High Voltage
The DC/DC converter produces dangerous voltage (170V). Exercise extreme caution when building and testing this circuit.
Driving the Nixie
The nixie tube is driven through a 74141 BCD-to-decimal decoder, which contains high-voltage open-collector transistors suitable for nixie driving. The IN-14 Russian nixie tube fits on a standard 14-pin DIP socket.
Circuit Schematic
R3 and D2 protect the PIC input from the high voltage feedback.
Operation
Mode selection at power-up: 0 = positive logic DCF, 1 = negative logic DCF, 2 = manual time setting. The single digit sequentially displays hours, minutes, and seconds with pauses between each pair of digits.
C Source Code
/* * DCF-77 SINGLE NIXIE CLOCK * January, 2006 * * PIC16F84A * 16 Mhz crystal, HS clock * * PORTA.0, in : DCF pulse input * PORTA.1, out : LED pulse repeater * PORTA.2, out : LED pulse synch * PORTA.3, in : SWITCH, pull-down * * PORTB.0->3, out : BCD to 74141 decoder * PORTB.4->5, undef : not connected * PORTB.6, in : voltage control * PORTB.7, out : 40 KHz pulse for nixie HV power supply * ******************************************************************************* */ #define BLANK 0x0f // BCD code for nixie blanking #define MAXCOUNT 15625 // TMR0 overflows in 1 second #define ADJUST 0 #define timer_d_min 28000 // TMR0 overflows in ~2 seconds #define timer_h_0 1400 // TMR0 overflows in ~0.1 second #define timer_h_1 2800 // TMR0 overflows in ~0.2 second #define putNibble(b) PORTB = b unsigned int tmrh ; unsigned int tmrd ; unsigned char bitnum ; char last_bit ; unsigned char parity ; unsigned char full ; unsigned char locked ; unsigned char mode ; // 0:pos, 1:neg, 2:no DCF unsigned char mn ; unsigned char hh ; unsigned int scaler ; unsigned char ohh, omn, oss ; // RTC unsigned char dhh, dmn, dss ; // display values unsigned char pwm ; // PWM output enable unsigned char vmax, vcurr ; unsigned char curr ; void delay_25ms(unsigned char n) { while(n) { Delay_ms(25) ; n-- ; } } /* display a value 00-99 on nixie */ void mkDigit(unsigned char d) { putNibble(BLANK) ; delay_25ms(10) ; putNibble(d / 10) ; delay_25ms(16) ; putNibble(BLANK) ; delay_25ms(2) ; putNibble(d % 10) ; delay_25ms(12) ; } /* select a digit from 0 to vmax, flashing vcurr */ void selectDigit(void) { unsigned char i, j, k ; pwm = 1 ; i = 0 ; for(;;) { for(j = 0 ; j <= vmax ; j++) { for(k = 0 ; k < 10 ; k++) { putNibble(j) ; delay_25ms(1) ; putNibble(vcurr == j ? BLANK : j) ; delay_25ms(1) ; if(PORTA.F3) { putNibble(BLANK) ; delay_25ms(8) ; putNibble(j) ; pwm = 0 ; curr = j ; return ; } } } if(vcurr < 10) { i++ ; if(i == 3) { pwm = 0 ; curr = vcurr ; return ; } } } } /* * ISR */ void interrupt(void) { if(INTCON.T0IF) { PORTB.F7 = !PORTB.F7 & !PORTB.F6 & pwm ; if(PORTA.F0 ^ mode) { tmrh++ ; if(tmrd > timer_d_min) { bitnum = 0 ; if(full) { ohh = hh ; omn = mn ; oss = 3 ; scaler = 0 ; locked = 1 ; } mn = hh = 0 ; parity = 0 ; full = 0 ; PORTA.F2 = 1 ; } tmrd = 0 ; } else { tmrd++ ; if(tmrh > 0) { if(tmrh > timer_h_1) { last_bit = 1 ; switch(bitnum) { case 21: mn++ ; break ; case 22: mn += 2 ; break ; case 23: mn += 4 ; break ; case 24: mn += 8 ; break ; case 25: mn += 10 ; break ; case 26: mn += 20 ; break ; case 27: mn += 40 ; break ; case 29: hh++ ; break ; case 30: hh += 2 ; break ; case 31: hh += 4 ; break ; case 32: hh += 8 ; break ; case 33: hh += 10 ; break ; case 34: hh += 20 ; break ; } if((bitnum != 28) && (bitnum != 35) && (bitnum != 58)) { parity++ ; } bitnum++ ; } else if(tmrh > timer_h_0) { if(bitnum == 20) { last_bit = -1 ; bitnum = 0 ; PORTA.F2 = 0 ; } else { last_bit = 0 ; bitnum++ ; } } else { last_bit = -1 ; bitnum = 0 ; PORTA.F2 = 0 ; } if(bitnum == 21) { parity = 0 ; } if((bitnum == 29) || (bitnum == 36) || (bitnum == 59)) { if((parity & 1) != last_bit) { bitnum = 0 ; PORTA.F2 = 0 ; } parity = 0 ; } if(bitnum == 59) { full++ ; } } tmrh = 0 ; } /* RTC */ scaler++ ; if(scaler > MAXCOUNT) { scaler = 0 ; oss++ ; if(oss == 60) { oss = 0 ; omn++ ; if(omn == 60) { omn = 0 ; ohh++ ; if(ohh == 24) { ohh = 0 ; } } } } PORTA.F1 = PORTA.F0 ^ mode ; INTCON.T0IF = 0 ; } } /* * program entry */ main() { TRISA = 0b00001001 ; TRISB = 0b01000000 ; INTCON = 0b10100000 ; OPTION_REG = 0b11011000 ; locked = 0 ; vcurr = EEPROM_Read(0) ; // get last mode /* select mode 0-2 */ vmax = 2 ; selectDigit() ; mode = curr ; /* if mode 2 (no DCF), set time manually */ vcurr = 10 ; if(mode == 2) { vmax = 2 ; selectDigit() ; ohh = curr * 10 ; // hours tens vmax = 9 ; selectDigit() ; ohh += curr ; // hours units vmax = 5 ; selectDigit() ; omn = curr * 10 ; // minutes tens vmax = 9 ; selectDigit() ; omn += curr ; // minutes units oss = 3 ; locked = 1 ; } EEPROM_Write(0, mode) ; // store selected mode /* main loop */ for(;;) { if(locked > 0) { if(PORTA.F3) { /* edit sleep mode schedule */ for(dhh = 0 ; dhh < 24 ; dhh++) { pwm = 1 ; mkDigit(dhh) ; vcurr = EEPROM_Read(0x10 + dhh) ; vmax = 1 ; selectDigit() ; EEPROM_Write(0x10 + dhh, curr) ; } } else { /* display cycle */ PORTB = BLANK ; pwm = 1 ; delay_25ms(1) ; dss = oss ; dmn = omn ; dhh = ohh ; mkDigit(dhh) ; mkDigit(dmn) ; mkDigit(dss) ; pwm = 0 ; // nixie off if(EEPROM_Read(0x10 + dhh)) { delay_25ms(60) ; // short pause } else { if(mode == 2) { delay_25ms(255) ; } // long pause else { locked = 0 ; } // unlock for re-sync } } } } }
Download
Single-Tube Nixie Clock files
Pre-compiled HEX file ready to program into your PIC16F84A (16 MHz crystal):