Friday, March 15, 2013

Binary clock



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.


20 comments:

  1. Awesome! I love binary watches and this one has an unique "geek" feeling. Keep up the good work!

    ReplyDelete
    Replies
    1. Thanks very much! Soon I'll post the new version

      Delete
  2. I like it! I saw your blog linked on Hack a Day, and had to take a look!

    ReplyDelete
  3. you'd be arrested for wearing that in Poland, anti-terrorism laws and all.

    ReplyDelete
    Replies
    1. Seriously? I think you meant USA, not Poland.

      Delete
  4. Nice one!!! you gave me a new weeknd project for my holydays

    ReplyDelete
  5. I saw this on HAD too and it's very cool
    Well done !

    ReplyDelete
  6. Could you post the source for this little jewel?

    ReplyDelete
    Replies
    1. I'll post it with the new version of the watch

      Delete
  7. I want make a watch like this but I still do not understand the electronic component of SV, would you give me a clearer explanation, thank you!!

    ReplyDelete
    Replies
    1. I'll post soon (i hope) the new version with a better explanation

      Delete
    2. "SV1" is a connector for a PICkit programmer which, when Emanuele posts the code, is what you use to program the PIC chip.

      Delete
  8. sorry i couldn't understand how to set time. i made circuit, only 2 leds of hour leds always on.

    ReplyDelete
    Replies
    1. you should get in programming mode every time you unpower and then power it (pull off and on the voltage source)...
      and other way to enter in programming mode is to press 8 times the right button (or maybe the left, can't remember) while the led are still ON.

      the programming mode work as follow:

      -enter programming mode
      -every click of left button increases the minutes
      -one click on right button set the minutes
      -every click of left button increases the hours
      -one click of the right button set hours
      -exit programming mode

      the right and left button indication can be wrong, maybe you have to switch right with left( can't remember )

      so for examples you need to set the 8:23

      -8 click on the right button
      -23 click on the left button
      -1 click on the right button
      -8 click on the left button
      -1 click on the right button
      and you have done :)

      Delete
    2. This comment has been removed by the author.

      Delete
  9. Hello;
    sorry i couldnt run the circuit, i did exatly what you told but still doesn't work. only 2 leds (porta6 and porta7) always on. Maybe my problem which is i use 16F628A. is that program suitable 16F628A or i have to use F628 ?
    lastly; while programming the pic, is oscillator -ER osc, with CLKOUT- ? is that true

    ReplyDelete
    Replies
    1. I added the configuration bits screen at the end of the page, I hope it will run now :)

      Delete
    2. perfetto ... grande :)) it's aliveeee !!!
      thank you sooo much my friend, you are the best :D

      Delete
    3. :) I'm now working on the improved version of the clock
      -more precise time
      -less power consumption
      -regulable led light
      -C written program

      Stay tuned :)

      Delete
  10. That is my watch :)

    http://imageshack.us/photo/my-images/537/3a5edf.jpg

    http://imageshack.us/photo/my-images/539/2b2333.jpg

    http://imageshack.us/photo/my-images/673/089e05.jpg

    http://imageshack.us/photo/my-images/633/3563b7.jpg

    http://imageshack.us/photo/my-images/539/61aa46.jpg

    http://imageshack.us/photo/my-images/902/62118d.jpg

    ReplyDelete