Full Version : Connect SNES Pad to PC (PIC ASM)
avr >>PIC 8051 ZILOG ARM TI H8 ETC >>Connect SNES Pad to PC (PIC ASM)


Admin3- 04-18-2006
Want to connect your old SNES pad onto your PC and use it as an extra keyboard or gamepad?
This is the firmware for PIC16F84 processor which let you use it as a keyboard controller.

CODE
;**********************************************************************
;
; Capture Keyboard and replay it on a keypad  
; First release, Version 0.2.0, Dec 22, 2001
; Copyright 2001 by Rick Huang
;
; Revision
; V 0.1.0  First release
; V 0.2.0  Update to send repeated keystrokes when the
;   buttons are pressed for a long time  
;
; - You can use this code for watever you wish, but I take no
;   responsability for any injury, damage to property.
; - Connection infomration will be posted when I have time....
;
;**********************************************************************

include <p16f84.inc>

__config _RC_OSC & _WDT_OFF

KeyData EQU 0ch
SpecKey EQU 0dh
Counter EQU 0eh
TimeOut EQU 0fh
PadData EQU 10h
PadDatb EQU 11h
OldPada EQU 12h
OldPadb EQU 13h
ReCount EQU 14h
TempLo0 EQU 15h
TempHi0 EQU 16h
SpeKeyL EQU 17h
SpeKeyH EQU 18h
Parrity EQU 19h
DelayCT EQU 1ah
KeyBuff EQU 1bh
XferBuf EQU 1ch
ResendT EQU 1dh
Temp1 EQU 1eh

goto start
ORG 4

  ;waiting for <0004>
  ;
  ;interrupt vector

;*****************************************************************
;** Interrupt

Int:
btfss INTCON, T0IE;If timer0 interrupt is not enabled
goto IntProgram;Interrupt is generated by programing cycle

bsf PORTA, 2;Read Cycle start here
goto dummy1 ;Send pulse on data latch
dummy1:   ;Wait cycle
bcf PORTA, 2
movlw 10h ;initialize 16 cycles
movwf ReCount
ReadCycle:
CLRC
btfsc PORTA, 4;Read data first
SETC
rrf PadData, F
rrf PadDatb, F;Save data in a 16bit memory
bcf PORTA, 3
goto  dummy2 ;Send clock --\__/--  low going
dummy2:   ;Wait...
bsf PORTA, 3
decfsz ReCount, F
goto ReadCycle;Loop

;*******************************Check for the difference in data

movfw PadDatb
xorwf  OldPadb, W
movwf TempLo0 ;Save the change in TempLo0
movfw PadData
xorwf OldPada, W
movwf TempHi0

movfw PadDatb
movwf OldPadb ;Now the new data become the old data
movfw PadData
movwf OldPada

movlw b'00001111'
andwf TempHi0, W
iorwf TempLo0, W
btfsc STATUS, Z
goto NoChange;Nothing changed, resend keyboard pulse
clrf ResendT

InitSend:
  ;Need to use the PadDatab register
movlw 0ch ;
movwf ReCount ;Initial loop for 12bit
SendCycle:
rrf TempHi0, F
rrf TempLo0, F
BNC NextCycle
  ;Change of data located at?
rrf PadData, F
rrf PadDatb, F
BC KeyUp ;1 = key up, 0 = key down
  ;KeyDown
movfw ReCount
call  LookUp

BNC NormalDown;Carry - Special Key
  ;Special Key
movwf KeyBuff
movlw 0e0h
call SendData
call FourDelay
movfw KeyBuff

NormalDown:
call SendData
call FourDelay
call FourDelay

decfsz ReCount, F
goto SendCycle
goto ExitInt
KeyUp:   ;KeyUp
movfw ReCount
call LookUp
movwf KeyBuff
BNC NormalUp
  ;Special Key
movlw 0e0h
call SendData
call FourDelay

NormalUp:
movlw 0f0h
call SendData
  ;Add proper delay
call FourDelay
movfw KeyBuff
call SendData
call FourDelay
call FourDelay

decfsz ReCount, F
goto SendCycle
goto ExitInt

NextCycle:  ;NoChange, take next item in the PadDatb
rrf PadData, F
rrf PadDatb, F
decfsz ReCount, F
goto SendCycle;End of loop, exit

;******************************* No change in keyboard data, detect resend condition
NoChange:
movlw b'11110000'
iorwf PadData, W
andwf PadDatb, W
movwf Temp1
comf Temp1, W
btfsc STATUS, Z
goto ExitInt
incf ResendT, F
movlw d'30'  ;Half a sec per resend
xorwf ResendT, W
btfss STATUS, Z
goto ExitInt
;Clear data buffer

movlw 0ffh
xorwf  OldPadb, W
movwf TempLo0 ;Save the change in TempLo0
movlw 0ffh
xorwf OldPada, W
movwf TempHi0

movlw d'25'
movwf ResendT
goto InitSend

;******************************* Exit
ExitInt:
  ;return from interrupt
bcf INTCON, 2
retfie
;******************************* Send keyboard style data
SendData:
movwf KeyData
movlw b'00001000'
movwf PORTB ;disable keyboard data path

CLRC
call SendBit ;Start bit

movlw 08h
movwf Counter
clrf Parrity

SendLoop:
rrf KeyData, F

call SendBit

decfsz Counter, F
goto SendLoop
  ;Parrity
incf Parrity, F
rrf Parrity, F
call SendBit

  ;Stop
SETC
nop
nop
nop
call SendBit
  ;Add delay
goto dummyb1
dummyb1:
goto dummyb2
dummyb2:
bsf STATUS, RP0
bsf PORTB, 0
bcf STATUS, RP0
bcf PORTB, 3
bsf PORTB, 2;Enable keyboard data path
return
;******************************* SendBit
SendBit:
bsf STATUS, RP0
bsf PORTB, 0;Clock High
  ;Add delay here
SKPC  ;This is a reverse!
goto SendZero

sendOne:
incf Parrity, F
bsf PORTB, 1;Data High
goto BitEnd
SendZero:
bcf PORTB, 1;Data Low
goto BitEnd
BitEnd:
goto delaySB1;delay for High cycle, 10dummy
delaySB1:
goto delaySB2
delaySB2:
goto delaySB3
delaySB3:
goto delaySB4
delaySB4:
goto delaySB5
delaySB5:

bcf PORTB, 0;Clock Low

goto delaySB11;delay for low cycle, 8dummy
delaySB11:
goto delaySB12
delaySB12:
goto delaySB13
delaySB13:
goto delaySB14
delaySB14:
bcf STATUS, RP0

  ;NOTE   high - process send data, in the subroutine
  ; low  - fetch data, outside the subroutine
return
;******************************* 4ms delay
FourDelay:
clrf Counter
FourLoop:
goto FourDummy0
FourDummy0:
incfsz Counter, F
goto FourLoop
return
;******************************* Lookup Table of Keys
LookUp:
movwf KeyData
movlw 88h ;Indirect address of EECON1
movwf FSR

movlw 0ch ;Get Special Key Status
movwf EEADR
bsf INDF, RD;Indirect point to EECON1
movfw EEDATA
movwf SpeKeyH

incf EEADR, F;Get Lower Special Key
bsf INDF, RD;Indirect point to EECON1
movfw EEDATA
movwf SpeKeyL

movfw KeyData
movwf EEADR  
decf EEADR, F
bsf INDF, RD;Indirect point to EECON1
movfw EEDATA

LookLoop:
rrf SpeKeyH, F
rrf SpeKeyL, F
decfsz KeyData, F
goto LookLoop

return

;*****************************************************************
;**  Initialization
start:
  ;Setup for interrupt on Timer 0
clrwdt
bsf STATUS, RP0;Set prescaler for timer0 32:1
movlw b'10000100'
movwf TMR0
bcf STATUS, RP0;First bank

movlw b'00100000';NOTE GIE is not enabled at this point
movwf INTCON
  ;Setup for input/output
movlw b'00001000';Data Clock normaly HIGH
movwf PORTA  
bsf STATUS, RP0;Second bank Note: bit0 - Clock I/O
movlw b'10000011';Input on bit 7       bit1 - DATA I/O
movwf TRISB ;Set port-B for output
movlw b'00010000'
movwf TRISA ;Set port-A for input / bit 4
bcf STATUS, RP0

;*****************************************************************
;**  Main program loop

;call Capture
movlw b'00000100'
movwf PORTB

btfsc PORTB, 7
goto Program

bsf INTCON, GIE;Enable the interrupt at this point
Loop:
goto Loop
;*****************************************************************
;**  Interrupt generated for program
IntProgram:
movwf KeyBuff
movfw PORTB
movwf XferBuf
bcf INTCON, INTF
movfw KeyBuff
retfie

;*****************************************************************
;**
Program:
  ;Setup Interrupt-on-change on PortB<0>
movlw b'00010000'
movwf INTCON ;Note, GIE is not on!

bsf PORTB, 4
ProgramLoop:
bcf PORTB, 5
call FullCapture
  ;Display a successful capture
bcf PORTB, 4

btfsc SpecKey, 7
bsf PORTB, 5

call  ReadPad ;Read key# on the pad

call WriteData;Write into EEprom
  ;Display a successful Read
bsf PORTB, 4
goto ProgramLoop

;*****************************************************************
;**  Read Pad
ReadPad:
movlw 0bh
movwf PadData
bsf PORTA, 2;Read Cycle start here
goto Pdummy1 ;Send pulse on data latch
Pdummy1:  ;Wait cycle
bcf PORTA, 2
movlw 0ch ;initialize 16 cycles
movwf ReCount
PReadCycle:
btfss PORTA, 4;Read data first
return

decf PadData, F
bcf PORTA, 3
goto  Pdummy2 ;Send clock --\__/--  low going
Pdummy2:  ;Wait...
bsf PORTA, 3
decfsz ReCount, F
goto PReadCycle;Loop

goto ReadPad ;All key empty!


;*****************************************************************
;**  Full Capture
FullCapture:
call Capture
TSTF SpecKey
SKPNZ
return  ;Regular key.

movlw 0e0h ;Special key? if not, Retry
xorwf SpecKey, W
BNZ FullCapture
movlw 0f0h ;Key Up follows? If so, Retry
xorwf KeyBuff, W
BZ FullCapture
return
;*****************************************************************
;**  Capture Keyboard data
Capture:
bsf INTCON, GIE;Enable interrupt
bsf XferBuf, 0;Enable interrupt  for next cycle

clrf SpecKey
movlw 09h
movwf Counter
KeyLoop:
call WaitCycle

SKPNC  ;Timeout
goto  Capture ;Resample

CLRC
btfsc XferBuf, 1
SETC
rrf SpecKey, F

bsf XferBuf, 0;Enable interrupt  for next cycle

decfsz Counter, F
goto  KeyLoop


;******************************* two dummy data  / Parrity and stop bit
call WaitCycle
SKPNC
goto Capture
bsf XferBuf, 0;Enable interrupt  for next cycle

call WaitCycle
SKPNC
goto Capture
bsf XferBuf, 0;Enable interrupt  for next cycle

;******************************* Capture special key!

clrf KeyData
movlw 09h
movwf Counter
KeyLoopS:
call WaitCycleL

SKPNC  ;Timeout
goto  NoSpecKey;Resample

CLRC
btfsc XferBuf, 1
SETC
rrf KeyData, F

bsf XferBuf, 0;Enable interrupt  for next cycle

decfsz Counter, F
goto  KeyLoopS


;******************************* two dummy data  / Parrity and stop bit
call WaitCycle
SKPNC
goto Capture
bsf XferBuf, 0;Enable interrupt  for next cycle

call WaitCycle
SKPNC
goto Capture
bsf XferBuf, 0;Enable interrupt  for next cycle

bcf INTCON, GIE
return

NoSpecKey:
movfw SpecKey
movwf KeyData
clrf SpecKey

bcf INTCON, GIE
return
;******************************* Wait Cycle
WaitCycle:
clrf TimeOut
LCLoop:
btfsc XferBuf, 0
goto IncTimeLC;wait for low
CLRC
return
IncTimeLC:
decfsz TimeOut, F
goto LCLoop
SETC
return
;******************************* Wait Cycle Long
WaitCycleL:
movlw 03h
movwf DelayCT
LLongLoop:
clrf TimeOut
LLowLoop:
btfsc XferBuf, 0
goto LIncTime
CLRC
return
LIncTime:
decfsz TimeOut, F
goto LLowLoop

decfsz DelayCT, F
goto LLongLoop
SETC
return
;*****************************************************************
;**  EEprom writing sequence
WriteData:
movfw PadData
movwf EEADR
movfw KeyData ;First Byte
movwf EEDATA

call EEwrite
;****************************** Start to write special key data

movwf KeyData
movlw 88h ;Indirect address of EECON1
movwf FSR

movlw 0ch ;Get Special Key Status
movwf EEADR
bsf INDF, RD;Indirect point to EECON1
movfw EEDATA
movwf SpeKeyH

incf EEADR, F;Get Lower Special Key
bsf INDF, RD;Indirect point to EECON1
movfw EEDATA
movwf SpeKeyL

clrf TempLo0
clrf TempHi0
incf PadData, F
SETC
WriteLoop:
rlf TempLo0, F
rlf TempHi0, F
decfsz PadData, F
goto WriteLoop

TSTF SpecKey
SKPNZ
goto CleanBit;No special key, CleanSpecial bit

movfw TempLo0
iorwf SpeKeyL, F

movfw TempHi0
iorwf SpeKeyH, F

goto WriteBack

CleanBit:
comf TempLo0, W
andwf SpeKeyL, F

comf TempHi0, W
andwf SpeKeyH, F
;******************************* Write back the data
WriteBack:
movlw 0ch
movwf EEADR
movfw SpeKeyH ;First Byte
movwf EEDATA
call EEwrite

incf EEADR, F
movfw SpeKeyL
movwf EEDATA
call EEwrite
return

;*****************************************************************
;**  EEprom Write
EEwrite:
bsf STATUS, RP0

bcf INTCON, GIE;Writing sequence
bsf EECON1, WREN
movlw 55h
movwf  EECON2
movlw 0aah
movwf EECON2
bsf EECON1, WR
NotDone1:
btfsc EECON1, WR
goto NotDone1
bcf STATUS, RP0;Finish writing KeyData,
return
;*****************************************************************
;** End

end



Forumer™ is Voted #1 Free Forum Hosting provider
Build your own community today with the largest message board hosting company.