#### Forth code // /////////////////////////////////////////////////////////////////////////// // Key debouncing, runs at 2 ms rate approx. : hooked to timer 3 // State definitions for InputStates[ n] %00000000 constant instInactive #// inactive %01000000 constant instActivating #// inactive - going active %10000000 constant instActive #// active %11000000 constant instDeactivating #// active - going inactive %11000000 constant instStateMask %00111111 constant instCountMask 25 constant instDebounceCount #// Initial debounce counter value, 25 -> 50 ms // Setup bit definitions for debounce inputs 0 // Zero masks counted sofar 1 + $01 constant mskTest #// Test 1 + $02 constant mskMenuKey #// Menu key 1 + $04 constant mskUpKey #// UP key 1 + $08 constant mskDownKey #// Down key 1 + $10 constant mskSrvKey #// Service key constant InputCount #// Number of masks defined above group #// Keep all tm3 related vars grouped InputCount array InputStates #// Array of input states / counters variable t3Counter #// For debouncing variable t3State #// For debouncing variable t3InpStatus #// For debouncing variable InpStatus #// For debouncing endGroup // Define an inversion mask for inputs mskTest False And // Test input inverts not mskMenuKey True And Or // Menu key inverts mskUpKey True And Or // UP key inverts mskDownKey True And Or // Down key inverts mskSrvKey True And Or // Service key inverts constant invMask // //////////////////////////////////////////////////////////////////////////// ### NOTE <@" xxxx"> is used to access xxxx 4th ssymbol from assembly ### Pin_xxx and Port_xxx are defined elsewhere in a HW setup file code _CollectRawInputs ( b1 -- b2 ) // Interrupt code, don't call from forth directly ; // Collect pins according to mask's and inv's into wreg. clrf wreg ; // Assume all inputs are zero btfsc <@" Port_NOT_MENU_KEY">, <@" Pin_NOT_MENU_KEY"> iorlw <@" mskMenuKey"> btfsc <@" Port_NOT_UP_KEY">, <@" Pin_NOT_UP_KEY"> iorlw <@" mskUpKey"> btfsc <@" Port_NOT_DOWN_KEY">, <@" Pin_NOT_DOWN_KEY"> iorlw <@" mskDownKey"> btfsc <@" Port_TEST_MODE">, <@" Pin_TEST_MODE"> iorlw <@" mskTest"> btfsc <@" Port_SRV_KEY">, <@" Pin_SRV_KEY"> iorlw <@" mskSrvKey"> xorlw <@" invMask"> ; // Invert inputs as specified in invMask return ; // Done endCode #### snippet from timer interrupt ; // Process input status from t3InpStatus to InpStatus ; // States : an array of 4 states ; // ; // xxcccccc ; // |||||||| ; // ||++++++-- 6 bit counter ; // ++-------- 2 bit state ; // ; // 00 inactive ; // 01 activating ; // 10 active ; // 11 deactivating ; ; // t3State : state for current input ; // t3Counter : loop counter call <@" _CollectRawInputs"> ; // Get physical inputs into wreg bits 5 .. 0 movwf <@" t3InpStatus"> ; // into t3InpStatus movlw <@" InputCount"> ; // number of inputs to process movwf <@" t3Counter"> AddressToFsr0 <@" InputStates"> ; // Set up pointer into state array t3_lp ; // Process an input movf indf0, w ; // Get current state into t3State andlw <@" instStateMask"> movwf <@" t3State"> ; // dispatch on current state movlw <@" instInactive"> cpfseq <@" t3State"> ; // S/ state = instInactive goto t3_test_activating ; // B/ test next ; // ===================== ; // State == instInactive btfss <@" t3InpStatus">, 0 ; // S/ physical input is active goto t3_next ; // B/ physical input is not active movlw <@" instDebounceCount"> + <@" instActivating"> ; // Setup new state + debounce counter movwf indf0 ; // Set it into position goto t3_next ; // B/ process next t3_test_activating movlw <@" instActivating"> cpfseq <@" t3State"> goto t3_test_active ; // ======================= ; // State == instActivating btfss <@" t3InpStatus">, 0 ; // S/ physical input is active goto t3_actinginact ; // B/ not active ; // physical input still active movf indf0, w ; // Get counter andlw <@" instCountMask"> decfsz wreg, f ; // S/ Counter = 0 goto t3_actnz ; // B/ Counter not zero ; // Debounce counter zero, advance state movlw <@" instActive"> movwf indf0 goto t3_next ; // B/ process next t3_actnz iorlw <@" instActivating"> ; // Write back decremented counter movwf indf0 goto t3_next ; // B/ process next t3_actinginact ; // physical input not active anymore, reset state movlw <@" instInActive"> movwf indf0 goto t3_next ; // B/ process next t3_test_active movlw <@" instActive"> cpfseq <@" t3State"> goto t3_test_deactivating ; // =================== ; // State == instActive btfsc <@" t3InpStatus">, 0 ; // S/ physical input is inactive goto t3_next ; // B/ physical input is not inactive movlw <@" instDebounceCount"> + <@" instDeactivating"> ; // Setup new state + debounce counter movwf indf0 ; // Set it into position goto t3_next ; // B/ process next t3_test_deactivating movlw <@" instDeactivating"> cpfseq <@" t3State"> goto t3_test_error ; // ========================= ; // State == instDeactivating btfsc <@" t3InpStatus">, 0 ; // S/ physical input is inactive goto t3_inactingact ; // B/ not inactive ; // physical input still inactive movf indf0, w ; // Get counter andlw <@" instCountMask"> decfsz wreg, f ; // S/ Counter = 0 goto t3_inactnz ; // B/ Conter not zero ; // Debounce counter zero, advance state movlw <@" instInActive"> movwf indf0 goto t3_next ; // B/ process next t3_inactnz iorlw <@" instDeactivating"> ; // Write back decremented counter movwf indf0 goto t3_next ; // B/ process next t3_inactingact ; // physical input not inactive anymore, set back state movlw <@" instActive"> movwf indf0 goto t3_next ; // B/ process next t3_test_error ; // ================ ; // State == INVALID clrf indf0 ; // in case of error clear all state t3_next ; // Setup InpStatus based upon current state bsf <@" InpStatus">, <@" InputCount"> ; // Assume active btfss indf0, 7 ; // S/ bit 7 set -> active bcf <@" InpStatus">, <@" InputCount"> ; // Assumption was wrong, correct it ; // Keep loop invariant ok incf fsr0l, f ; // Advance pointer bcf Status, c rrcf <@" t3InpStatus">, f ; // And bring next bit into position bcf Status, c rrcf <@" InpStatus">, f ; // And bring next bit into position ; // Check for more work to do decfsz <@" t3Counter">, f ; // more inputs to do ? goto t3_lp ; // B/ yes ; // Done, fall through ### end snippet from timer interrupt ### and more forth code // //////////////////////////////////////////////////////////////////////////// // Helper functions - debounced input checking : InpStatus@ ( -- b ) InpStatus @ ; // //////////////////////////////////////////////////////////////////////////// : InpTest ( bMask -- f ) InpStatus@ And 0<> ; // //////////////////////////////////////////////////////////////////////////// // Exported code - debounced input checkers : TestActive? ( -- f ) mskTest InpTest ; // //////////////////////////////////////////////////////////////////////////// : MenuKeyActive? ( -- f ) mskMenuKey InpTest ; // //////////////////////////////////////////////////////////////////////////// : UpKeyActive? ( -- f ) mskUpKey InpTest ; // //////////////////////////////////////////////////////////////////////////// : DownKeyActive? ( -- f ) mskDownKey InpTest ; // //////////////////////////////////////////////////////////////////////////// : SrvKeyActive? ( -- f ) mskSrvKey InpTest ;