February 2010 Archives

Sat Feb 27 14:52:28 CET 2010

Nixie clock webpage

I have written a webpage about my Nixie Clock in the English and Dutch language.

Nixie (c)(k)lok



Posted by Jan Wagemakers | Permanent link | File under: nixie, pic

Thu Feb 18 11:19:47 CET 2010

Update schematic and software of Nixie clock

I have updated the schematic (made with gEDA gschem) and software of my Nixie clock .


Posted by Jan Wagemakers | Permanent link | File under: nixie, pic

Sat Feb 13 17:23:47 CET 2010

Set time of Nixie clock

To set the time of my Nixie clock, I have added a button to my schematic and updated the software.

Yes, the schematic is ugly, ....


Click for larger picture


... the source code is ugly, ....

        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 


        cblock h'20'                                            
                menu                    ; 0   = display clock
                                        ; 1   = menu HH
                                        ; 2   = menu HL
                                        ; 3   = menu MH
                                        ; 4   = menu ML
                submenu
                HZ50counter
                button                  ; count how long button is pressed
                tmp
                DL      
                DH
                S
                H
                M
                ML
                MH
                HL
                HH
                tens_and_ones
                bin
                hundreds
                TENS
                ONES
                DisplayCounter
        endc

        org h'0000'                                             

init:
        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
main:
        movlw b'00000000'
        movwf PORTB
        movlw b'00000000'
        movwf PORTA
        clrf H
        clrf M
        clrf S
        clrf menu
        clrf submenu
        clrf button
        clrf DisplayCounter
        incf DisplayCounter, F
Loop:
        btfsc PORTA, D'3'
        goto released
        incf button, F

        movlw D'2'
        subwf button, w
        btfss STATUS, Z
        goto cont1      
pressed:                                ; pressed for longer then 1Sec

        clrf button                     ; reset counter

        movf submenu, w
        btfsc STATUS, Z
        goto INCmenu                    ; if pressed and no submenu then INC menu

        movlw D'1'
        subwf menu, w
        btfss STATUS, Z
        goto XH
        movlw D'10'
        addwf H, F
XH:
        movlw D'2'
        subwf menu, w
        btfsc STATUS, Z
        incf H, F

        movlw D'3'
        subwf menu, w
        btfss STATUS, Z
        goto XM
        movlw D'10'
        addwf M, F
XM:
        movlw D'4'
        subwf menu, w
        btfsc STATUS, Z
        incf M, F
        

        ; Convert Hour:Minutes to HH,HL:MH,ML
        ; ----------------------------------------------------
        movf M, w
        call Convert
        movf TENS, w
        movwf MH                        ; Minutes High Digit
        movf ONES, w
        movwf ML                        ; Minutes Low Digit
        movf H, w
        call Convert
        movf TENS, w
        movwf HH                        ; Hour High Digit
        movf ONES, w
        movwf HL                        ; Hour Low Digit
        ; ---------------------------------------------------
        goto cont1
INCmenu:
        incf menu, F
        goto cont1

released:
        clrf button
        movf submenu, w
        btfsc STATUS, Z
        goto Enter_Submenu
        clrf menu
        clrf submenu
        goto cont1
Enter_Submenu:
        clrf submenu
        incf submenu, F
cont1:
        
        movlw D'5'
        subwf menu, w
        btfsc STATUS, Z
        clrf menu                       ; if menu = 5 then menu = 0
        
        movf menu, W
        btfsc STATUS, Z
        goto clock1                     ; if menu = 0 then display normal clock

        movf submenu, w
        btfsc STATUS, Z
        goto DISPmenu                   ; Display :menu

        movlw D'1'
        subwf menu, w
        btfss STATUS, Z
        goto x1
        movf HH, w
        call number_to_digit
x1:
        movlw D'2'
        subwf menu, w
        btfss STATUS, Z
        goto x2
        movf HL, w
        call number_to_digit
x2:
        movlw D'3'
        subwf menu, w
        btfss STATUS, Z
        goto x3
        movf MH, w
        call number_to_digit
x3:
        movlw D'4'
        subwf menu, w
        btfss STATUS, Z
        goto x4
        movf ML, w
        call number_to_digit
x4:
        goto DC1
DISPmenu:
        movf menu, W
        call number_to_digit
        bsf PORTA, D'2'
        goto DC1

clock1: 
        clrf submenu
        ; Display Nothing and update HH,HL:MH,ML
        movlw d'1'
        subwf DisplayCounter, w
        btfss STATUS, Z
        goto clock2
        movlw b'00000000'
        movwf PORTB
        movlw b'00000000'
        movwf PORTA
        ; Convert Hour:Minutes to HH,HL:MH,ML
        ; ----------------------------------------------------
        movf M, w
        call Convert
        movf TENS, w
        movwf MH                        ; Minutes High Digit
        movf ONES, w
        movwf ML                        ; Minutes Low Digit
        movf H, w
        call Convert
        movf TENS, w
        movwf HH                        ; Hour High Digit
        movf ONES, w
        movwf HL                        ; Hour Low Digit
        ; ---------------------------------------------------
clock2:  ; Display HH
        movlw d'2'
        subwf DisplayCounter, w
        btfss STATUS, Z
        goto clock3
        movf HH, w
        call number_to_digit
clock3:  ; Display Nothing
        movlw d'3'
        subwf DisplayCounter, w
        btfss STATUS, Z
        goto clock4
        movlw b'00000000'
        movwf PORTB
        movlw b'00000000'
        movwf PORTA
clock4:  ; Display HL
        movlw d'4'
        subwf DisplayCounter, w
        btfss STATUS, Z
        goto clock5
        movf HL, w
        call number_to_digit
clock5:  ; Display Nothing
        movlw d'5'
        subwf DisplayCounter, w
        btfss STATUS, Z
        goto clock6
        movlw b'00000000'
        movwf PORTB
        movlw b'00000000'
        movwf PORTA
clock6:  ; Display :
        movlw d'6'
        subwf DisplayCounter, w
        btfss STATUS, Z
        goto clock7
        movlw b'00000000'
        movwf PORTB
        movlw b'00000100'
        movwf PORTA
clock7:  ; Display Nothing
        movlw d'7'
        subwf DisplayCounter, w
        btfss STATUS, Z
        goto clock8
        movlw b'00000000'
        movwf PORTB
        movlw b'00000000'
        movwf PORTA
clock8:  ; Display MH
        movlw d'8'
        subwf DisplayCounter, w
        btfss STATUS, Z
        goto clock9
        movf MH, w
        call number_to_digit
clock9:  ; Display Nothing
        movlw d'9'
        subwf DisplayCounter, w
        btfss STATUS, Z
        goto clock10
        movlw b'00000000'
        movwf PORTB
        movlw b'00000000'
        movwf PORTA
clock10: ; Display ML
        movlw d'10'
        subwf DisplayCounter, w
        btfss STATUS, Z
        goto clock11
        movf ML, w
        call number_to_digit
clock11: ; Display Nothing, and reset DisplayCounter
        movlw d'11'
        subwf DisplayCounter, w
        btfss STATUS, Z
        goto DCup
        movlw b'00000000'
        movwf PORTB
        movlw b'00000000'
        movwf PORTA
DC1:
        clrf DisplayCounter
DCup:   
        incf DisplayCounter, F

        clrf HZ50counter
HZ50islow:
        btfss PORTA, d'4'       
        goto HZ50islow
HZ50ishigh:
        btfsc PORTA, d'4'
        goto HZ50ishigh

        incf HZ50counter, F             ; Do every 1/50 sec. : 50HZcounter++
        movlw d'50'
        subwf HZ50counter, w            ; 50 * 1/50 seconds -> 1 second
        btfss STATUS, Z
        goto HZ50islow
second:
        incf S, F                       ; Do every second : S = S + 1
        movlw d'60'
        subwf S, w
        btfsc STATUS, Z                 ; If S = 60 then goto minute
        goto minute
        goto M1
minute:
        clrf S                          ; S was 60, so we do M = M + 1 and S = 0
        
        ; OK, it's time to update the clock by 1 minute
        ; ---------------------------------------------
        incf M, F
        movlw d'60'
        subwf M, w
        btfss STATUS, Z
        goto M1
        movwf M

        incf H, F
        movlw d'24'
        subwf H, w
        btfss STATUS, Z
        goto M1
        movwf H
M1:
        goto Loop

; ----------------------------------------------------------------------------
; Subroutines
; ----------------------------------------------------------------------------

number_to_digit:
        movwf tmp
        BTFSC STATUS, Z                 ; if tmp = 0 then tmp = 10
        movlw D'10'
        movwf tmp
        movlw b'00000001'
        movwf DL
        clrf  DH                        ; DH:DL = 0000000000000001
dountilzero:
        decfsz tmp, 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

;----------------------------------------------------------------------;
;                  Change binary nbr in bin to BCD                     ;
;----------------------------------------------------------------------;
binary_to_bcd:                  ; by Scott Dattalo
        clrf hundreds
        swapf bin, W
        addwf bin, W
        andlw B'00001111'
        skpndc
        addlw 0x16
        skpndc
        addlw 0x06
        addlw 0x06
        skpdc
        addlw -0x06
        btfsc bin,4
        addlw 0x16 - 1 + 0x6
        skpdc
        addlw -0x06
        btfsc bin,5
        addlw 0x30
        btfsc bin, 6
        addlw 0x60
        btfsc bin,7
        addlw 0x20
        addlw 0x60
        rlf hundreds, f
        btfss hundreds, 0
        addlw -0x60
        movwf tens_and_ones
        btfsc bin,7
        incf hundreds, f
        return

;----------------------------------------------------------------------;
;                Display binary value in W in decimal                  ;
;----------------------------------------------------------------------;
Convert:
        movwf bin
        call binary_to_bcd
;       movf hundreds, W      ; I don't use numbers > 99
;       movwf ...
        swapf tens_and_ones, W
        andlw H'F'
        movwf TENS
        movf tens_and_ones, W
        andlw H'F'
        movwf ONES
        return


; ----------------------------------------------------------------------------
        end
; ----------------------------------------------------------------------------

.... there are bugs, for example it's possible to set the clock's time to 67:89, but it does work ;)

Posted by Jan Wagemakers | Permanent link | File under: nixie, pic

Sat Feb 6 20:28:50 CET 2010

Nixie clock with PIC16f648a

After driving a nixie tube with a PIC16f648a it's time to do something more usefull with it, for example a clock.

Because the PIC16f648a is running with it's internal oscillator, and the circuit is powered by 230V 50Hz, I decided to synchronize the clock with the 50Hz mains frequency (look at RA4 in the schematic drawing) which will be more accurate.


Click for larger picture


And I have updated the PIC program so it displays a clock and uses the RA4 input to synchronize the clock with with the 50Hz mains frequency.
        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 


        cblock h'20'                                            
                HZ50counter
                tmp
                DL      
                DH
                S
                H
                M
                ML
                MH
                HL
                HH
                tens_and_ones
                bin
                hundreds
                TENS
                ONES
                DisplayCounter
        endc

        org h'0000'                                             

init:
        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
main:
        movlw b'00000000'
        movwf PORTB
        movlw b'00000000'
        movwf PORTA
        clrf H
        clrf M
        clrf S
        clrf DisplayCounter
        incf DisplayCounter, F
Loop:
        ; Convert Hour:Minutes to HH,HL:MH,ML
        ; -----------------------------------
        movf M, w
        call Convert
        movf TENS, w
        movwf MH                        ; Minutes High Digit
        movf ONES, w
        movwf ML                        ; Minutes Low Digit
        movf H, w
        call Convert
        movf TENS, w
        movwf HH                        ; Hour High Digit
        movf ONES, w
        movwf HL                        ; Hour Low Digit

test1:  ; Display Nothing
        movlw d'1'
        subwf DisplayCounter, w
        btfss STATUS, Z
        goto test2
        movlw b'00000000'
        movwf PORTB
        movlw b'00000000'
        movwf PORTA
test2:  ; Display HH
        movlw d'2'
        subwf DisplayCounter, w
        btfss STATUS, Z
        goto test3
        movf HH, w
        call number_to_digit
test3:  ; Display Nothing
        movlw d'3'
        subwf DisplayCounter, w
        btfss STATUS, Z
        goto test4
        movlw b'00000000'
        movwf PORTB
        movlw b'00000000'
        movwf PORTA
test4:  ; Display HL
        movlw d'4'
        subwf DisplayCounter, w
        btfss STATUS, Z
        goto test5
        movf HL, w
        call number_to_digit
test5:  ; Display Nothing
        movlw d'5'
        subwf DisplayCounter, w
        btfss STATUS, Z
        goto test6
        movlw b'00000000'
        movwf PORTB
        movlw b'00000000'
        movwf PORTA
test6:  ; Display :
        movlw d'6'
        subwf DisplayCounter, w
        btfss STATUS, Z
        goto test7
        movlw b'00000000'
        movwf PORTB
        movlw b'00000100'
        movwf PORTA
test7:  ; Display Nothing
        movlw d'7'
        subwf DisplayCounter, w
        btfss STATUS, Z
        goto test8
        movlw b'00000000'
        movwf PORTB
        movlw b'00000000'
        movwf PORTA
test8:  ; Display MH
        movlw d'8'
        subwf DisplayCounter, w
        btfss STATUS, Z
        goto test9
        movf MH, w
        call number_to_digit
test9:  ; Display Nothing
        movlw d'9'
        subwf DisplayCounter, w
        btfss STATUS, Z
        goto test10
        movlw b'00000000'
        movwf PORTB
        movlw b'00000000'
        movwf PORTA
test10: ; Display ML
        movlw d'10'
        subwf DisplayCounter, w
        btfss STATUS, Z
        goto test11
        movf ML, w
        call number_to_digit
test11: ; Display Nothing and reset DisplayCounter
        movlw d'11'
        subwf DisplayCounter, w
        btfss STATUS, Z
        goto test12
        movlw b'00000000'
        movwf PORTB
        movlw b'00000000'
        movwf PORTA
        clrf DisplayCounter
test12: 
        incf DisplayCounter, F

        clrf HZ50counter
HZ50islow:
        btfss PORTA, d'4'       
        goto HZ50islow
HZ50ishigh:
        btfsc PORTA, d'4'
        goto HZ50ishigh

        incf HZ50counter, F             ; Do every 1/50 sec. : 50HZcounter++
        movlw d'50'
        subwf HZ50counter, w            ; 50 * 1/50 seconds -> 1 second
        btfss STATUS, Z
        goto HZ50islow
second:
        incf S, F                       ; Do every second : S = S + 1
        movlw d'60'
        subwf S, w
        btfsc STATUS, Z                 ; If S = 60 then goto minute
        goto minute
        goto M1
minute:
        clrf S                          ; S was 60, so we do M = M + 1 and S = 0
        
        ; OK, it's time to update the clock by 1 minute
        ; ---------------------------------------------
        incf M, F
        movlw d'60'
        subwf M, w
        btfss STATUS, Z
        goto M1
        movwf M

        incf H, F
        movlw d'24'
        subwf H, w
        btfss STATUS, Z
        goto M1
        movwf H
M1:
        goto Loop

; ----------------------------------------------------------------------------
; Subroutines
; ----------------------------------------------------------------------------

number_to_digit:
        movwf tmp
        BTFSC STATUS, Z                 ; if tmp = 0 then tmp = 10
        movlw D'10'
        movwf tmp
        movlw b'00000001'
        movwf DL
        clrf  DH                        ; DH:DL = 0000000000000001
dountilzero:
        decfsz tmp, 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

;----------------------------------------------------------------------;
;                  Change binary nbr in bin to BCD                     ;
;----------------------------------------------------------------------;
binary_to_bcd:                  ; by Scott Dattalo
        clrf hundreds
        swapf bin, W
        addwf bin, W
        andlw B'00001111'
        skpndc
        addlw 0x16
        skpndc
        addlw 0x06
        addlw 0x06
        skpdc
        addlw -0x06
        btfsc bin,4
        addlw 0x16 - 1 + 0x6
        skpdc
        addlw -0x06
        btfsc bin,5
        addlw 0x30
        btfsc bin, 6
        addlw 0x60
        btfsc bin,7
        addlw 0x20
        addlw 0x60
        rlf hundreds, f
        btfss hundreds, 0
        addlw -0x60
        movwf tens_and_ones
        btfsc bin,7
        incf hundreds, f
        return

;----------------------------------------------------------------------;
;                Display binary value in W in decimal                  ;
;----------------------------------------------------------------------;
Convert:
        movwf bin
        call binary_to_bcd
;       movf hundreds, W      ; I don't use numbers > 99
;       movwf ...
        swapf tens_and_ones, W
        andlw H'F'
        movwf TENS
        movf tens_and_ones, W
        andlw H'F'
        movwf ONES
        return


; ----------------------------------------------------------------------------
        end
; ----------------------------------------------------------------------------



Click on the photo above to see the Nixie clock in action Play Ogg
or
click here to see it on youtube
(warning: low quality movie)


ToDo:
  • Make a better looking schematic drawing
  • Add a switch or something to set the time of the clock, so I don't have to wait at 00:00 to power the circuit ;-)
  • Solder the floating electronic components on the circuit board

Posted by Jan Wagemakers | Permanent link | File under: nixie, pic

Mon Feb 1 22:54:13 CET 2010

Drive Nixie tube digits with a PIC16f648a

After making a power supply to drive a nixie tube and adding 11 BUZ80 SIPMOS Power Transistors it was time to add a PIC to the circuit.


Click for larger picture


To test if everything works as expected, I have written a little test program (asm) to display all the digits ( 1 2 3 4 5 6 7 8 9 0 : ) in a loop.
        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 


        cblock h'20'                                            
                delay1
                delay2
                delay3
        endc

        org h'0000'                                             

init:
        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
main:
        movlw b'00000001'
        movwf PORTB
        movlw b'00000000'
        movwf PORTA
        call Delay

        movlw b'00000010'
        movwf PORTB
        movlw b'00000000'
        movwf PORTA
        call Delay

        movlw b'00000100'
        movwf PORTB
        movlw b'00000000'
        movwf PORTA
        call Delay

        movlw b'00001000'
        movwf PORTB
        movlw b'00000000'
        movwf PORTA
        call Delay

        movlw b'00010000'
        movwf PORTB
        movlw b'00000000'
        movwf PORTA
        call Delay

        movlw b'00100000'
        movwf PORTB
        movlw b'00000000'
        movwf PORTA
        call Delay

        movlw b'01000000'
        movwf PORTB
        movlw b'00000000'
        movwf PORTA
        call Delay

        movlw b'10000000'
        movwf PORTB
        movlw b'00000000'
        movwf PORTA
        call Delay

        movlw b'00000000'
        movwf PORTB
        movlw b'00000001'
        movwf PORTA
        call Delay

        movlw b'00000000'
        movwf PORTB
        movlw b'00000010'
        movwf PORTA
        call Delay

        movlw b'00000000'
        movwf PORTB
        movlw b'00000100'
        movwf PORTA
        call Delay

        goto main

; ----------------------------------------------------------------------------
; Subroutines
; ----------------------------------------------------------------------------

; Delay = 1 seconds
; Clock frequency = 4 MHz

; Actual delay = 1 seconds = 1000000 cycles
; Error = 0 %

Delay
                        ;999990 cycles
        movlw   0x07
        movwf   delay1
        movlw   0x2F
        movwf   delay2
        movlw   0x03
        movwf   delay3
Delay_0
        decfsz  delay1, f
        goto    $+2
        decfsz  delay2, f
        goto    $+2
        decfsz  delay3, f
        goto    Delay_0

                        ;6 cycles
        goto    $+1
        goto    $+1
        goto    $+1

                        ;4 cycles (including call)
        return

; Generated by http://www.piclist.com/cgi-bin/delay.exe (December 7, 2005 version)
; Sat Jan 30 23:37:02 2010 GMT

; See also various delay routines at http://www.piclist.com/techref/microchip/delays.htm 

; ----------------------------------------------------------------------------
        end
; ----------------------------------------------------------------------------




Click on the photo above to see the Nixie clock in action Play Ogg
or
click here to see it on youtube
(warning: low quality movie)


ToDo:
  • Make a better looking schematic drawing ;-)
  • Do something useful with it, instead of just counting numbers

Posted by Jan Wagemakers | Permanent link | File under: nixie, pic