Make a binary clock is the dream of all NERD on the world right? (mmm.. or maybe build a lightsaber :) ).
I got this idea while I was attending my last year of school, and i decide to design and build a binary
wristwatch.
I was studing pic's at the moment so, for the brain I chose a everyone-known PIC16F628.
For the time display I thought of using 4 led's for the hours and 6 led for the minutes following this scheme:
You can get the hours by adding the value of ON green leds, and the same process for the minutes with red leds.
HOW TO MISURE THE CORRECT TIME?
To keep the correct timing i used Timer1 operating in asynchronous counter mode, the idea is this:
to save battery life the pic will be on sleep-mode when the time is not displayed, and the led will be ON only for a few second after one of the 2 buttons is being pressed. While in sleep-mode the pic shut-down almost all of his feature, but the TMR1 counter mode still stays on, so you can count the time while the pic is sleeping.
When the TMR1 16-bit-register overflow, a interrupt signal wake up the pic, in this case the second's are updated and the pic returns at bed.
To use TMR1 as external counter, you have to give him something to count, this is made by adding a 32.768 Hz quarz oscillator between pins RB7 and RB6.
The pic will be running with internal oscillator clock at 32 khz instead of 4 Mhz to save additional current.
HOW TO DISPLAY TIME?
The time is displayed when one of the 2 buttons is pressed. The question now is: how can the pic read the button if it's on sleep-mode? Well, for that I used interrupt-on-change feature for RB4 and RB5, when the state of these pins change the pic is waked up.
When a button is pressed, TMR0 is also load with a value and TMR0 interrupt is enabled, this is used to measure the time the leds will be on, when TMR0 overflow, all the leds are tuned OFF and the pic return in sleep-mode.
SUMMARIZING ALL THE LOGIC BEHIND THIS CLOCK
-start of the program (initialization)
-pic go on sleep
IF TMR1 go on overflow
-wake up pic
-update time
-return on sleep
IF PORB-interrupt
-wake the pic
-turn on leds displaying time
-wait for a while (with TMR0 overflow)
-turn off all leds
-return on sleep
HOW TO SET TIME?
Well, in this case i have to updade the program, now you can set the time only the first time you boot the clock.
SCHEMATICS
(the strip is for pic-kit programmer)
(there is one more led used for MODE-led)
SOME PHOTOS
the body is made of PVC, the battery I'm using is a CR2032, the battery compartment is milled in the body by a CNC machine.
The strap is simply glued to the bottom of the body, in 1mm-deep recess.
here is the asm code
list p=16F628
include <P16F628.INC>
;TITLE "Smazlogio v1.7"
;AUTHOR Santelelle
;min 1 porta.2
;min 2 porta.3
;min 4 porta.4
;min 8 portb.0
;min 16 portb.1
;min 32 portb.3
;portb minutes b'00001011'
;porta minutes b'00011100'
;ore 1 porta.1
;ore 2 porta.0
;ore 4 porta.7
;ore 8 porta.6
;portb hours b'00000000'
;porta hours b'11000011'
;pulsante sinistro portb.4
;pulsante destro portb.5
;led MODE portb.3
SEC EQU 0x20
MIN EQU 0x21
ORE EQU 0x22
W_TEMP EQU 0x23
S_TEMP EQU 0x24
TMR1_INTERRUPT_FLAG EQU 0x25
LED_ON EQU 0x26
CONTATORE_PULSANTE1 EQU 0x27
PROGRAM EQU 0x28
DELAY_COUNTER EQU 0x29
TMR0_INTERRUPT_FLAG EQU 0x2A
CONTATORE EQU 0x2B
PORTB_INTERRUPT_FLAG EQU 0x2C
CONTATORE_PULSANTE2 EQU 0x2D
ORG 0000H
goto START
;
ORG 0004H ;interrupt occurred
BTFSC PIR1, TMR1IF ;Timer1 overflowed?
call T1_OVERFL ;YES, Service the Timer1 Overflow Interrupt
BTFSC INTCON,RBIF ;portb changed?
call PORTB_INTERRUPT ;goto portb_interrupt routine
BTFSC INTCON,TMR0IF ;portb changed?
call TMR0_INTERRUPT ;goto portb_interrupt routine
retfie
;
; Should NEVER get here
;
ERROR1 ; NO, Unknown Interrupt Source
BSF PORTA , 4 ; Toggle a port pin to indicate error
BCF PORTA , 4
GOTO ERROR1
START
;inizializzazione variabili
bcf INTCON,GIE ;global interrupt enable
clrf SEC
clrf MIN
clrf ORE
clrf TMR1_INTERRUPT_FLAG
clrf LED_ON
clrf PROGRAM
clrf TMR0_INTERRUPT_FLAG
clrf CONTATORE
clrf PORTB_INTERRUPT_FLAG
clrf DELAY_COUNTER
;fine inizializzazione variabili
;settaggio registri
bcf STATUS,RP0 ; select bank0
clrf PORTA
bsf STATUS,RP0 ; select bank1
movlw b'00100000'
movwf TRISA
bcf STATUS,RP0 ; select bank0
clrf PORTB
bsf STATUS,RP0 ; select bank1
movlw b'11110000'
movwf TRISB
bsf STATUS,RP0 ; select bank1
movlw b'00000111'
movwf OPTION_REG
movlw b'00000001' ; enable TMR1 overflow
movwf PIE1
movlw b'00000011'
movwf PCON
bcf STATUS,RP0 ; select bank0
movlw b'00000111'
movwf CMCON
clrf PORTA ; accende tutti i led
clrf PORTB ; accende tutti i led
;fine settaggio registri
ASPETTA_PULS ;until the button isn't pushed the program doesn't start
btfsc PORTB,4 ;
goto ASPETTA_PULS ;
movlw b'11111111' ;turn off all portb
movwf PORTA ;
movlw b'11111111' ;turn off all portb
movwf PORTB ;
;movlw b'00001111' ;set timer1 as external asyncronous counter
movlw b'00111111' ;16 seconds
movwf T1CON ;
goto PROGRAMMING_MODE
m_cicle ;main cicle
btfsc TMR1_INTERRUPT_FLAG,0 ;if an interrupt occurred
call AGGIORNA_ORA ;upgrade time
btfss TMR0_INTERRUPT_FLAG,0
goto NO_TMR0_INTERRUPT
bcf TMR0_INTERRUPT_FLAG,0
clrf CONTATORE
bcf LED_ON,0
clrf CONTATORE
NO_TMR0_INTERRUPT
btfss PORTB_INTERRUPT_FLAG,0
goto NO_PORTB_INTERRUPT
bcf PORTB_INTERRUPT_FLAG,0
btfss PORTB,4
incf CONTATORE
bsf LED_ON,0
clrf TMR0
bcf INTCON,T0IF ;clear the interrupt TMR0 flag
bsf INTCON,T0IE ;activate timer0 interrupt
NO_PORTB_INTERRUPT
movlw b'00001000'
subwf CONTATORE,0
btfsc STATUS,Z
goto PROGRAMMING_MODE
btfss LED_ON,0 ;se è attivo il flag accende i led
goto NO_OUTPUT
call OUTPUT_MINUTI
call OUTPUT_ORE
goto m_cicle
NO_OUTPUT
call ALL_LED_OFF
sleep;
goto m_cicle ;end main cicle
PROGRAMMING_MODE
bcf INTCON,GIE ;disables interrupt
bcf INTCON,RBIF
bcf INTCON,TMR0IF
bcf PIR1, TMR1IF
call ALL_LED_OFF
bcf PORTB,2 ;turn on blue led
clrf MIN
clrf ORE
call DELAY
clrf CONTATORE_PULSANTE1
clrf CONTATORE_PULSANTE2
clrf CONTATORE
PROG_MINUTI
;
btfss PORTB,4
incf CONTATORE_PULSANTE1
btfsc PORTB,4
clrf CONTATORE_PULSANTE1
movlw b'00001110'
subwf CONTATORE_PULSANTE1,w
btfsc STATUS,Z
goto RELASE_CYCLE1R_
;
btfss PORTB,5
incf CONTATORE_PULSANTE2
btfsc PORTB,5
clrf CONTATORE_PULSANTE2
movlw b'00001110'
subwf CONTATORE_PULSANTE2,w
btfsc STATUS,Z
goto RELASE_CYCLE1L_
goto PROG_MINUTI
;
RELASE_CYCLE1R_
incf MIN
call OUTPUT_MINUTI
clrf CONTATORE_PULSANTE1
clrf CONTATORE_PULSANTE2
RELASE_CYCLE1R
btfss PORTB,4
clrf CONTATORE_PULSANTE1
btfsc PORTB,4
incf CONTATORE_PULSANTE1
movlw b'00001110'
subwf CONTATORE_PULSANTE1,w
btfsc STATUS,Z
goto PROG_MINUTI
goto RELASE_CYCLE1R
;
RELASE_CYCLE1L_
clrf CONTATORE_PULSANTE1
clrf CONTATORE_PULSANTE2
RELASE_CYCLE1L
btfss PORTB,5
clrf CONTATORE_PULSANTE2
btfsc PORTB,5
incf CONTATORE_PULSANTE2
movlw b'00001110'
subwf CONTATORE_PULSANTE2,w
btfsc STATUS,Z
goto PROG_HOUR_
goto RELASE_CYCLE1L
;;
PROG_HOUR_
clrf CONTATORE_PULSANTE1
clrf CONTATORE_PULSANTE2
PROG_HOUR
btfss PORTB,4
incf CONTATORE_PULSANTE1
btfsc PORTB,4
clrf CONTATORE_PULSANTE1
movlw b'00001110'
subwf CONTATORE_PULSANTE1,w
btfsc STATUS,Z
goto RELASE_CYCLE2R_
btfss PORTB,5
incf CONTATORE_PULSANTE2
btfsc PORTB,5
clrf CONTATORE_PULSANTE2
movlw b'00001110'
subwf CONTATORE_PULSANTE2,w
btfsc STATUS,Z
goto RELASE_CYCLE2L_
goto PROG_HOUR
RELASE_CYCLE2R_
incf ORE
call OUTPUT_ORE
clrf CONTATORE_PULSANTE1
clrf CONTATORE_PULSANTE2
RELASE_CYCLE2R
btfss PORTB,4
clrf CONTATORE_PULSANTE1
btfsc PORTB,4
incf CONTATORE_PULSANTE1
movlw b'00001110'
subwf CONTATORE_PULSANTE1,w
btfsc STATUS,Z
goto PROG_HOUR
goto RELASE_CYCLE2R
RELASE_CYCLE2L_
clrf CONTATORE_PULSANTE1
clrf CONTATORE_PULSANTE2
RELASE_CYCLE2L
btfss PORTB,5
clrf CONTATORE_PULSANTE2
btfsc PORTB,5
incf CONTATORE_PULSANTE2
movlw b'00001110'
subwf CONTATORE_PULSANTE2,w
btfsc STATUS,Z
goto END_PROGRAMMING
goto RELASE_CYCLE2L
END_PROGRAMMING
call ALL_LED_OFF
bcf T1CON,T1OSCEN
clrf TMR1H
clrf TMR1L
bsf T1CON,T1OSCEN
bsf INTCON,RBIE ;portb interrupt on change enable
bsf INTCON,PEIE ;peripheral interrupt enable
bsf INTCON,GIE ;global interrupt enable
goto m_cicle
ALL_LED_OFF
movlw b'11111111'
movwf PORTA
movwf PORTB
return
OUTPUT_MINUTI
movlw b'00001011'
iorwf PORTB,f
movlw b'00011100'
iorwf PORTA,f
btfsc MIN,0
bcf PORTA,2
btfsc MIN,1
bcf PORTA,3
btfsc MIN,2
bcf PORTA,4
btfsc MIN,3
bcf PORTB,0
btfsc MIN,4
bcf PORTB,1
btfsc MIN,5
bcf PORTB,3
return
OUTPUT_ORE
movlw b'11000011'
iorwf PORTA,f
btfsc ORE,0
bcf PORTA,1
btfsc ORE,1
bcf PORTA,0
btfsc ORE,2
bcf PORTA,7
btfsc ORE,3
bcf PORTA,6
return
AGGIORNA_ORA
bcf TMR1_INTERRUPT_FLAG,0 ;clear interrupt TMR1 flag
;incf SEC ;inc seconds
;incf SEC ;inc seconds
movlw b'00010000'
addwf SEC,f
movlw b'00111100' ;are seconds >= 60?
subwf SEC,W ;
btfsc STATUS,C ;
call INC_MIN ; call the function that increment minutes
movlw b'00111100' ;are minutes >= 60?
subwf MIN,W ;
btfsc STATUS,Z ;
call INC_ORE ; call the function that increment hours
movlw b'11111111'
return ;return to main
INC_MIN ;increment minutes
incf MIN,f
movlw b'00111100' ;seconds = seconds - 60
subwf SEC , f ;
return
INC_ORE ;increment minutes
incf ORE ;inc ore
movlw b'00111100' ;minutes = minutes - 60
subwf MIN , f ;
movlw b'00001100' ;are hours = 12?
subwf ORE,W ;
btfsc STATUS,Z ;
clrf ORE ; if hours=12 then hours=0
return
TMR0_INTERRUPT
bsf TMR0_INTERRUPT_FLAG,0
bcf INTCON,T0IF
bcf INTCON,T0IE
bsf INTCON,7 ;enable interrupt
return
PORTB_INTERRUPT
movf PORTB,w
bcf INTCON,RBIF
btfss PORTB,4
goto SET_PORTB_FLAG
btfss PORTB,5
goto SET_PORTB_FLAG
bsf INTCON,7 ;enable interrupt
return
SET_PORTB_FLAG
bsf PORTB_INTERRUPT_FLAG,0
bsf INTCON,7 ;enable interrupt
return
T1_OVERFL ;TMR1 overflowed
bsf TMR1_INTERRUPT_FLAG,0
bcf PIR1, TMR1IF ; Clear Timer1 Interrupt Flag
bsf INTCON,7 ;enable interrupt
return
DELAY
clrf DELAY_COUNTER
DELAY_CYCLE
incf DELAY_COUNTER
btfss STATUS,Z
goto DELAY_CYCLE
return
end
Edit: I'm really sorry, I forgot the configuration bits.