📄 picclock.asm
字号:
; Thermometer / clock
; Jan 2001
; LCD hookup on RB3 - RB0
; RS to ground
; RW on RB4
; Enable on RB5
; RA0 input on A/D
; RA1 output on A/D
; RA2 input for setting time
; RA3 input for entering time
; RA4 input for detecting charging
; RA7 output high to turn on LCD/temp
;
INCLUDE 'M16F62x.inc'
DEVICE PROTECT_OFF, WDT_OFF, PWRT_ON, BOD_OFF, MCLR_ON, LVP_OFF
DEVICE INTRC_OSC_NOCLKOUT
DEVICE PIC16F628
porta_buf equ 0x20
portb_buf equ 0x21
trisa_buf equ 0x22
trisb_buf equ 0x23
W_s equ 0x24
STATUS_s equ 0x25
LCD_data equ 0x26
LCD_Enable equ 5
LCD_RS equ 4
;LCD_RW equ tied to ground
TimeH equ 0x27
TimeM equ 0x28
TimeS equ 0x29
TimePos equ 7 ;position on screen where time is drawn
tempF equ 0x30
tempC equ 0x31
i equ 0x32
x equ 0x33 ;16 bit registers. high comes lower in ram
xlow equ 0x34
y equ 0x35
ylow equ 0x37
t equ 0x38
tlow equ 0x39
tempF_f equ 0x3a ;fractional portion of temperatures
tempC_f equ 0x3b
TempPos equ 0x40 + 4
TempPin equ 1 ;pin on port A to sample
waitcounter equ 0x3c ;file register for wait
DispTempEn equ 0x40 ;non-zero if enabled
org 0x0000
BCF INTCON, GIE
goto start
MOVLF macro LITERAL, FILE
movlw LITERAL
movwf FILE
ENDM
BSW macro LITERAL
iorlw (1<<LITERAL)
ENDM
BCW macro LITERAL
andlw ((0xff) ^ (1<<LITERAL))
ENDM
MODF macro FILE, LITERAL ;FILE mod LITERAL (doesn't work if file/literal > 1)
movf FILE, W ;move to working
MOD LITERAL
movwf FILE ;move back to register
ENDM
MOD macro LITERAL ; W mod LITERAL
addlw (256 - LITERAL) ;subtract literal
BTFSS STATUS, C ;if negative, add back
addlw LITERAL
ENDM
WAITMACRO MACRO LITERAL
movlw LITERAL
call wait
ENDM
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; interrupt handler
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
org 0x0004 ;interrupt handler
movwf W_s ;save context
swapf W_s, F
swapf STATUS, W
movwf STATUS_s
;main interrupt routine
movlw 0x80
addwf TMR1H ;use half of cycle
;handle time
incf TimeS
MODF TimeS, 60
BTFSS STATUS, Z
goto updatetime
;second overflow
incf TimeM
MODF TimeM, 60
BTFSS STATUS, Z
goto updatetime
;minutes overflow
incf TimeH
MODF TimeH, 24
updatetime call CheckPower
;bsf disptempen,7
btfss DispTempEn, 7 ;if zero, don't update
goto exit_int
movlf TimePos, LCD_Data
call MoveLCD
call DrawTime
movlw 11101111b
BSF STATUS, RP0
andwf TRISA
BCF STATUS, RP0
movlw 11101111b
andwf porta
movf timeS, w
andlw 1
addlw 1111b
andlw 10000b
iorwf PORTA
;handle temperature
movlf TempPos, LCD_Data
call MoveLCD
call sampleTemp
call DrawTempF
;exit interrupt
exit_int BCF PIR1,TMR1IF ;clear timer overflow
swapf STATUS_s, W
movf STATUS
swapf W_s, W
retfie
;;;;;;;;; start of program
start
MOVLW 0x07
MOVWF CMCON
movlf 00000000b,porta
bsf STATUS, rp0
movlf 11111111b, trisa
bcf STATUS, rp0
clrf DispTempEn
waitforpower WAITMACRO 20
;call CheckPower
call InitLCD
;btfss DispTempEn, 7
; goto waitforpower
;configure the LCD
;call InitLCD ;done in checkpower
;set display mode
;movlf 00000100b, LCD_Data
;call ModeLCD
;call set time routine
clrf DispTempEn
bsf DispTempEn, 4
clrf TimeH
clrf TimeM
clrf TimeS
clrf TempF
clrf TempF_f
clrf TempC
clrf TempC_f
;call SetTime
call ClearLCD
;configure timer interrupt
call InitTimer1 ;set up timer
call CheckPower ;see if it should stay powered up
stable sleep
goto stable
;;;;;;;;;;;;;;;;;;;;;
; subroutines
;;;;;;;;;;;;;;;;;;;;;
InitTimer1 movlw 0x80 ;only use half of cycle. otherwise would be too long of loop
movwf TMR1H ;
clrf TMR1L ;set initial value
movlw 00001110b ; 1:1 prescale, oscillator enabled, not synchronized, external clock, not enabled yet
movwf T1CON ;set timer1 control register
BSF INTCON, PEIE ; open up interrupts
bsf STATUS, rp0
BSF PIE1, TMR1IE
bcf STATUS, rp0
BSF INTCON, GIE
BSF T1CON, 0 ; start timer
return
Wait clrf waitcounter
incf waitcounterincf
btfss STATUS, Z
goto $ - 2
addlw 0xff ;ms to wait in W (approx)
btfss STATUS, Z
goto wait
return
LATCHLCD MACRO
movf portb_buf, w
BSW LCD_Enable
movwf portb
nop
clrw
addlw 1
btfss STATUS,Z
goto $ - 2
nop
BCW LCD_Enable
movwf portb
nop
nop
ENDM
;;; initiate LCD display
InitLCD BCF STATUS, RP1
BSF STATUS, RP0 ;bank 1
movlf 11000000b, TRISB ;bit mask for LCD output
BCF STATUS, RP0 ;bank 0
WAITMACRO 20
movlf 00000011b, portb_buf
LATCHLCD
WAITMACRO 5
movlf 00000011b, portb_buf
LATCHLCD
WAITMACRO 5
movlf 00000011b, portb_buf
LATCHLCD
WAITMACRO 5
movlf 00000010b, portb_buf
LATCHLCD
WAITMACRO 5
;set function byte 1
movlf 00000010b, portb_buf
LATCHLCD
WAITMACRO 2
;set function byte 0
movlf 00001000b, portb_buf
LATCHLCD
WAITMACRO 2
;clear display
movlf 00000000b, portb_buf
LATCHLCD
WAITMACRO 2
movlf 00001000b, portb_buf
LATCHLCD
WAITMACRO 1
;reset display
movlf 00000000b, portb_buf
LATCHLCD
WAITMACRO 2
movlf 00000001b, portb_buf
LATCHLCD
WAITMACRO 2
return
;;; clear display
ClearLCD
movlf 00000000b, portb_buf
LATCHLCD
WAITMACRO 1
movlf 00000001b, portb_buf
LATCHLCD
WAITMACRO 1
return
;;;; set display mode bits
; bit 2 - on/off
; bit 1 - cursor
; bit 0 - blink
ModeLCD movlf 00000000b, portb_buf
LATCHLCD
WAITMACRO 1
movlw 00000111b
andwf LCD_Data, W
iorlw 00001000b
movwf portb_buf
LATCHLCD
WAITMACRO 1
clrf portb_buf
clrf portb
return
;;; LCD_Data is sent as data
DataLCD swapf LCD_Data, W
andlw 00001111b
BSW LCD_RS
movwf portb_buf
LATCHLCD
WAITMACRO 1
movf LCD_Data, W
andlw 00001111b
BSW LCD_RS
movwf portb_buf
LATCHLCD
WAITMACRO 1
clrf portb_buf
clrf portb
return
;;;; Move to location
MoveLCD swapf LCD_Data, W
andlw 00000111b
iorlw 00001000b
movwf portb_buf
LATCHLCD
WAITMACRO 1
movf LCD_Data, W
andlw 00001111b
movwf portb_buf
LATCHLCD
WAITMACRO 1
clrf portb_buf
clrf portb
return
;;; draw temp at current location on LCD
DrawTempF movf TempF, W
movwf X
movlw 100
movwf Y
call Divide ;find 100s
movf X, w
btfsc STATUS, Z
movlw ( ' ' - '0' )
addlw '0'
movwf LCD_Data
Call DataLCD ;draw 100s digit
movf T, W ;use remander (10s and 1s
movwf X
movlw 10
movwf Y
Call Divide
movf X, W ;tens
addlw '0'
movwf LCD_Data
Call DataLCD
movf T, W
addlw '0' ;ones
movwf LCD_DATA
call DataLCD
movlw '.'
movwf LCD_DATA
Call DataLCD
movf TempF_f, W
addlw '0'
movwf LCD_Data
Call DataLCD
movlw 0xDF ;degree symbol
movwf LCD_Data
Call DataLCD
movlw 'F'
movwf LCD_Data
Call DataLCD
return
;;; draw time at current location on LCD
DrawTime
;draw hours
movf TimeH, W
MOD 12
btfsc STATUS, Z
movlw 12
;w contains hour number
movwf X
movlw 10
movwf Y
Call Divide
movf X, W ;move 10s to w
btfsc STATUS, Z ;if 0, then set to space
movlw (' ' - '0')
addlw '0' ;set to correct digit
movwf LCD_Data
Call DataLCD
movf T, W
addlw '0'
movwf LCD_Data
Call DataLCD
movlw ':'
movwf LCD_Data
Call DataLCD
;minutes
movf TimeM, W
movwf X
Call Divide ;divide by ten
movf X, W
addlw '0'
movwf LCD_Data
Call DataLCD
movf T, W
addlw '0'
movwf LCD_Data
Call DataLCD
movlw ':'
movwf LCD_Data
Call DataLCD
;seconds
movf TimeS, W
movwf X
Call Divide ;divide by ten
movf X, W
addlw '0'
movwf LCD_Data
Call DataLCD
movf T, W
addlw '0'
movwf LCD_Data
Call DataLCD
movlw ' '
movwf LCD_Data
Call DataLCD
movf TimeH, W
movwf X
movlw 12
movwf Y
Call Divide ;find am/pm
movlw 'a'
btfsc X, 0
movlw 'p'
movwf LCD_Data
call DataLCD
return
;;; get user input for time
SetTime clrf TimeS ;clear time
clrf TimeM
clrf TimeH
movlf 00000101b, LCD_Data
Call ModeLCD
clrf LCD_Data
Call MoveLCD
movlf TIMEMESSAGE, LCD_Data
Call MessageLCD
setH movlf TimePos + 0x40, LCD_Data
Call MoveLCD
Call DrawTime
movlf ( TimePos + 0x40 + 1 ), LCD_Data
Call MoveLCD
Call getIncrementSetTime
movwf X
addwf TimeH, W
MOD 24
movwf TimeH
Call WaitSecond
BTFSC X, 0
goto setH
setMh movlf TimePos + 0x40, LCD_Data
Call MoveLCD
Call DrawTime
movlf ( TimePos + 0x40 + 3 ), LCD_Data
Call MoveLCD
Call getIncrementSetTime
movwf X
BTFSC X, 0
movlw 10 ; add ten if was 1
addwf TimeM, W
MOD 60
movwf TimeM
Call WaitSecond
BTFSC X, 0
goto setMh
setM movlf TimePos + 0x40, LCD_Data
Call MoveLCD
Call DrawTime
movlf ( TimePos + 0x40 + 4 ), LCD_Data
Call MoveLCD
Call getIncrementSetTime
movwf X
addwf TimeM, W
MOD 60
movwf TimeM
Call WaitSecond
BTFSC X, 0
goto setM
setSh movlf TimePos + 0x40, LCD_Data
Call MoveLCD
Call DrawTime
movlf ( TimePos + 0x40 + 6 ), LCD_Data
Call MoveLCD
Call getIncrementSetTime
movwf X
BTFSC X, 0
movlw 10 ; add ten if was 1
addwf TimeS, W
MOD 60
movwf TimeS
Call WaitSecond
BTFSC X, 0
goto setSh
setS movlf TimePos + 0x40, LCD_Data
Call MoveLCD
Call DrawTime
movlf ( TimePos + 0x40 + 7 ), LCD_Data
Call MoveLCD
Call getIncrementSetTime
movwf X
addwf TimeS, W
MOD 60
movwf TimeS
Call WaitSecond
BTFSC X, 0
goto setS
movlf 00000100b, LCD_Data
Call ModeLCD
return
;;; wait one second
WaitSecond
WAITMACRO 250
WAITMACRO 250
WAITMACRO 250
WAITMACRO 250
return
;;; return 1 if pressed + button, and 0 if pressed enter
getIncrementSetTime
btfsc PORTA, 2
goto onehigh
btfsc PORTA, 3
goto zerohigh
goto getIncrementSetTime
onehigh WAITMACRO 50
btfsc PORTA, 2
retlw 1
goto getIncrementSetTime
zerohigh WAITMACRO 50
btfsc PORTA, 3
retlw 0
goto getIncrementSetTime
;;;; divide x by y into register x, remander in T
Divide
clrf T
movlw 8
movwf i
divtop bcf STATUS, C
rlf X, F
rlf T, F
movf Y, W
subwf T, W
btfsc STATUS, C
movwf T
btfsc STATUS, C
bsf X, 0
decfsz i
goto divtop
return
;;; more math
;;; add X:Xl + Y:Yl -> X:Xl
add16 clrf T ;hold carry if needed
movf Y+1, W
addwf X+1, F
btfsc STATUS, C
incf X
btfsc STATUS, C
incf T
movf Y, W
addwf X, F
movf T, W
iorwf STATUS ;status has C as 1 if carried.
return
add16m MACRO Xm, Ym
movf Ym+1, W
addwf Xm+1, F
btfsc STATUS, C
incf Xm
movf Ym, W
addwf Xm, F
ENDM
sub16 clrf T
movf Y+1, W
subwf X+1, F
btfss STATUS, C ;check for borrow
decf X ;was a borrow
btfss STATUS, C ;again
incf T ;T = 1 if borrow
movf Y, W
subwf X, F
movf T, W
xorwf STATUS ; if borrow occured once, C will be 0. else, 1. borrow can't happen twice
return
sub16m MACRO Xm, Ym
movf Ym+1, W
subwf Xm+1, F
btfsc STATUS, C
decf Xm
movf Ym, W
subwf Xm, F
ENDM
; x:x1 by y:y1 into t:t1:x:x1
mult16 clrf T ;32 bit result is T:Tl:X:Xl
clrf T+1
movlw 16 ;16 rounds
movwf i
loopmult16 btfss X+1, 0
goto noadd
add16m T, Y
noadd bcf STATUS, C
rrf T
rrf T+1
rrf X
rrf X+1
decfsz i
goto loopmult16
return
MOV16 MACRO Xm,Ym ;Xm <- Ym
movf Ym, W
movwf Xm
movf Ym+1, W
movwf Xm+1
ENDM
;;; get temperature
sampleTemp
movlw 11111101b ;1 is output, 0 is input
BSF STATUS, rp0
andwf TRISA
BCF STATUS, rp0
clrf T+1
movlf 16, T
clrf T+1
presampleloop movf porta, W
andlw 1
btfss STATUS, Z
bcf porta, 1 ;skip if 0
btfsc STATUS, Z
bsf porta, 1 ;skip if 1
nop
nop
nop
decfsz T+1
goto presampleloop
decfsz T
goto presampleloop
clrf X
clrf X+1
movlf 32, T ; 8192 samples
clrf T+1
;bcf porta, 1 ;output 0
;btfsc porta, 0 ;wait until 0
;goto $ - 1
;bsf porta, 1 ;output 1
;btfss porta, 0 ;wait until 1
;goto $ - 1
sampleloop movf porta, W
andlw 1
btfss STATUS, Z
bcf porta, 1 ;skip if 0
btfsc STATUS, Z
bsf porta, 1 ;skip if 1
addwf X+1, F
btfsc STATUS, C
incf X
decfsz T+1
goto sampleloop
decfsz T
goto sampleloop
;sensor measurement in x,x+1
movf X+1, W
movwf TempF
movlf 4, Y+1
clrf Y
call mult16 ;multiply by 4, so upper is 128 - 0 range.
;correction math
movlf 0, Y ; f(x) = 1.6445 * X - 48.402
movlf 156, Y + 1
call mult16
movf X, w
movwf X+1
movf T+1, w
movwf X
movlf 28, Y ; 29 and 84/256
movlf 229, Y + 1
call Add16
;now format
movf X, W
movwf TempF
movf x+1,w
movwf X
;range of 0 - 256, 16 interval.
movlf 26, Y ;divide lower by 26 to get 0-9 interval
call Divide
movf x,w
movwf TempF_f
;BSF STATUS, rp0
;clrf TRISA ;turn off output
;BCF STATUS, rp0
bcf PORTA, 1
return
CheckPower movf PORTA, W
andlw 10000000b
xorwf DispTempEn, w
btfsc STATUS, Z
return ;if zero, no change
xorwf DispTempEn, w
btfss STATUS, Z ;if not set...
goto displayon ;... turn on display...
displayoff movlw 10111111b
andwf PORTA
movlw 10111111b
bsf STATUS, RP0
andwf TRISA, F
movlw 11111111b
iorwf TRISB, F
bcf STATUS, RP0
clrf DispTempEn
return
displayon movlw 01000000b
iorwf PORTA, F
movlw 10111111b
bsf STATUS, RP0
andwf TRISA, F
bcf STATUS, RP0
movlw 01000000b
iorwf PORTA, F
call InitLCD
movlf 00000100b, LCD_Data
call ModeLCD
movlf 10000000b, DispTempEn
return
;;; displayable messages
TIMEMESSAGE equ 0
org 0x0400
getbyte addwf PCL, F ;message data follows
db "Enter current time:", 0
;;; draw message subroutine. message index in LCD_Data
MessageLCD clrf i
movlf 03h, PCLATH
movf LCD_Data, W
movwf i ;location to fetch from
messageloop movf i, W
incf i
call getbyte
addlw 0
btfsc STATUS, Z ;return when 0 in W
goto exitmessage
movwf LCD_DATA ; otherwise, display character
Call DataLCD
WAITMACRO 1
goto messageloop
exitmessage movlf 00h, PCLATH
return
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -