Dobrý deň,
potreboval by som pomoc s objasnením nasledovného programu na vykreslovanie LED hodín pomocou rotujúcich LEDiek na motorčeku.
;--------
; Noblink.asm
; mechanically scanned LED clock
; Original file mclock.asm
; display of seconds added
; turned off the blinking double dots
;
;--------
list p=16F84
radix hex
include "p16F84.inc"
;--------
; remember to set blast-time options: OSC=regular xtal, WDT=ON
; timings all based on 4 MHz crystal
;--------
w equ 0
f equ 1
;--------
; Start of available RAM.
;--------
cblock 0x0C
safe_w ;not really temp, used by interrupt svc
safe_s ;not really temp, used by interrupt svc
period_count ;incremented each interrupt
period_dup ;copy of period_count safe from interrupt
period_calc ;stable period after hysteresis calc.
period_use ;stable period after hysteresis calc.
flags ;b2=int b1=minute b4=edge b5=seconds
dot_index ;which column is being displayed
digit_index ;which digit is being displayed
hours ;in display format, not hex(01-12)
minutes ;00 to 59
seconds ;00 to 59
bigtick_dbl ;incremented each interrupt
bigtick_hi
bigtick_lo
sectick_hi
sectick_lo
keys ;key value
scratch ;scratch value
tick ;used by delay
endc
;--------
; Start of ROM
;--------
org 0x00 ;Start of code space
goto Start
;--------
; INTERRUPT SERVICE ROUTINE
;--------
org 0x04 ;interrupt vector
Intsvc movwf safe_w ;save w
swapf STATUS,w ;swap status, w
movwf safe_s ;save status(nibble swap, remember)
;--------
; done saving, now start working
;--------
; clear watchdog timer to ensure startup
clrwdt
;
; increment period count
; incf skip_cnt,f
; btfss STATUS,Z
; goto Bigticker
; movlw 0xfe ;play with this one for width of displayed characters
; movwf skip_cnt
incf period_count,f
btfsc STATUS,Z ;zero set means overflow
decf period_count,f
; 234375 interrupts every minute. Increment the bigtick each time.
Bigticker
incf bigtick_lo,f
btfsc STATUS,Z
incf bigtick_hi,f
btfsc STATUS,Z
incfsz bigtick_dbl,f
goto Bigtick_out
;--------
; here? bigtick has rolled over to zero and one minute has passed.
; reload bigtick and set a flag for the main counter
;--------
movlw 0xFC ;234375 = 0x039387
movwf bigtick_dbl ;0 - 0x039387 = 0xFC6C79
movlw 0x6C
movwf bigtick_hi
movlw 0x79
movwf bigtick_lo
bsf flags,1 ;notify Keep_time
Bigtick_out
;-------- now start with the seconds
incf sectick_lo,f
btfsc STATUS,Z
incfsz sectick_hi,f
goto Sectick_out
;--------
; here? sigtick has rolled over to zero and one second has passed.
; reload sectick and set a flag for the main counter
;--------
movlw 0xF0 ;3907 = 0x0F43
movwf sectick_hi ;0 - 0x0F43 = 0xF0BD
movlw 0xBD
movwf sectick_lo
bsf flags,5 ;notify Keep_time
Sectick_out
;--------
; done working, start restoring
;--------
swapf safe_s,w ;fetch status, reswap nibbles
movwf STATUS ;restore status
swapf safe_w,f ;swap nibbles in preparation
swapf safe_w,w ;for the swap restoration of w
bcf INTCON,2 ;clear interrupt flag before return
retfie ;return from interrupt
;--------
; CHARACTER LOOKUP TABLE
; ignore high bit. set=LED off, clear=LED on, bit0=bottom LED, bit6=top LED
;--------
Char_tbl
addwf PCL,f
dt 0xC1,0xBE,0xBE,0xBE,0xC1 ;"O"
dt 0xFF,0xDE,0x80,0xFE,0xFF ;"1"
dt 0xDE,0xBC,0xBA,0xB6,0xCE ;"2"
dt 0xBD,0xBE,0xAE,0x96,0xB9 ;"3"
dt 0xF3,0xEB,0xDB,0x80,0xFB ;"4"
dt 0x8D,0xAE,0xAE,0xAE,0xB1 ;"5"
dt 0xE1,0xD6,0xB6,0xB6,0xF9 ;"6"
dt 0xBF,0xB8,0xB7,0xAF,0x9F ;"7"
dt 0xC9,0xB6,0xB6,0xB6,0xC9 ;"8"
dt 0xCF,0xB6,0xB6,0xB5,0xC3 ;"9"
; dt 0xE0,0xDB,0xBB,0xDB,0xE0 ;"A"
; dt 0x80,0xB6,0xB6,0xB6,0xC9 ;"B"
; dt 0xC1,0xBE,0xBE,0xBE,0xDD ;"C"
; dt 0x80,0xBE,0xBE,0xBE,0xC1 ;"D"
; dt 0x80,0xB6,0xB6,0xBE,0xBE ;"E"
; dt 0x80,0xB7,0xB7,0xBF,0xBF ;"F"
dt 0xFF,0xFF,0xC9,0xFF,0xFF ;":"
Char_tbl_end
;--------
; SUBROUTINES STARTING HERE
;--------
; clear important bits of ram
;--------
Ram_init movlw 0x07
movwf keys
movlw 0x12 ;why do clocks always start
movwf hours ;at 12:00 ?
clrf minutes
clrf seconds
clrf dot_index
clrf digit_index
movlw 0xFC ;234375 = 0x039387
movwf bigtick_dbl ;0 - 0x039387 = 0xFC6C79
movlw 0x6C
movwf bigtick_hi
movlw 0x79
movwf bigtick_lo
movlw 0xF0 ;3907 = 0x0F43
movwf sectick_hi ;0 - 0x0F43 = 0xF0BD
movlw 0xBD
movwf sectick_lo
movlw 0x40
movwf period_calc
retlw 0
;--------
; unused pins I am setting to be outputs
;--------
Port_init movlw 0x00 ;all output, b7=unused
tris PORTB ;on port b attached to LEDs
movlw b'00010111' ;port a has 5 pins. I need 4 inputs
;b0=minutes, b1=10mins, b2=hours
;b3=unused, b4=rotation index
tris PORTA ;on port a
retlw 0
;--------
; get timer-based interrupts going
;--------
Timer_init bcf INTCON,2 ;clear TMR0 int flag
bsf INTCON,7 ;enable global interrupts
bsf INTCON,5 ;enable TMR0 int
clrf TMR0 ;clear timer
clrwdt ;why is this needed? just do it..
movlw b'11011000' ;set up timer. prescaler(bit3)bypassed
option ;send w to option. generate warning.
clrf TMR0 ;start timer
retlw 0
;--------
; test for index in rotation and store period in period_dup
;--------
Check_index movf PORTA,w ;get the state of port a
xorwf flags,w ;compare with saved state
andlw b'00010000' ;only interested in bit 4
btfsc STATUS,Z ;test for edge
retlw 0 ;not an edge, same as last
xorwf flags,f ;save for next time
btfsc flags,4 ;test for falling edge
retlw 0 ;must have been a rising edge
movf period_count,w ;make a working copy
movwf period_dup ;called period dup
clrf period_count ;a fresh start for next rotation
clrf digit_index ;set to first digit
clrf dot_index ;first column
; calculate a period that does not dither or jitter
; period will not be changed unless new period is really different
movf period_calc,w
subwf period_dup,w ;find difference
btfss STATUS,C ;carry flag set means no borrow
goto Calc_period_neg ;must be other way
sublw 2 ;allowable deviation = 3
btfss STATUS,C ;borrow won't skip
incf period_calc ;new value much larger than calc
movf period_calc,w
movwf period_use
bcf STATUS,C ;clear carry before a rotate
rrf period_use,f
bcf STATUS,C ;clear carry before a rotate
rrf period_use,f
retlw 0
Calc_period_neg addlw 2 ;allowable deviation = 3
btfss STATUS,C ;carry will skip
decf period_calc ;no carry means it must be changed
retlw 0
;--------
; change LED pattern based on state of digit_index and dot_index
;--------
Display_now movlw 0x05
xorwf dot_index,w ;test for end of digit
movlw 0xFF ;pattern for blank column
btfsc STATUS,Z
goto D_lookup_3 ;it needs a blank
bcf STATUS,C ;clear carry before a rotate
rlf digit_index,w ;double the index because each
addwf PCL,f ;takes two instructions
D_10hr swapf hours,w ;D_10hr
;swapf period_calc,w
goto D_lookup ;what a great rush of power
D_1hr movf hours,w ;I feel when modifying
;D_1hr movf period_calc,w ;I feel when modifying
goto D_lookup ;the program counter
D_colon movlw 0x0A ;the semicolon
goto D_lookup
D_10min swapf minutes,w
goto D_lookup
D_1min movf minutes,w
goto D_lookup
D_colon2 movlw 0x0A ;the semicolon
goto D_lookup
D_10sec swapf seconds,w
goto D_lookup
D_1sec movf seconds,w
goto D_lookup
D_nothing retlw 0
D_lookup andlw b'00001111' ;strip off hi bits
movwf scratch ;multiply this by 5 for lookup
addwf scratch,f ;table base position
addwf scratch,f ;is this cheating?
addwf scratch,f ;I think not.
addwf scratch,f ;I think it is conserving energy!
btfss STATUS,Z ;test for zero
goto D_lookup_2 ;not a zero
movf digit_index,f ;this is just to test/set flag
movlw 0xFF ;this makes a blank LED pattern
btfsc STATUS,Z ;test if it is 10 hrs digit
goto D_lookup_3 ;it's a leading zero
D_lookup_2 movf dot_index,w ;get column
addwf scratch,w ;add it to digit base
call Char_tbl ;get the dot pattern for this column
D_lookup_3 movwf PORTB ;send it to the LEDs
; movlw 0x2C ;overhead value sub from period
; subwf period_use,w ;compensate for overhead and set
movfw period_use
call Delay ;width of digits with this delay
incf dot_index,f ;increment to the next column
movlw 0x06 ;6 columns is a digit plus space
xorwf dot_index,w ;next digit test
btfss STATUS,Z
retlw 0 ;not a new digit
clrf dot_index ;new digit time
incf digit_index,f
retlw 0 ;Display_now done.
;--------
; a short delay routine
;--------
Delay movwf tick
Delay_loop decfsz tick,f
goto Delay_loop ;w is not damaged, so Delay can
return ;be recalled without reloading
;--------
; test for keypress and call time adjust if needed
;--------
Check_keys movf PORTA,w ;get port "a"
xorwf keys,w ;compare with previous
andlw b'00000111' ;only care about button pins
btfsc STATUS,Z ;zero set=no buttons
retlw 0 ;return
xorwf keys,f ;store key value
movlw 0x64 ;a fairly long delay will
movwf scratch ;prevent key bounces
Key_delay movlw 0xFF
call Delay
decfsz scratch
goto Key_delay
btfss keys,2 ;test "minutes" button
goto Inc_mins
btfss keys,1 ;test "tens" button
goto Inc_tens
btfss keys,0 ;test "hours" button
goto Inc_hours
retlw 0 ;must be a glitch. yeah, right!
;--------
; increment ten minutes
;--------
Inc_tens movlw 0x0A
movwf scratch ;scratch has ten
Inc_tens_loop call Inc_mins
decfsz scratch
goto Inc_tens_loop ;another minute added
retlw 0
;--------
; increment one hour
;--------
Inc_hours movlw 0x12
xorwf hours,w
btfsc STATUS,Z
goto Inc_hours_12
movlw 0x07 ;this part gets a little sloppy
addwf hours,w
movlw 0x07
btfss STATUS,DC
movlw 1
addwf hours,f
retlw 0
Inc_hours_12 movlw 0x01
movwf hours
retlw 0
;--------
; increment the time based on flags,1 as sent by interrupt routine
; Inc_mins loop also used by time-setting routine
;--------
Keep_time btfss flags,5 ;the minutes flag
goto Keep_time2 ;no change in seconds
bcf flags,5 ;clear the minutes flag
movlw 0x07 ;start incrementing time
addwf seconds,f ;add 7 seconds into f
movlw 0x06 ;'oops' decrementing time
btfsc STATUS,DC ;did adding 7 cause digit carry?
goto Keep_time2 ;then test for an hour change
subwf seconds,f ;dec 6 seconds into f
Keep_time2 btfss flags,1 ;the minutes flag
retlw 0 ;not this time
bcf flags,1 ;clear the minutes flag
clrf seconds ; clear the seconds & seconds timervalues
movlw 0xF0 ;3907 = 0x0F43
movwf sectick_hi ;0 - 0x0F43 = 0xF0BD
movlw 0xBD
movwf sectick_lo
Inc_mins movlw 0x07 ;start incrementing time
addwf minutes,w ;add 7 minutes into w
btfsc STATUS,DC ;did adding 7 cause digit carry?
goto Sixty_mins ;then test for an hour change