📄 clock.asm
字号:
LIST P = 16C74, n = 66
ERRORLEVEL -302
;
;******************************************************************************
;
; This program implements a real time clock using the TMR1 module of the
; PIC16Cxx family. A LCD display module is used to display (update) the time
; every second. Three keys are used to set the time.
;
; Program = CLOCK.ASM
; Revision Date: 5-15-94
; 1-15-97 Compatibility with MPASMWIN 1.40
;
;******************************************************************************
;
;
; HARDWARE SETUP
; LCD Control Lines
; RA0 = E (Enable)
; RA1 = RW (Read/Write)
; RA2 = RS (Register Select)
; LCD Data Lines
; RB<3:0>
; Switch Inputs
; RB7 = Select Hour / Minute / Off
; RB6 = Increment Hour / Minute
; RB5 = Reset Minutes to 00
;
INCLUDE <p16c74.inc>
FALSE EQU 0
TRUE EQU 1
INCLUDE <CLOCK.h>
;
LCD_DATA EQU PORTB ; The LCD data is on the lower 4-bits
LCD_DATA_TRIS EQU TRISB ; The TRIS register for the LCD data
LCD_CNTL EQU PORTA ; Three control lines
;
PICMaster EQU FALSE ; A Debugging Flag
Debug EQU FALSE ; A Debugging Flag
Debug_PU EQU TRUE ; A Debugging Flag
;
;
; Reset address. Determine type of RESET
;
org RESET_V ; RESET vector location
RESET BSF STATUS, RP0 ; Bank 1
BTFSC PCON, NOT_POR ; Power-up reset?
GOTO START ; YES
GOTO OTHER_RESET ; NO, a WDT or MCLR reset
;
; This is the Periperal Interrupt routine. Need to determine the type
; of interrupt that occurred. The following interrupts are enabled:
; 1. PORTB Change (RBIF)
; 2. TMR1 Overflow Interrupt (T1IF)
;
page
org ISR_V ; Interrupt vector location
PER_INT_V
if ( Debug )
bsf PORTD, 0 ; Set high, use to measure total
endif ; time in Int Service Routine
;
BCF STATUS, RP0 ; Bank 0
BTFSC PIR1, TMR1IF ; Timer 1 overflowed?
GOTO T1_OVRFL ; YES, Service the Timer1 Overflow Interrupt
BTFSS INTCON, RBIF ; NO, Did PORTB change?
GOTO ERROR1 ; NO, Error Condition - Unknown Interrupt
;
PORTB_FLAG ; Are any of PORTB's inputs active?
MOVF PORTB, W ;
ANDLW 0xE0 ; Keep only the 3 switch values
DEBOUNCE MOVWF TEMP ;
MOVLW DB_HI_BYTE ; This is the debounce delay
MOVF MSD, F ;
CLRF LSD ;
KB_D_LP1 DECFSZ LSD, F ;
GOTO KB_D_LP1 ;
DECFSZ MSD, F ;
GOTO KB_D_LP1 ;
END_DELAY MOVF PORTB, W ;
ANDLW 0xE0 ; Keep only the 3 switch values
SUBWF TEMP, F ;
BTFSS STATUS, Z ; Is the Zero bit set?
; (switches were the same on 2 reads)
GOTO DEBOUNCE ; NO, Try another read
KEY_MATCH MOVWF TEMP ; YES, need to see which is depressed.
;
MOVLW 0x80 ; Since doing key inputs, clear TMR1
MOVWF TMR1H ; for 1 sec overflow.
CLRF TMR1L ;
BCF PIR1, TMR1IF ; Clear Timer 1 Interrupt Flag
BTFSS TEMP, HR_MIN_SW ; Is the hour-min-off switch depressed?
GOTO SELECT_UNITS ; YES, specify the units selected
BTFSS TEMP, INC_SW ; Is the inc switch depressed?
GOTO INC_UNIT ; YES, Increment the selected Units
BTFSS TEMP, CLR_MIN_SW ; Is the clear minute switch depressed?
GOTO CLR_MIN ; YES, clear the minutes.
;
; No key match occured, or finished with PortB interrupt and need to clear interrupt condition.
;
CLR_RB ; No RB<7:5> keys are depressed (rising edge Int.)
MOVF PORTB, F ; Clear the PORTB mismatch condition
BCF INTCON, RBIF ; Clear the PORTB Int Flag
if ( Debug )
bcf PORTD, 0 ; Set low, use to measure total
; time in Int Service Routine
endif
RETFIE ; Return / Enable Global Interrupts
;
page
SELECT_UNITS
MOVLW 0xFF ;
MOVWF WAIT_CNTR ; WAIT_CNTR has LSb set after each SELECT UNIT key press.
INCF FLAG_REG, F ; Increment the pointer to the MIN_UNIT:HR_UNIT
BSF FLAG_REG, KEY_INPUT ;
GOTO DISPLAY ; Flash the Display of the selected unit
;
INC_UNIT
CLRF WAIT_CNTR ; WAIT_CNTR is cleared to zero after each key press.
BTFSC FLAG_REG, HR_UNIT ; Are the hour units selected?
GOTO INC_HRS ; YES, Increment the hour units
BTFSS FLAG_REG, MIN_UNIT ; Are the minute units selected?
GOTO CLR_RB ; NO, Not a valid key. Clear flags
;
INCF MIN, F ; YES, Increment the minute units
MOVLW 0x3C ; This is Decimal 60
SUBWF MIN, W ; MIN - 60 = ?
BTFSS STATUS, Z ; MIN = 60?
GOTO DISPLAY ; NO, display time
; YES, MIN = 0 (use code from CLR_MIN)
CLR_MIN CLRF MIN ; MIN = 0
MOVLW 0x04 ; Clear the seconds
MOVWF SECS ; Initial Second count = 4
MOVLW 0x80 ; Clear Timer 1, for 1 sec overflow
MOVWF TMR1H ;
CLRF TMR1L ;
BCF PIR1, TMR1IF ; Clear the TMR1 overflow interrupt.
CLRF WAIT_CNTR ; WAIT_CNTR is cleared to zero after each key press.
BTFSC TEMP, CLR_MIN_SW ; Is the clear minute switch depressed?
GOTO DISPLAY ; NO. Rollover from increment key
BCF FLAG_REG, MIN_UNIT ; YES, Clear ALL relevant flags
BCF FLAG_REG, HR_UNIT ;
BCF FLAG_REG, KEY_INPUT ;
GOTO DISPLAY ;
;
page
;
T1_OVRFL
BCF PIR1, TMR1IF ; Clear Timer 1 Interrupt Flag
BTFSS FLAG_REG, KEY_INPUT ; Are we using the key inputs?
GOTO INC_TIME ; NO, Need to Increment the time
INCF WAIT_CNTR, F ; YES,
MOVLW 0x0A ; 10 counts x 1 seconds
SUBWF WAIT_CNTR, W ; Has the 10 Sec wait for key expired?
BTFSS STATUS, Z ; Is the result 0?
GOTO DISPLAY ; NO, Display value
CLRF WAIT_CNTR ; YES, Clear WAIT_CNTR
BCF FLAG_REG, KEY_INPUT ;
BCF FLAG_REG, HR_UNIT ;
BCF FLAG_REG, MIN_UNIT ;
;
;
INC_TIME MOVLW 0x80 ;
MOVWF TMR1H ; 1 Second Overflow
INCF SECS, F ;
BTFSS SECS, 6 ;
GOTO DISPLAY ;
MOVLW 0x04 ;
MOVWF SECS ;
INCF MIN, F ;
MOVLW 0x3C ; W = 60d
SUBWF MIN, W ;
BTFSS STATUS, Z ;
GOTO DISPLAY ;
CLRF MIN ;
INC_HRS INCF HRS, F ;
MOVLW 0x0C ; It is now 12:00, Toggle AM / PM
SUBWF HRS, W ;
BTFSS STATUS, Z ;
GOTO CK_13 ; Need to check if HRS = 13
BTFSS FLAG_REG, AM ; Was it AM or PM
GOTO SET_AM ; Was PM, Needs to be AM
BCF FLAG_REG, AM ; It is PM
GOTO DISPLAY ;
SET_AM BSF FLAG_REG, AM ; It is AM
GOTO DISPLAY ;
CK_13 MOVLW 0x0D ; Check if HRS = 13
SUBWF HRS, W ;
BTFSS STATUS, Z ;
GOTO DISPLAY ;
CLRF HRS ;
INCF HRS, F ;
GOTO DISPLAY ;
;
page
INIT_DISPLAY
MOVLW DISP_ON ; Display On, Cursor On
CALL SEND_CMD ; Send This command to the Display Module
MOVLW CLR_DISP ; Clear the Display
CALL SEND_CMD ; Send This command to the Display Module
MOVLW ENTRY_INC ; Set Entry Mode Inc., No shift
CALL SEND_CMD ; Send This command to the Display Module
RETURN
;
DISPLAY
MOVLW DD_RAM_ADDR ;
CALL SEND_CMD ;
;
BTFSC FLAG_REG, KEY_INPUT ; Do we need to flash the selectected units?
GOTO FLASH_UNITS ; YES, we need to flash selected units
CALL LOAD_HRS ; NO, do a normal display
CALL LOAD_COLON ;
CALL LOAD_MIN ;
GOTO LOAD_AM ;
;
FLASH_UNITS
CLRF PCLATH ; This clears PCLATH, This table in 1st
MOVF FLAG_REG, W ; 256 bytes of program memory
ANDLW 0x03 ; only HR_UNIT and MIN_UNIT bit can be non-zero
UNIT_TBL
ADDWF PCL, F ; HR_UNIT:MIN_UNIT
GOTO NO_UNITS ; 0 0 - Display everything.
GOTO HR_UNITS ; 0 1 - Flash the hour units
GOTO MIN_UNITS ; 1 0 - Flash the minute units
UNIT_TBL_END
MOVLW 0xFC ; 1 1 - Need to clear FLAG_REG<HR_UNIT:MIN_UNIT>
ANDWF FLAG_REG, F ;
GOTO NO_UNITS ; 0 0 - Display everything.
;
if ( (UNIT_TBL & 0x0FF) >= (UNIT_TBL_END & 0x0FF) )
MESSG "Warning: Table UNIT_TBL crosses page boundry in computed jump"
endif
;
;
HR_UNITS
BTFSS WAIT_CNTR, 0 ; If WAIT_CNTR is odd,
; hour digits are displayed as blank
GOTO SKIP_BLK_HRS ;
MOVLW ' ' ;
CALL SEND_CHAR ;
MOVLW ' ' ;
CALL SEND_CHAR ;
SKIP_BLK_HRS
BTFSS WAIT_CNTR, 0 ; WAIT_CNTR was even, display hour digits
CALL LOAD_HRS ;
;
MOVLW ':' ; : always on, display all other character
CALL SEND_CHAR ;
CALL LOAD_MIN ;
GOTO LOAD_AM ;
;
page
MIN_UNITS
CALL LOAD_HRS ; Display hours
MOVLW ':' ; : always on
CALL SEND_CHAR ;
BTFSS WAIT_CNTR, 0 ; If WAIT_CNTR is odd,
; minute digits are displayed as blank
GOTO SKIP_BLK_MIN ;
MOVLW ' ' ;
CALL SEND_CHAR ;
MOVLW ' ' ;
CALL SEND_CHAR ;
SKIP_BLK_MIN
BTFSS WAIT_CNTR, 0 ; WAIT_CNTR was even, display minute digits
CALL LOAD_MIN ;
GOTO LOAD_AM ;
;
NO_UNITS
CALL LOAD_HRS ; Display all character
MOVLW ':' ;
CALL SEND_CHAR ;
CALL LOAD_MIN ;
GOTO LOAD_AM ;
;
LOAD_HRS
MOVF HRS, W ; Load the Wreg with the value
CALL BIN_2_BCD ; to convert to BCD
MOVF MSD, W ; Load the MSD value into the Wreg
CALL NUM_TABLE ; Get the ASCII code
CALL SEND_CHAR ; Send this Character to the Display
;
MOVF LSD, W ; Load the LSD value into the Wreg
CALL NUM_TABLE ; Get the ASCII code
CALL SEND_CHAR ; Send this Character to the Display
RETURN
;
LOAD_COLON MOVLW ' ' ; ASCII value for a Blank space
BTFSC SECS, 0 ; Is it an EVEN or ODD second
ADDLW ':' - ' ' ; Is ODD, Second colon is ON.
; Add delta offset of ASCII Characters
CALL SEND_CHAR ; Send this Character to the Display
RETURN
;
LOAD_MIN
MOVF MIN, W ; Load the Wreg with the value
CALL BIN_2_BCD ; to convert to BCD
MOVF MSD, W ; Load the MSD value into the Wreg
CALL NUM_TABLE ; Get the ASCII code
CALL SEND_CHAR ; Send this Character to the Display
;
MOVF LSD, W ; Load the LSD value into the Wreg
CALL NUM_TABLE ; Get the ASCII code
CALL SEND_CHAR ; Send this Character to the Display
RETURN
;
page
LOAD_AM MOVLW ' ' ; ASCII value for a Blank space
CALL SEND_CHAR ; Send this Character to the Display
MOVLW 'A' ; ASCII value for a Blank space
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -