 
 
;-----------------------------------------------------------------------;
; BINCLOCK.ASM          A clock that displays in bcd numbers            ;
;-----------------------------------------------------------------------;
        LIST P=16F84           ;  tells which processor is used
        INCLUDE "p16f84.inc"   ;  defines various registers etc. Look it over.
        ERRORLEVEL -224        ;  supress annoying message because of tris
        __CONFIG _PWRTE_ON & _LP_OSC & _WDT_OFF   ;  configuration switches
            CBLOCK     0CH
                sec             ; seconds digit
                sec10           ; 10's of second digit
                mins            ; minutes digit
                min10           ; 10's of minutes digit
                hr              ; hours digit
                hr10            ; 10's of hours digit
                w_temp          ; holds W during interrupt
                status_temp     ; holds STATUS during interrupt
                fsr_temp        ; holds FSR during interrupt
                button          ; holds mask for pushbuttons
              ENDC
          
;-----------------------------------------------------------------------;
;  Here are some DEFINEs which give 'names' to pushbutton port bits     ;
;-----------------------------------------------------------------------;
            #DEFINE SETPB PORTB, 4
            #DEFINE SELECTPB PORTB, 5
            #DEFINE SHOWPB PORTB, 6
            ORG 0               ; start at location 0
            goto main           ; jump over to main routine       
            ORG 4
             
            goto isr            ; jump to interrupt routine
;-----------------------------------------------------------------------;
;                  High limit + 1 of digits at position W               ;
;-----------------------------------------------------------------------;
sethi:
            addwf PCL, f
         dt H'A',H'6',H'A',H'6',H'A',H'3'
;-----------------------------------------------------------------------;
;                           Delay routines                              ;
;-----------------------------------------------------------------------;
msec250:                       ; enter here to delay for 250 milliseconds
         movlw D'250'          
nmsec:                         ; delay for # msec in W on entry
         nop                   ; each nop is 0.122 milliseconds
         nop
         nop                   ; each total loop is 8 X 0.122 = 0.976 msec
         nop
         addlw H'FF'           ; same as subtracting 1 from W
         btfss STATUS, Z       ; skip if result is zero
         goto nmsec            ; this is  2 X 0.122 msec  
         return                ; back to calling point
;-----------------------------------------------------------------------;
;                        Delay for one second                           ;
;-----------------------------------------------------------------------;
onesecond:                     ; a subroutine that delays for 1 seconds
         call msec250
         call msec250
         call msec250
         call msec250
         return
;-----------------------------------------------------------------------;
;                   Put value in W on LEDs for 1 second                 ;
;-----------------------------------------------------------------------;
sendnbr:
         movwf PORTB          ; light LEDs
         call onesecond       ; wait 1 second
         clrf PORTB           ; clear the LEDs
         movlw D'100'         ; pause for 0.1 sec
         call nmsec
         return 
;-----------------------------------------------------------------------;
;                   Send the current time out LEDs                      ;
;-----------------------------------------------------------------------;
disptime:              
             movf hr10, W
             call sendnbr
             movf hr, W
             call sendnbr
             movf min10, W
             call sendnbr
             movf mins, W
             call sendnbr
             return
;-----------------------------------------------------------------------;
;                 Wait until selected button is released                ;
;-----------------------------------------------------------------------;
waitup6:                             ; wait for show pushbutton up
            movlw B'01000000'        ; RB6 mask
            movwf button
            goto wait
waitup5:                             ; wait for select pushbutton up
            movlw B'00100000'        ; RB5 mask
            movwf button
            goto wait
waitup4:                             ; wait for set pushbutton up
            movlw B'00010000'        ; RB4 mask
            movwf button
wait:
            movf button, W           ; mask into W
            andwf PORTB, W
            btfsc STATUS, Z          ; skip if not zero (released)
            goto wait
            movlw D'10'
            call nmsec               ; wait 10 msec for debounce
            movf button, W           ; check for release again
            andwf PORTB, W
            btfsc STATUS, Z          ; skip if selected button released
            goto wait
            return                   ; yes, finished
;-----------------------------------------------------------------------;
;                       Initilization Subroutine                        ;
;-----------------------------------------------------------------------;
init:
            movlw B'0000000'           ; all outputs port A
            tris PORTA                 
            movlw B'01110000'          ; RB4 - RB6 inputs, others outputs
            tris PORTB                 ; on port B
            movlw H'0'                 ; all low (off)
            movlw PORTB
            movlw B'00000100'          ; pull-ups enabled                                    
                                       ; prescaler assigned to TMR0
                                       ; prescaler set to 1:32
                                       ; rolls over each second
            option                
            movlw 0
            movwf hr10
            movlw H'9'                 ; initialize hrs, mins and secs
            movwf hr                   ; Do this before interrupts are
            movlw H'5'                 ; turned on because isr also acts
            movwf min10                  ; on these registers
            movlw H'0'
            movwf mins
            movwf sec10
            movwf sec
            movlw B'10100000'          ; GIE & T0IE set, T0IF cleared
            movwf INTCON
            return
;-----------------------------------------------------------------------;
;  Interrupt routine, increments time by one second  (BCD)              ;
;-----------------------------------------------------------------------;
isr:
            movwf w_temp             ; save W
            swapf STATUS,W           ; save status
            movwf status_temp        ; without changing flags
            swapf FSR,W              ; save FSR
            movwf fsr_temp           ; without changing flags
            movlw sec                ; point at sec register
            movwf FSR
newdigit:   incf INDF, f             ; current digit up one
            movlw sec                ; get difference between sec and FSR
            subwf FSR, W
            call sethi               ; use to get high limit + 1
            subwf INDF, W            ; reached that number yet?
            btfss STATUS, Z          ; skip over if yes
            goto restore             ; else exit isr
            clrf INDF                ; set current digit to 0
            incf FSR, f               ; point at next digit
            btfss hr10, 1            ; has hr10 reached 2?
            goto newdigit            ; no, increment the next digit
            btfss hr, 2              ; has hr reached 4?
            goto newdigit            ; no
            clrf hr                  ; yes, set hour to 00
            clrf hr10                ; and hour 10
restore: 
            swapf status_temp,W      ; get original status back
            movwf STATUS             ; into status register
            swapf fsr_temp,W         ; get original fsr back
            movwf FSR                ; into status register
            swapf w_temp,f           ; old no flags trick again
            swapf w_temp,W           ; to restore W
            bcf INTCON,T0IF          ; clear the TMR0 interrupt flag
            retfie                   ; finished reset GIE
;-----------------------------------------------------------------------;
;           Increment and display digit pointed to by FSR               ;
;-----------------------------------------------------------------------;
updigit:
            incf INDF, f          ; selected digit up one
            movlw mins            ; set up to subtract mins address
            subwf FSR, W          ; from address of current digit
            call sethi            ; get maximum of digit + 1 into W
            subwf INDF, W         ; is it = to current digit value?
            btfsc STATUS, Z       ; gives zero if yes, skip if no
            clrf INDF             ; reset value of digit to zero
            movf INDF, W          ; get current value and ..
            movwf PORTB           ; display it
            call onesecond        ; pause for 1 second
            return
;-----------------------------------------------------------------------;
;          increment selected digit until select pressed                ;
;-----------------------------------------------------------------------;
setdigit:
            movwf PORTB
            btfss SETPB           ; set pressed?
            call updigit          ; yes
            btfsc SELECTPB        ; check if select pressed
            goto $ -3             ; repeat till select pressed again
            call waitup5          ; make sure select released
            incf FSR, f
            return
;-----------------------------------------------------------------------;
;                     Select and increment digits                       ;
;-----------------------------------------------------------------------;
select:
            bcf INTCON, GIE       ; no interrupts while setting time
            movlw mins            ; point at minutes register
            movwf FSR
            call waitup5          ; wait on select pushbutton up
            movlw B'00000001'     ; light right LED (mins)
            call setdigit
            movlw B'00000010'     ; light min10 LED
            call setdigit
            movlw B'00000100'     ; light hr LED
            call setdigit
            movlw B'00001000'     ; hr10 LED on
            call setdigit
            clrf PORTB            ; clear LEDs
            bsf INTCON, GIE       ; enable interrupts again
            return
;-----------------------------------------------------------------------;
;                          The main routine                             ;
;-----------------------------------------------------------------------;
main:      
            call init             ; set up initial conditions
loop:       
            btfss SHOWPB          ; check for show pushbutton
            call disptime         ; display the time
            btfss SELECTPB        ; check for select
            call select
            goto loop             ; do forever
            end
If the 'select' pushbutton is pressed the program goes into a mode where the digits can be set. The rightmost LED will come on indicating that the minutes digit is to be set. The minutes digit will be incremented and displayed at one second intervals while the 'set' pushbutton is pressed. Pressing 'select' again will transfer to the next higher digit. After tens of hours is set, the next press of the 'select' button returns you to the time display mode.
If you look at the interrupt routine in 'eggtimer' you find each of the three digit registers treated in turn. This time there are six registers but you don't see the name of any but 'sec' in 'isr'. The code between saving and restoring of registers is even smaller in the case of 'binclock'. How can this be, more registers but fewer instructions?
We use the register 'FSR' in the isr and must save it on entry and restore it on exit of the interrupt subroutine. This is because we also use FSR in the display routines outside the isr.
Setting time involves three subroutines. 'select' calls 'setdigit' which in turn calls 'updigit' Subroutine calls can be listed in any order and the call will find the code. But, I like to list subroutines with those called preceding those doing the calling. This leaves the main routine last.
Notice that interrupts are disabled at the beginning of the time setting routine and enabled on leaving. This is necessary because the interrupt routine works with the same registers as the time setting routine. We can't have both changing the registers 'at the same time'.
A mask is like a piece of cardboard with holes in it that you place over the binary representation of a register. Where holes are, the bits come through unchanged; in other positions they will be changed to zeros. The mask has 1's where the holes are, zeros in the other bit positions. We 'AND' the number with a mask to zero certain bits.
Suppose we 'AND' the number B'10110101' with the mask B'00001111'. The result is B'00000101'. We have removed the high four bits, (upper nibble), of the original number. By using a mask with only 1 bit set, we can look at a single bit in a number. This is what is done in the code starting at waitup6.
For more information on 'AND' and other logical bit operations try: http://www.cscene.org/cs9/cs9-02.html
Secondly, the display indicating which digit is to be set is the same as the display for the digits 1,2,4 and 8. Maybe when indicating which digit is to be set the digit could flash on and off. Can you change the subroutine 'setdigit' to make this happen?
The clock could be turned into an alarm clock. Give some thought to how you would have the current time checked against alarm time to set off the alarm. You will need more registers to hold the alarm time digits. The same time setting routine can be used because of FSR.
You might want the clock to be able to 'memorize' the alarm times, even if the battery failed or was removed. That will be covered in program 6.
This clock program could be combined with routines from 'morsenbr' for an audible clock.
You may want to have the clock display every ten seconds rather than have to press the 'show pushbutton'. Can you make the necessary changes? I hope you are using low current LEDs if you do this.
Comments:
Questions:
Why use a mask to check for a button release?James Newton replies: Using the mask allows the program to pass the button to be checked as a variable. The bit test commands must have the bit number hard coded. DT is a shorthand for multiple retlw commands.+
Why not test directly with "btfss SETPB" or "btfsc SETPB", as applicable?
Also, in the table defining the limits for each digit, what is the "dt" command? I would have expected a "retlw" in front of each value. Is this short hand?
Think about the largest number that can be displayed for each digit on a clock display.+
Meh, sorry... i just noticed something terribly wrong.. of course it'd need to be lit only when the button is pressed, otherwise it'd be too difficult to read the clock, as understanding wether it's showing hours or minutes atm would be rather difficult.+
(yes, i am a newbie with PICs)
Interesting.. How would i go if i wanted it to begin at 00:00, use rb0, rb1 and rb2 for ten hours and ten minutes, rb3, rb4, rb5 and rb6 for hours and minutes. The leds would be lit 24/7... Any help would be appreciated.+
| file: /Techref/piclist/cheapic/binclock.htm, 21KB, , updated: 2008/3/3 10:58, local time: 2025/10/31 01:01, 
 
216.73.216.219,10-1-97-123:LOG IN | 
| ©2025 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions? <A HREF="http://ecomorder.com/Techref/piclist/cheapic/binclock.htm"> Binary Clock </A> | 
| Did you find what you needed? | 
| Welcome to ecomorder.com! | 
| Welcome to ecomorder.com! | 
.