Projecten

Projecten

Nixie Tube Clock

De Nixie Tube Klok is een digitale klok met als display een Nixie Tube. De werking van deze klok kan onderverdeeld worden in twee grote blokken, namelijk de hardware en de software.

Nixie Tube Klok
Nixie Tube Klok

Hardware

Hier wordt stap voor stap de opbouw van de hardware beschreven. Het verhaal begint toen ik in mijn verzameling van oude onderdelen een Nixie Tube vond en eens wou testen of ik deze een cijfer kon laten tonen.

Voeding

Een Nixie Tube heeft een hoge spanning nodig. De eerste stap is dus om een voldoende hoge spanning te genereren. Door gebruik te maken van onderstaand schema, wordt een voldoende hoge gelijkspanning aangemaakt en is het mogelijk om bv. het cijfer 8 te laten oplichten.

Voeding
Voeding

Wanneer alles is aangesloten, kan inderdaad een digit van van de Nixie Tube getoond worden.

Digits schakelen

Best wel tof om het cijfer 8 op te laten lichten. Maar echt plezant zou zijn als we de digits kunnen aansturen door een PIC®-microcontroller.  Een microcontroller kan echter geen hoge spanningen schakelen. Omdat ik nog een aantal mosfets had liggen heb ik deze gebruikt als elektronische schakelaar waarmee dan later de microcontroller de digits kan schakelen.

Schema met Mosfet
Schema met Mosfet

Dit alles is verder opgebouwd op de gaatjes print. Door nu de ingang van een bepaalde MOSFET hoog te maken, zal de desbetreffende digit getoond worden.

Nixie MosFET
Nixie + MosFET

Afgewerkte klok

Hieronder zie je het afgewerkte schema van de Nixie Klok. Klik op de afbeelding om het schema als PDF te downloaden.

Schema Nixie Klok
Schema Nixie Klok

Zoals je ziet is er een PIC 16F648A microcontroller aan toegevoegd. Ook is er nu een knop aanwezig waarmee de tijd in te stellen is. Via ingang RA4 loopt de klok gesynchroniseerd met de 50HZ netfrequentie.

Onderstaande youtube-video toont de Nixie Klok in actie.

 

Software

Zonder software zal de Nixie klok niet veel doen. Hieronder vind je de broncode van de Nixie klok die voldoende van commentaar is voorzien om de werking te kunnen snappen.

Enkel bijzondere kenmerken:

  • interne clock wordt gebruikt, met een duizelwekkende snelheid van 48Khz 😉
  • het meeste tijd wordt door de microcontroller besteed aan het wachten op een nul-doorgang van de 50HZ netfrequentie. Via die nuldoorgang wordt de klok gesynchroniseerd met de netfrequentie, waardoor de klok juist blijft lopen.
; ------------------------------------------------------------------------------
;
;                               Single Nixie Clock                        v0.0.4
;
; ------------------------------------------------------------------------------
;
; Written by :
;
;               Jan Wagemakers   : Donated to the Public Domain
;
; ------------------------------------------------------------------------------
        LIST     p=PIC16F648A
        INCLUDE "p16f648a.inc"
        errorlevel -302
        ;
        __CONFIG _CP_OFF&_DATA_CP_OFF&_LVP_OFF&_BODEN_OFF&_MCLRE_OFF&_PWRTE_ON&_WDT_OFF&_INTOSC_OSC_NOCLKOUT 
; ------------------------------------------------------------------------------
; Define variables
; ------------------------------------------------------------------------------
        cblock h'20'                                            
                menu                    ; 0   = display clock
                                        ; 1   = menu H(high)
                                        ; 2   = menu H(low)
                                        ; 3   = menu M(high)
                                        ; 4   = menu M(low)
                submenu                 ; 0   = menu
                                        ; 1   = submenu
                HZ50counter             ; Count the 50HZ pulse
                tick                    ; 1/2sec tick synchronized with 50HZ
                buttonr                 ; count how long button is released
                buttonp                 ; count how log button is pressed
                number                  ; number to display on Nixie
                DL                      ; used in number to digit conversion    
                DH                      ; used in number to digit conversion
                S                       ; Seconds in Binary (only used internal)
                H                       ; Hours in BCD
                M                       ; Minutes in BCD
                Hstep1                  ; Hours in BCD at the moment DisplayCounter = 1
                Mstep1                  ; Minutes in BCD at the moment DisplayCounter = 1
                Delay                   ; used in sleep routine
                DisplayCounter          ; Display what part of the clock?
        endc
; ------------------------------------------------------------------------------
; Let's start
; ------------------------------------------------------------------------------
        org h'0000'                                            
; ------------------------------------------------------------------------------
; Init PIC input output
; ------------------------------------------------------------------------------
        bcf STATUS, RP1
        bsf STATUS, RP0                 ; select bank 1
        bcf PCON, OSCF                  ; CLK=48Khz
        movlw b'11111000'               ; 1 = input 0 = output
        movwf TRISA                     ; set input/output PORTA      
        clrf TRISB                      ; PORTB = output
        bcf STATUS, RP0                 ; select bank 0
        movlw h'07'                     ; turn comparators off
        movwf CMCON
; ------------------------------------------------------------------------------
; Reset some variables
; ------------------------------------------------------------------------------
        clrf H
        clrf M
        clrf S
        clrf tick
        clrf menu
        clrf submenu
        clrf buttonp
        clrf buttonr
        clrf DisplayCounter
; ------------------------------------------------------------------------------
; Loop : everything is done is this loop  
; ------------------------------------------------------------------------------
Loop:
; ------------------------------------------------------------------------------
; Start clock menu routine
; ------------------------------------------------------------------------------
        btfsc PORTA, D'3'               ; IF RA3 <> 0 THEN ...
        goto  released                  ; ... button is not pressed ELSE ...
pressed:                                ; ... button is pressed
        incf buttonp, F
        movlw D'2'                      ; check how long key is pressed
        subwf buttonp, w
        btfss STATUS, Z
        goto chkkey_done                ; not long enough, go away
        ; ----------------------------------------------------------------------
        ; button is pressed long enough
        ; ----------------------------------------------------------------------
        clrf buttonp                    ; reset counter
        ;
        movf submenu, w                 ; menu or submenu?
        btfss STATUS, Z
        goto psubmenu              
        ; ----------------------------------------------------------------------
        ; button pressed : menu routine (:menu)
        ; ----------------------------------------------------------------------
        incf menu, F
        movlw D'5'
        subwf menu, w
        btfsc STATUS, Z
        clrf menu                       ; if menu = 5 then menu = 0
        ;
        movf menu, W
        movwf number
        call number_to_digit            ; display menu number
        bsf PORTA, D'2'                 ; display menu number with :
        ;
        goto chkkey_done                ; go away
        ; ----------------------------------------------------------------------
        ; button pressed : submenu routine
        ; ----------------------------------------------------------------------
psubmenu:
        ; ----------------------------------------------------------------------
        ; IF menu=1 THEN H = H + 0x10
        ; ----------------------------------------------------------------------
        movlw D'1'
        subwf menu, w
        btfss STATUS, Z
        goto XH
        movlw H'10'
        addwf H, F
        ; ----------------------------------------------------------------------
        ; IF menu=2 THEN H++
XH:     ; ----------------------------------------------------------------------
        movlw D'2'
        subwf menu, w
        btfsc STATUS, Z
        incf H, F
        ; ----------------------------------------------------------------------
        ; IF menu=3 THEN M = M + 0x10
        ; ----------------------------------------------------------------------
        movlw D'3'
        subwf menu, w
        btfss STATUS, Z
        goto XM
        movlw H'10'
        addwf M, F
        ; ----------------------------------------------------------------------
        ; IF menu=4 THEN M++
XM:     ; ----------------------------------------------------------------------
        movlw D'4'
        subwf menu, w
        btfsc STATUS, Z
        incf M, F
        ; ----------------------------------------------------------------------
        ; Check for overflow of digits
        ; ----------------------------------------------------------------------
        movlw B'11110000'
        btfsc M, D'3'
        btfss M, D'1'
        goto check1 
        andwf M, f                      ; IF M(low) = 10 then M(low) = 0
check1:
        movlw B'00001111'
        btfsc M, D'6'
        btfss M, D'5'
        goto check2
        andwf M, f                      ; IF M(high) = 10 then M(high) = 0
check2:
        movlw B'11110000'
        btfsc H, D'3'
        btfss H, D'1'
        goto check3
        andwf H, f                      ; IF H(low) = 10 then H(low) = 0
check3:
        movlw B'00001111'
        btfsc H, D'5'
        btfss H, D'4'
        goto check4
        andwf H, f                      ; IF H(high) = 3 then H(high) = 0                    
check4:
        btfss H, D'5'                   ; IF H(high) = 2 AND ...
        goto check5
        movlw B'00001111'
        andwf H, w                      ; w = H(low)
        sublw D'3'                      ; ... H(low) > 3 then ...
        btfss STATUS, C                
        clrf H                          ; .... reset H because for ex. ...
                                        ; .... 25:00 is false
check5:
        ; ----------------------------------------------------------------------
        ; Display the right digit on the Nixie
        ; ----------------------------------------------------------------------
disp_digit:
        ; -----------------------------------------------------------------------
        ; IF menu = 1 THEN display H(high)
        ; -----------------------------------------------------------------------
        movlw B'11110000'
        andwf H, w
        movwf number  
        swapf number, F                                 ; number = H(high)
        movlw D'1'
        subwf menu, w
        btfsc STATUS, Z
        call number_to_digit
        ; -----------------------------------------------------------------------
        ; IF menu = 2 THEN display H(low)
        ; -----------------------------------------------------------------------
        movlw B'00001111'
        andwf H, w
        movwf number                                    ; number = H(low)
        movlw D'2'
        subwf menu, w
        btfsc STATUS, Z
        call number_to_digit
        ; -----------------------------------------------------------------------
        ; IF menu = 3 THEN display M(high)
        ; -----------------------------------------------------------------------
        movlw B'11110000'
        andwf M, w
        movwf number
        swapf number, F                                 ; number = M(high)
        movlw D'3'
        subwf menu, w
        btfsc STATUS, Z
        call number_to_digit
        ; -----------------------------------------------------------------------
        ; IF menu = 41 THEN display M(low)
        ; -----------------------------------------------------------------------
        movlw B'00001111'
        andwf M, w
        movwf number                                    ; number = M(low)
        movlw D'4'
        subwf menu, w
        btfsc STATUS, Z
        call number_to_digit
        ;      
        goto chkkey_done                ; and done.
        ; ----------------------------------------------------------------------
        ; END button pressed
        ; ----------------------------------------------------------------------
released:
        incf buttonr, F
        movlw D'2'
        subwf buttonr, w
        btfss STATUS, Z
        goto chkkey_done
        ; ----------------------------------------------------------------------
        ; button is released long enough
        ; ----------------------------------------------------------------------
        clrf buttonr                    ; reset counter
        ;
        movf menu, W
        btfsc STATUS, Z
        goto clock                      ; if menu = 0 then display normal clock
        ;
        movf submenu, w                 ; menu or submenu
        btfss STATUS, Z
        goto rsubmenu
        ; ----------------------------------------------------------------------
        ; button released : menu routine (:menu --> digit)
        ; ----------------------------------------------------------------------
rmenu:
        bsf submenu, D'1'               ; enter submenu
        goto disp_digit                 ; Mmmm, spaghetti code ;-)
        ; ----------------------------------------------------------------------
        ; button released : submenu routine
        ; ----------------------------------------------------------------------
rsubmenu:
        clrf menu
        clrf submenu
        clrf DisplayCounter             ; exit menu/submenu
        ; ----------------------------------------------------------------------
        ; Let's end the button/menu/submenu routine
        ; ----------------------------------------------------------------------
chkkey_done:
        movf menu, W
        btfsc STATUS, Z
        goto clock                      ; if menu = 0 then display normal clock
        goto HZ50
; ------------------------------------------------------------------------------
; Start normal clock routine
; ------------------------------------------------------------------------------
clock:
        incf DisplayCounter, F
        ; ----------------------------------------------------------------------
        ; IF DisplayCounter = 1 THEN
        ;       Display Nothing AND
        ;       Hstep1 = H Mstep1 = M
        ; ----------------------------------------------------------------------
        movlw d'1'
        subwf DisplayCounter, w
        btfsc STATUS, Z
        call cls_and_saveHM
        ; ----------------------------------------------------------------------
        ; IF DisplayCounter = 2 THEN
        ;       Display Hstep1(high)
        ; ----------------------------------------------------------------------
        movlw B'11110000'
        andwf Hstep1, w
        movwf number    
        swapf number, F                                 ; number = Hstep1(high)
        movlw d'2'
        subwf DisplayCounter, w
        btfsc STATUS, Z
        call number_to_digit
        ; ----------------------------------------------------------------------
        ; IF DisplayCounter = 3 THEN
        ;       Display Nothing
        ; ----------------------------------------------------------------------
        movlw d'3'
        subwf DisplayCounter, w
        btfsc STATUS, Z
        call cls        
        ; ----------------------------------------------------------------------
        ; IF DisplayCounter = 4 THEN
        ;       Display Hstep1(low)
        ; ----------------------------------------------------------------------
        movlw B'00001111'
        andwf Hstep1, w
        movwf number                                    ; number = Hstep1(low)
        movlw d'4'
        subwf DisplayCounter, w
        btfsc STATUS, Z
        call number_to_digit
        ; ----------------------------------------------------------------------
        ; IF DisplayCounter = 5 THEN
        ;       Display Nothing
        ; ----------------------------------------------------------------------
        movlw d'5'
        subwf DisplayCounter, w
        btfsc STATUS, Z
        call cls
        ; ----------------------------------------------------------------------
        ; IF DisplayCounter = 6 THEN
        ;       Display :
        ; ----------------------------------------------------------------------
        movlw d'6'
        subwf DisplayCounter, w
        btfsc STATUS, Z
        bsf PORTA, D'2'                                 ; display :
        ; ----------------------------------------------------------------------
        ; IF DisplayCounter = 7 THEN
        ;       Display Nothing
        ; ----------------------------------------------------------------------
        movlw d'7'
        subwf DisplayCounter, w
        btfsc STATUS, Z
        call cls
        ; ----------------------------------------------------------------------
        ; IF DisplayCounter = 8 THEN
        ;       Display Mstep1(high)
        ; ----------------------------------------------------------------------
        movlw B'11110000'
        andwf Mstep1, w
        movwf number                                    
        swapf number, F                                 ; number = Mstep1(high)
        movlw d'8'
        subwf DisplayCounter, w
        btfsc STATUS, Z
        call number_to_digit
        ; ----------------------------------------------------------------------
        ; IF DisplayCounter = 9 THEN
        ;       Display Nothing
        ; ----------------------------------------------------------------------
        movlw d'9'
        subwf DisplayCounter, w
        btfsc STATUS, Z
        call cls
        ; ----------------------------------------------------------------------
        ; IF DisplayCounter = 10 THEN
        ;       Display Mstep1(low)
        ; ----------------------------------------------------------------------
        movlw B'00001111'
        andwf Mstep1, w
        movwf number                                    ; number = Mstep1(low)
        movlw d'10'
        subwf DisplayCounter, w
        btfsc STATUS, Z
        call number_to_digit
        ; ----------------------------------------------------------------------
        ; IF DisplayCounter = 11 THEN
        ;       Display Nothing  AND
        ;       DisplayCounter = 0
        ; ----------------------------------------------------------------------
        movlw d'11'
        subwf DisplayCounter, w
        btfsc STATUS, Z
        call cls_and_crlf_DisplayCounter        
; ------------------------------------------------------------------------------
; Synchronize with 50HZ __+--+__+--+__
; ------------------------------------------------------------------------------
HZ50:
        clrf HZ50counter
HZ50islow:
        call zzz                        ; sleep a while
        btfss PORTA, d'4'      
        goto HZ50islow
HZ50ishigh:
        call zzz                        ; sleep a while
        btfsc PORTA, d'4'
        goto HZ50ishigh
        ;
        incf HZ50counter, F             ; Do every 1/50 sec. : 50HZcounter++
        movlw d'25'
        subwf HZ50counter, w            ; 25 * 1/50 seconds -> 1/2 second
        btfss STATUS, Z
        goto HZ50islow
        ;
        incf tick, F                    ; Do every 1/2 second : tick = tick + 1
        movlw d'2'
        subwf tick, w
        btfss STATUS, Z
        goto Loop                       ; IF tick = 2 then tick = 0 and ...
        clrf tick                       ; else just go to loop
; ------------------------------------------------------------------------------
; INC clock sec, min, hour
; ------------------------------------------------------------------------------
        incf S, F                       ; Do every second : S = S + 1
        movlw d'60'
        subwf S, w
        btfss STATUS, Z 
        goto Loop
        clrf S                          ; IF S = 60 THEN S = 0 and ...
        ; ----------------------------------------------------------------------
        ; OK, it's time to update the clock by 1 minute
        ; ----------------------------------------------------------------------
        incf M, f                       ; M = M + 1
        movlw D'6'
        btfsc M, D'3'
        btfss M, D'1'
        goto Mok                        ; IF M(low) = 10 THEN
        addwf M, f                      ;    M(low) = 0  AND M(high)++
Mok:
        movlw H'60'
        subwf M, w
        btfss STATUS, Z
        goto Loop
        clrf M                          ; IF M(BCD)  = 60 THEN M = 0 and ...
        ; ----------------------------------------------------------------------
        ; OK, it's time to update the clock by 1 hour
        ; ----------------------------------------------------------------------
        incf H, F                       ; ... H = H + 1
        movlw D'6'
        btfsc H, D'3'
        btfss H, D'1'
        goto Hok                        ; IF H(low) = 10 THEN
        addwf H, f                      ;    H(low) = 0  AND H(high)++
Hok:
        movlw H'24'
        subwf H, w
        btfsc STATUS, Z        
        clrf H                          ; IF H(BCD) = 24 THEN H = 0
        goto Loop
; ------------------------------------------------------------------------------

; ------------------------------------------------------------------------------
; Subroutines
; ------------------------------------------------------------------------------
cls_and_crlf_DisplayCounter:
        clrf DisplayCounter
        goto cls
cls_and_saveHM:
        movf H, w
        movwf Hstep1
        movf M, w
        movwf Mstep1
cls:
        clrf PORTB                      ; Display nothing
        clrf PORTA
        return
        ;
number_to_digit:
        movf number, w
        BTFSC STATUS, Z                 ; if number = 0 then number = 10
        movlw D'10'
        movwf number
        movlw b'00000001'
        movwf DL
        clrf  DH                        ; DH:DL = 0000000000000001
dountilzero:
        decfsz number, F
        goto isnotzero
        movf DL, w
        movwf PORTB
        movf DH, w
        movwf PORTA
        return
isnotzero:
        BCF STATUS, C
        rlf DL, F
        rlf DH, F
        goto dountilzero
        ;
zzz:                                    ; zzz zzz zzz zzz (sleep)
        movlw D'4'
        movwf Delay
zloop:
        decfsz Delay, F
        goto zloop
        return
        ;
; ----------------------------------------------------------------------------
        end
; ----------------------------------------------------------------------------