; ****************************************************************************** ; 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 13:23, local time: 2024/9/1 10:27,
3.22.250.142:LOG IN
|
©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://techref.massmind.org/Techref/scenix/buttons_vp.src"> scenix buttons_vp</A> |
Did you find what you needed? |
Welcome to massmind.org! |
Welcome to techref.massmind.org! |
.