?? picclock.asm
字號:
LIST p=16F84 ; PIC16F844 is the target processor
#include "P16F84.INC" ; Include header file
CBLOCK 0x10 ; Temporary storage
state
secs
mins
hours
ticks
idc
bcd
ENDC
; Constants for bit allocation. The BIT_x constants are actual bit numbers and
; the MASK_x are bit masks for the same bit.
BIT_HSEL EQU H'0000'
BIT_TSET EQU H'0001'
BIT_HSET EQU H'0002'
BIT_MSET EQU H'0003'
BIT_H24 EQU H'0000'
BIT_PM EQU H'0001'
BIT_SET EQU H'0002'
BIT_HSB EQU H'0003'
MASK_H24 EQU H'0001'
MASK_PM EQU H'0002'
MASK_SET EQU H'0004'
MASK_HSB EQU H'0008'
; Macro to generate a MOVLW instruction that also causes a model break:
break MACRO arg
DW 0x3100 | (arg & H'FF')
ENDM
ORG 0
entrypoint goto initialise
ORG 4
intvector goto clock
initialise ; Register set up:
clrw ; Zero.
movwf PORTA ; Ensure PORTA is zero before we enable it.
movwf PORTB ; Ensure PORTB is zero before we enable it.
bsf STATUS,RP0 ; Select Bank 1
movlw H'1F' ; Mask for PORTA inputs/outputs.
movwf TRISA ; Set TRISA register.
movlw H'01' ; Mask for PORTA inputs/outputs.
movwf TRISB ; Set TRISB register.
bcf STATUS,RP0 ; Reselect Bank 0.
; Initialise clock:
clrf state
bsf state,BIT_HSB
movlw D'0'
movwf hours
movlw D'0'
movwf mins
movlw D'0'
movwf secs
; Clear 50Hz tick count:
clrf ticks
; Clear interrupt disable count (idc) semaphore:
clrf idc
; Initialise display:
call wr_hours
call wr_mins
call wr_secs
call wr_state
; Finally initialise interrupts for clock on RB0/INT pin:
movlw H'90'
movwf INTCON
start ; When not processing an interrupt we sit and check input pins:
call chk_tset ; Time set select active?
call chk_hsel ; H12/H24 display format select active?
goto start
;------------------------------------------------------------------------------
; Interrupt handler. We come here for every tick of the time base.
clock ; Toggle half-second flag and set state outputs:
incf ticks,F ; Increment clock ticks.
movf ticks,W ; Get ticks value.
sublw D'25' ; Is it 25 (W=25-W)?
btfss STATUS,Z ; Test zero flag.
goto endclock ; Return.
toggle_hs ; Half second - toggle HS flag, write it and return:
clrf ticks ; Reset timebase,
movf state,W ; Get state.
xorlw MASK_HSB ; Toggle half-second bit.
movwf state ; Save it back to register.
call wr_state ; Display it.
movf state,W ; Get state.
btfss state,BIT_HSB ; Is bit now clear?
goto endclock ; Return.
inc_secs ; Incrmement seconds...
incf secs,F ; Increment seconds count.
movf secs,W ; Get it into W.
sublw D'60' ; Is it 60 (W=60-W)?
btfsc STATUS,Z ; Test zero flag, skip clear if no set.
goto reset_secs ; Clear seconds, increment minutes.
call wr_secs ; Write seconds it to display.
goto endclock ; Done.
reset_secs clrf secs
call wr_secs ; Write seconds to display.
incf mins,F ; Increment minute count.
movf mins,W ; Get it into W.
sublw D'60' ; Is it 60 (W=60-W)?
btfsc STATUS,Z ; Test zero flag, skip clear if no set.
goto reset_mins ; Clear minutes, increment hours.
call wr_mins ; Write minutes it to display.
goto endclock ; Done.
reset_mins clrf mins ; Reset minute count to zero.
call wr_mins ; Write minutes to display.
call inc_hours ; Increment hours, display it with PM flag.
endclock movlw H'90'
movwf INTCON
retfie ; Return
;------------------------------------------------------------------------------
; Subroutine. Check the state of the HSEL input and set h12/h24 format as
; required.
chk_hsel btfsc PORTA,BIT_HSEL ; Test 12/24 select.
goto set_h12 ; H12 set so switch to 12 hour format.
; fall through ; H12 not set so switch to 24 hour format.
set_h24 btfsc state,BIT_H24 ; Are we on 12 hour format?
retlw 0 ; No, so no need to do anything...
bcf INTCON,GIE ; Disable interrupts.
incf idc,F ; Increment count of number of disables.
bsf state,BIT_H24 ; Clear h12 flag.
movf hours,W ; Get hours value.
sublw D'12' ; Is it 12:xx?
btfsc STATUS,Z ; Test zero flag.
clrf hours ; Reset to zero.
movf hours,W ; Get hours value.
btfsc state,BIT_PM ; Is the PM indicator set?
addlw D'12' ; Add 12 to get 24 hour value.
movwf hours ; Save result (does nothing for AM).
bcf state,BIT_PM ; Clear PM flag.
call wr_hours ; Write hours.
call wr_state ; Write H12 state and PM state.
goto chk_hsel_iec ; Done.
set_h12 btfss state,BIT_H24 ; Are we on 12 hour format?
retlw 0 ; Yes, so no need to do anything...
bcf INTCON,GIE ; Disable interrupts.
incf idc,F ; Increment count of number of disables.
bcf state,BIT_H24 ; Set h12 flag.
movf hours,W ; Get hour value.
sublw D'11' ; W=11-W. C is clear for a borrow (W>=12).
btfss STATUS,C ; Test carry flag.
goto set_h12_pm ; Set PM.
set_h12_am bcf state,BIT_PM ; Clear PM bit.
movf hours,W ; Get hours.
btfsc STATUS,Z ; Is it zero?
addlw D'12' ; Yes, add 12 to get 00:xx to 12:xx.
movwf hours ; Save any result.
call wr_hours ; Display hours.
call wr_state ; Display H12 and PM states.
goto chk_hsel_iec ; Done.
set_h12_pm bsf state,BIT_PM ; Set PM bit.
movlw D'12' ; Constant.
subwf hours,F ; hours=hours-12 (23..12 -> 11..0).
btfsc STATUS,Z ; Zero set?
movwf hours ; Yes, so reset to '12'.
call wr_hours ; No, so leave hours alone and display it.
call wr_state ; Display H12 and PM states.
goto chk_hsel_iec ; Done.
chk_hsel_iec decfsz idc,F ; Decrement idc. If zero we can reenable interrupts.
retlw 1 ; Return without enabling interrupts.
chk_hsel_done movlw H'90' ; Constant for GIE and T0IE.
movwf INTCON ; Set interrupt register.
retlw 1 ; Return.
;------------------------------------------------------------------------------
chk_tset btfsc PORTA,BIT_TSET ; Set mode?
retlw 0
bcf INTCON,GIE ; Disable interrupts.
incf idc,F ; Increment count of number of disables.
bsf state,BIT_SET ; Set the 'set mode' bit.
clrf secs ; Setting time resets seconds count.
call wr_secs ; Display it.
bcf state,BIT_HSB ; Clear seconds toggle.
call wr_state ; Update the state output latch.
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -