Scenix Buttons_vp.src
; ******************************************************************************
; Push Buttons & Path Switcher (with abbreviated real time clock)
;
;
; Length: >=74 bytes (depends upon number of buttons & clock type)
; Author: Craig Webb
; Written: 98/8/17
;
; This program implements a software time clock virtual peripheral
; that keeps a 16 bit count of elapsed time in milliseconds.
; The option is available to include seconds, minutes, hours and even
; days to this clock if desired.
; The code takes advantage of the SX's internal RTCC-driven interrupt
; to operate in the background while the main program loop is executing.
;
;******************************************************************************
;
;****** Assembler directives
;
; uses: SX28AC, 2 pages of program memory, 8 banks of RAM, high speed osc.
; operating in turbo mode, with 8-level stack & extended option reg.
;
DEVICE pins28,pages2,banks8,oschs
DEVICE turbo,stackx,optionx
ID 'Buttons' ;program ID label
RESET reset_entry ;set reset/boot address
;
;******************************* Program Variables ***************************
;
;****** Program Parameters
;
clock_type = 0 ;16 bit msec count only
;clock_type = 1 ;include sec, min, hours
;clock_type = 2 ;include day counter
;
num_buttons = 2 ;number of buttons (1-4)
;
;****** Program Constants
;
int_period = 163 ;period between interrupts
;
hold_bit = 4-(num_buttons/2) ;debounce period = 2^hold_bit msec
;
tick_lo = 80 ;50000 = msec instruction count
tick_hi = 195 ; for 50MHz, turbo, prescaler=1
;
mspersec_hi = 1000/256 ;msec per second hi count
mspersec_lo = 1000-(mspersec_hi*256) ;msec per second lo count
;
;****** Port definitions
;
button0 EQU RB.0 ;Push button 0
button1 EQU RB.1 ;Push button 1
button2 EQU RB.2 ;Push button 2
button3 EQU RB.3 ;Push button 3
;
;****** Register definitions
;
ORG 8 ;start of program registers
main = $ ;main bank
;
temp DS 1 ;temporary storage
temp2 DS 1
;
ORG 010H ;bank0 variables
clock EQU $ ;clock bank
buttons EQU $ ;push button bank
;
time_base_lo DS 1 ;time base delay (low byte)
time_base_hi DS 1 ;time base delay (high byte)
msec_lo DS 1 ;millisecond count (low)
msec_hi DS 1 ;millisecond count (high)
IF clock_type>0 ;do we want sec, min, hours?
seconds DS 1 ;seconds count
minutes DS 1 ;minutes count
hours DS 1 ;hours count
ENDIF
IF clock_type>1 ;do we want day count?
days DS 1 ;days count
ENDIF
;
;
debounce0 DS 1 ;push button 0 debounce count
debounce1 DS 1 ;push button 1 debounce count
debounce2 DS 1 ;push button 2 debounce count
debounce3 DS 1 ;push button 3 debounce count
pbflags DS 1 ;push button status flags
pb0_pressed EQU pbflags.0 ;push button 0 action status
pb1_pressed EQU pbflags.1 ;push button 1 action status
pb2_pressed EQU pbflags.2 ;push button 2 action status
pb3_pressed EQU pbflags.3 ;push button 3 action status
pb0_down EQU pbflags.4 ;push button 0 down status
pb1_down EQU pbflags.5 ;push button 1 down status
pb2_down EQU pbflags.6 ;push button 2 down status
pb3_down EQU pbflags.7 ;push button 3 down status
;
;*************************** INTERRUPT VECTOR ******************************
;
; Note: The interrupt code must always originate at 0h.
; A jump vector is not needed if there is no program data that needs
; to be accessed by the IREAD instruction, or if it can all fit into
; the lower half of page 0 with the interrupt routine.
;
ORG 0 ;interrupt always at 0h
; JMP interrupt ;interrupt vector
;
;**************************** INTERRUPT CODE *******************************
;
; Note: Care should be taken to see that any very timing sensitive routines
; (such as adcs, etc.) are placed before other peripherals or code
; which may have varying execution rates (like the software clock, for
; example).
;
interrupt ;beginning of interrupt code
;
;****** Virtual Peripheral: Time Clock
;
; This routine maintains a real-time clock count (in msec) and allows processing
; of routines which only need to be run once every millisecond.
;
; Input variable(s) : time_base_lo,time_base_hi,msec_lo,msec_hi
; seconds, minutes, hours, days
; Output variable(s) : msec_lo,msec_hi
; seconds, minutes, hours, days
; Variable(s) affected : time_base_lo,time_base_hi,msec_lo,msec_hi
; seconds, minutes, hours, days
; Flag(s) affected :
; Size : 17/39/45 bytes (depending upon clock type)
; + 1 if bank select needed
; Timing (turbo) : [99.9% of time] 14 cycles
; [0.1% of time] 17/39/45 cycles (or less)
; + 1 if bank select needed
;
; BANK clock ;select clock register bank
MOV W,#int_period ;load period between interrupts
ADD time_base_lo,W ;add it to time base
SNC ;skip ahead if no underflow
INC time_base_hi ;yes overflow, adjust high byte
MOV W,#tick_hi ;check for 1 msec click
MOV W,time_base_hi-W ;Is high byte above or equal?
MOV W,#tick_lo ;load instr. count low byte
SNZ ;If hi byte equal, skip ahead
MOV W,time_base_lo-W ;check low byte vs. time base
SC ;skip ahead if low
;commented out because of path_switcher/pushbutton routines which use msec count
; JMP :done_clock ;If not, end clock routine
JMP done_pbs ;If not, end clock routine
:got_tick CLR time_base_hi ;Yes, adjust time_base reg.'s
SUB time_base_lo,#tick_lo ; leaving time remainder
INCSZ msec_lo ;And adjust msec count
DEC msec_hi ; making sure to adjust high
INC msec_hi ; byte as necessary
IF clock_type>0 ;do we want sec, min, hours?
MOV W,#mspersec_hi ;check for 1000 msec (1 sec tick)
MOV W,msec_hi-W ;Is high byte above or equal?
MOV W,#mspersec_lo ;load #1000 low byte
SNZ ;If hi byte equal, skip ahead
MOV W,msec_lo-W ;check low byte vs. msec count
SC ;skip ahead if low
JMP :done_clock ;If not, end clock routine
INC seconds ;increment seconds count
CLR msec_lo ;clear msec counters
CLR msec_hi ;
MOV W,#60 ;60 seconds per minute
MOV W,seconds-W ;are we at minute tick yet
JNZ :done_clock ;if not, jump
INC minutes ;increment minutes count
CLR seconds ;clear seconds count
MOV W,#60 ;60 minutes/hour
MOV W,minutes-W ;are we at hour tick yet?
JNZ :done_clock ;if not, jump
INC hours ;increment hours count
CLR minutes ;clear minutes count
ENDIF ;<if> we wanted sec, min, hours
IF clock_type>1 ;do we want to count days?
MOV W,#24 ;24 hours per day
MOV W,hours-W ;are we at midnight?
JNZ :done_clock ;if not, jump
INC days ;increment days count
CLR hours ;clear hours count
ENDIF ;<if> we wanted day count
:done_clock
;
;****** Virtual Peripheral: Path Switch
;
; This routine allows alternating execution of multiple modules which don't
; need to be run during every interrupt pass in order to reduce the overall
; execution time of the interrupt on any given pass (i.e. it helps the code
; run faster).
; This version runs with the software clock virtual peripheral msec_lo variable
; allowing altenation between the switch positions once each millisecond.
;
; Input variable(s) : msec_lo
; Output variable(s) :
; Variable(s) affected :
; Flag(s) affected :
; Size : 3 bytes + 1 bytes per jump location
; Timing (turbo) : 8 cycles
;
:path_switch MOV W,msec_lo ;load switch selector byte
AND W,#00000011b ;keep low 2 bits - 4 position
JMP PC+W ;jump to switch position pointer
:pos0 JMP pb0 ;pushbutton 0 checking routine
:pos1 JMP pb1 ;pushbutton 1 checking routine
:pos2 JMP pb2 ;pushbutton 2 checking routine
:pos3 JMP pb3 ;pushbutton 3 checking routine
;
;
;****** Virtual Peripheral: Push Buttons*
;
; This routine monitors any number of pushbuttons, debounces them properly
; as needed, and flags the main program code as valid presses are received.
; *Note: this routine requires the Time Clock virtual peripheral or similar
; pre-processing timer routine.
;
; Input variable(s) : pb0_down,pb1_down,debounce0,debounce1
; pb2_down,pb3_down,debounce2,debounce3
; Output variable(s) : pb0_pressed, pb1_pressed, pb2_pressed, pb3_pressed
; Variable(s) affected : debounce0, debounce1, debounce2, debounce3
; Flag(s) affected : pb0_down,pb1_down,pb0_pressed,pb1_pressed
; pb2_down,pb3_down,pb2_pressed,pb3_pressed
; Size : 12 bytes per pushbutton + actions (see below**)
; + 1 byte if path switch not used
; Timing (turbo) : 7,10, or 12 cycles/pushbutton (unless path switch used)
; + actions (see below**)
;
pb0
; BANK buttons ;select bank (if not done elsewhere)
JB button0,:pb0_up ;button0 pressed?
JB pb0_down,:done_pb0 ;yes, but is it new press?
INC debounce0 ; and adjust debounce count
JNB debounce0.hold_bit,:done_pb0 ;wait till long enough
SETB pb0_down ;yes, flag that button is down
;**If the button activity is short (a few bytes), it can fit here, though be
; careful that longest possible interrupt doesn't exceed int_period # of cycles.
;
; <short code segment can go here>
;
;**Otherwise, use this flag to process button press in main code (and don't
; forget to reset the flag once the button activity is complete).
SETB pb0_pressed ; and set pb0 action flag
SKIP ;skip next instruction
:pb0_up CLRB pb0_down ;button up, clear flag
CLR debounce0 ; and clear debounce count
:done_pb0
;
JMP done_pbs ;this needed only if path switch used
pb1
IF num_buttons>1 ;more than 1 push button?
; BANK buttons ;do bank select (if not done elsewhere)
JB button1,:pb1_up ;button1 pressed?
JB pb1_down,:done_pb1 ;yes, but is it new press?
INC debounce1 ; and adjust debounce count
JNB debounce1.hold_bit,:done_pb1 ;wait till long enough
SETB pb1_down ;yes, flag that button is down
;**If the button activity is short (a few bytes), it can fit here, though be
; careful that longest possible interrupt doesn't exceed int_period # of cycles.
;
; <short code segment can go here>
;
;**Otherwise, use this flag to process button press in main code (and don't
; forget to reset the flag once the button activity is complete).
SETB pb1_pressed ; and set pb1 action flag
SKIP ;skip next instruction
:pb1_up CLRB pb1_down ;button up, clear flag
CLR debounce1 ; and clear debounce count
:done_pb1
;
JMP done_pbs ;this needed only if path switch used
ENDIF ;more than 1 push button
pb2
IF num_buttons>2 ;more than 2 push buttons?
; BANK buttons ;do bank select (if not done elsewhere)
JB button2,:pb2_up ;button2 pressed?
JB pb2_down,:done_pb2 ;yes, but is it new press?
INC debounce2 ; and adjust debounce count
JNB debounce2.hold_bit,:done_pb2 ;wait till long enough
SETB pb2_down ;yes, flag that button is down
;**If the button activity is short (a few bytes), it can fit here, though be
; careful that longest possible interrupt doesn't exceed int_period # of cycles.
;
;**Otherwise, use this flag to process button press in main code (and don't
; orget to reset the flag once the button activity is complete).
SETB pb2_pressed ; and set pb2 action flag
SKIP ;skip next instruction
:pb2_up CLRB pb2_down ;button up, clear flag
CLR debounce2 ; and clear debounce count
:done_pb2
;
JMP done_pbs ;this needed only if path switch used
ENDIF ;more than 2 push buttons
pb3
IF num_buttons>2 ;more than 3 push buttons?
; BANK buttons ;do bank select (if not done elsewhere)
JB button3,:pb3_up ;button3 pressed?
JB pb3_down,:done_pb3 ;yes, but is it new press?
INC debounce3 ; and adjust debounce count
JNB debounce3.hold_bit,:done_pb3 ;wait till long enough
SETB pb3_down ;yes, flag that button is down
;**If the button activity is short (a few bytes), it can fit here, though be
; careful that longest possible interrupt doesn't exceed int_period # of cycles.
;
;**Otherwise, use this flag to process button press in main code (and don't
; forget to reset the flag once the button activity is complete).
SETB pb3_pressed ; and set pb3 action flag
SKIP ;skip next instruction
:pb3_up CLRB pb3_down ;button up, clear flag
CLR debounce3 ; and clear debounce count
:done_pb3
ENDIF ;more than 3 push buttons
;
done_pbs
;
done_int mov w,#-int_period ;interrupt every 'int_period' clocks
retiw ;exit interrupt
;
;****** End of interrupt sequence
;
;************************** RESET ENTRY POINT *****************************
;
reset_entry
; PAGE start ;Set page bits and then
; JMP start ; jump to start of code
;
;*********************
;* Main Program Code *
;*********************
;
start mov !rb,#%00001111 ;Set RB in/out directions
CLR FSR ;reset all ram starting at 08h
:zero_ram SB FSR.4 ;are we on low half of bank?
SETB FSR.3 ;If so, don't touch regs 0-7
CLR IND ;clear using indirect addressing
IJNZ FSR,:zero_ram ;repeat until done
MOV !OPTION,#%10011111 ;enable rtcc interrupt
;
Main:loop
;
;the following code watches pb0-pb3 for presses and acts on them
button_check
; BANK buttons ;select pb bank
MOV W,pbflags ;load pushbutton flags
AND W,#00001111b ;keep only 'pressed' flags
JZ :no_press ;jump ahead if not pressed
MOV temp,W ;store flags temporarily
CLR temp2 ;clear 2nd temp storage reg.
:which_pb INC temp2 ;increment 2nd temp value
RR temp ;check which button
SC ;skip ahead if not this one
JMP :which_pb ;keep looping
MOV W,--temp2 ;get 2nd temp value (less 1)
MOV temp,W ;save it in temp
MOV W,#11110000b ;get clear mask for pbflags
AND pbflags,W ;clear all "pressed" flags
MOV W,temp ;get which button pressed
JMP PC+W ;Go do PB routines
:pb0 JMP pb0_action ;do pb0 action
:pb1 JMP pb1_action ;do pb1 action
:pb2 JMP pb2_action ;do pb2 action
:pb3 JMP pb3_action ;do pb3 action
:no_press
;
; <main program code goes here>
;
JMP Main:loop ;back to main loop
;
pb0_action
;
; <pb0 action here>
;
JMP Main:loop
;
pb1_action
;
; <pb1 action here>
;
JMP Main:loop
;
pb2_action
;
; <pb2 action here>
;
JMP Main:loop
;
pb3_action
;
; <pb3 action here>
;
JMP Main:loop
;
;***************
END ;End of program code
file: /Techref/scenix/buttons_vp.src, 14KB, , updated: 1999/2/20 12:23, local time: 2024/11/20 01:13,
|
| ©2024 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://linistepper.com/Techref/scenix/buttons_vp.src"> scenix buttons_vp</A> |
Did you find what you needed?
|