di2831l1.txt ;**************************************************************************************************** ; MICROCONTROLLER SOFTWARE ; ; "Low-power keypad consumes only 100 nA," EDN, Jan 24, 2002, pg 86 ; ;************************************************************************************************** #include "msp430x12x.h" ;****************************************************************************** ; M. Mitchell ; Texas Instruments, Inc ; October, 2001 ;****************************************************************************** RSEG CSTACK ; System stack DS 0 ;****************************************************************************** RSEG UDATA0 ; RAM Locations ;****************************************************************************** NoKey EQU 01h NoMatch EQU 02h Error_Flags DS 1 ; Error Flags ; xxxx xxxx ; || ; ||-- No Key being depressed ; |----- No key match found ;****************************************************************************** RSEG CODE ; Program code ;****************************************************************************** Reset mov #SFE(CSTACK),SP ; Initialize stackpointer SetupWDT mov #WDTPW+WDTHOLD,&WDTCTL ; Stop WDT SetupPorts mov.b #0F8h,&P1DIR ; Unused P1.x as Outputs mov.b #0FFh,&P2DIR ; Unused P2.x as outputs mov.b #0FFh,&P3DIR ; All P3.x as outputs eint ; Enable Interrupts SetupDCO mov.b #0,&BCSCTL1 ; Set Rsel=0, leave DCO=3 ; This gives nom MCLK of ; 130KHz at 3V, 25C. Mainloop call #Set_For_Press ; Setup to wait for key press bis #LPM4,SR ; Wait for key press call #Debounce ; Call debounce delay call #KeyScan ; Scan Keypad bit.b #NoKey,Error_Flags ; Test if no key was depressed jnz Mainloop ; False interrupt, no key pressed call #KeyLookup ; Lookup Key value call #Wait_For_Release ; Wait for key(s) to be released jmp Mainloop ; ;------------------------------------------------------------------------------ Set_For_Press ; Setup to wait for key press ;------------------------------------------------------------------------------ bis.b #BIT0+BIT1+BIT2+BIT3,&P3OUT ; Enable keypad bic.b #BIT0+BIT1+BIT2,&P1IES ; L-to-H interrupts clr.b &P1IFG ; Clear any pending flags mov.b #BIT0+BIT1+BIT2,&P1IE ; Enable interrupts clr.b Error_Flags ; Clear error flags ret ;------------------------------------------------------------------------------ Debounce ; Debounce Delay Routine ;------------------------------------------------------------------------------ SetupTA mov #TASSEL1+TACLR,&TACTL ; SMCLK, Clear TA mov #CCIE,&TACCTL0 ; Enable CCR0 interrupt mov #5125,&TACCR0 ; Value for typ delay of ~40mS bis #MC0,&TACTL ; Start TA in up mode bis #LPM0,SR ; Sleep during debounce delay ret ; Return ;------------------------------------------------------------------------------ KeyScan ; Keypad Routine ;------------------------------------------------------------------------------ #define KeyMask R15 #define LoopCount R14 #define KeyHex R13 #define KeyVal R5 mov #1,KeyMask ; Initialize scan mask mov #4,LoopCount ; Initialize loop counter clr KeyHex ; Clear register bic.b #07h,&P1OUT ; Clear column bits in P1OUT reg Scan_1 bic.b #0Fh,&P3OUT ; Stop driving rows bis.b #07h,&P1DIR ; Set column pins to output and low bic.b #07h,&P1OUT ; To bleed off charge and avoid ; erroneous reads bic.b #07H,&P1DIR ; Set column pins back to input Mov.b KeyMask,&P3OUT ; Drive row bit.b #7h,&P1IN ; Test if any key pressed jz Scan_2 ; No key pressed bis.b KeyMask,KeyHex ; If yes, set bit for row mov.b &P1IN,R12 ; Read column inputs and.b #07h,R12 ; Clear unused bits rla.b R12 ; rla.b R12 ; Rotate column bit rla.b R12 ; rla.b R12 ; bis.b R12,KeyHex ; Set column bit in KeyHex Scan_2 rla.b KeyMask ; Rotate mask dec LoopCount ; Decrement counter jnz Scan_1 ; Continue scanning if not done ; Check to see if any key is being pressed. If not, set flag and return. tst.b KeyHex ; Test KeyHex jnz EndScan ; If not 0 return bis.b #NoKey,Error_Flags ; Set flag EndScan bis.b #0Fh,&P3OUT ; Drive rows again ret ;------------------------------------------------------------------------------ KeyLookup ; Table look-up to determine what key was pressed. ;------------------------------------------------------------------------------ mov #10,KeyVal ; Initial key value LookLoop cmp.b Key_Tab(R5),KeyHex ; Compare jeq EndLU ; If equal end look-up dec KeyVal ; decrement pointer/counter jnz LookLoop ; Continue until find key or ; count to zero. EndError ; If get here, Did not find match, so more than one key is pressed. ; return error condition bis.b #NoMatch,Error_Flags ; Set Error Flag ret ; Return EndLU ; Done with Key look-up - found key successfully. dec KeyVal ; Adjust because using same ; register for key counter ; and table pointer ; --> The key that was pressed is now in R5. The applicaion ; can now move it for furthur handling, display, etc. ; This example doesn't actually do anything with the key information. ret ;------------------------------------------------------------------------------ Wait_For_Release ; Setup to wait for key release ;------------------------------------------------------------------------------ ; Isolate one row that is in use mov.b #1,R11 ; row counter L$1 and.b #0Fh,KeyHex ; And off column info in KeyHex rrc KeyHex ; Rotate row info through C jc proceed ; Looking for a '1' rla R11 ; Shift to next bit and jmp L$1 ; continue looking proceed inv.b R11 ; Invert and #0Fh,R11 ; Clear upper bits bic.b R11,&P3OUT ; Turn off all but one row ; Setup for interrupt on key release bis.b #07h,&P1DIR ; Set column pins to output and low bic.b #07h,&P1OUT ; To bleed off charge and avoid ; erroneous reads bic.b #07H,&P1DIR ; Set column pins back to input bis.b #07h,&P1IES ; H-L Interrupts clr.b &P1IFG ; Clear any pending flags bis.b #07h,&P1IE ; Enable Interrupts bis #LPM4,SR ; Sleep waiting for release Call #Debounce ; Debounce release of key call #KeyScan ; Scan keypad again bit.b #NoKey,Error_Flags ; Test if any key pressed jz Wait_For_Release ; If so, repeat End_Wait bic.b #NoKey,Error_Flags ; Clear flag ret ; Return ;------------------------------------------------------------------------------ P1ISR ; P1.x Interrupt service Routine ;------------------------------------------------------------------------------ bic #LPM4,0(SP) ; Return active clr.b &P1IFG ; Clear interrupt flag clr.b &P1IE ; Disable furthur P1 interrupts reti ;------------------------------------------------------------------------------ CCR0_ISR ; CCR0 Interrupt Service Routine ;------------------------------------------------------------------------------ bic #LPM0,0(SP) ; Return Active mov #TACLR,&TACTL ; Stop and clear TA clr &TACCTL0 ; Clear CCTL0 register reti ;------------------------------------------------------------------------------ Key_Tab ; Key look-up table ;------------------------------------------------------------------------------ DB 00h ; Dummy value. Allows use of same register for ; both table pointer and key counter DB 028h ; '0' key DB 011h ; '1' key DB 021h ; '2' key DB 041h ; '3' key DB 012h ; '4' key DB 022h ; '5' key DB 042h ; '6' key DB 014h ; '7' key DB 024h ; '8' key DB 044h ; '9' key ;------------------------------------------------------------------------------ COMMON INTVEC ; Interrupt vectors ;------------------------------------------------------------------------------ ORG RESET_VECTOR DW Reset ORG TIMERA0_VECTOR DW CCR0_ISR ORG PORT1_VECTOR DW P1ISR ;------------------------------------------------------------------------------ END