Saturday, January 22, 2011

Interfacing a SNES controller and 16x2 LCD to the PIC16f84A



I threw together this demo this morning after finding two snes controllers last night for $1.90 each at a thrift store.

                                          Controller after I meticulously cleaned it.
Next I researched online a bit to find out how to read the button presses (this pdf helped: http://www.parallax.com/dl/docs/prod/prop/hydra-ch6all-v1.0.pdf). The controller uses a active low 16bit wide shift register (last 4bits are always high). Read the pdf for the specifics of pulsing the latch and clock. All that needs to be hooked up is +5v, gnd, Clock, Latch, and Data (the pinout can be found here: http://pinouts.ru/Game/snescontroller_pinout.shtml). I used solid core copper wire that was folded over once to thicken it enough to hold when inserted in the connector socket since I didn't have a proper connector.
                                          Perfect for prototyping.
Next I wired up the breadboard. The first part was the power supply which consists of a AA battery and a max756 to step it up to the 5v needed by the controller, lcd, and pic.
                                          Indicator led and switch to turn on the power.
Next I wired up the PIC16f84A with an external RC clock and icsp header.
Finally I wired the controller (to port A) and lcd (to port B) up and started coding.
                                          The lcd printing button presses.
The code basically initializes the lcd and then continually polls the controller and when a certain button is pressed sends the character to the display. This way the display types the button presses and when you want to clear the screen you just press start or select.

For now I will post the code below (in assembly, and sorry about the formatting, it looked much nicer in mplab) and will upload a schematic and video of it in action when I get some time.
Note: The code provided below is not optimized and is rather messy. Remember that I am not responsible if you try and make this and it doesn't work or ends up blowing up. This was just meant as a proof of concept and a neat morning wake up exercise for me.

UPDATE:
Sorry its been awhile, I've been busy at school, but here is the schematic. Note that I left out the step up converter circuitry.



Code:
;Shawn Maxwell  ;
;1/22/11        ;
;LCD SNES       ;
;;;;;;;;;;;;;;;;;

;Writes SNES key presses to HD44780 compatable LCD in 4bit mode

COUNT1  equ  08h           ;delay constants
COUNT2  equ  09h

Start    BSF  03h,5         ;switch from bank 0 to 1

    MOVLW  b'00000000' ;Out RB to output
    MOVWF 06h
    MOVLW  b'11100'       ;Out RA0,1 to output, RA2-4 to input
    MOVWF 05h

    BCF 03h,5          ;switch from bank 1 to 0 
   
    ;RS = RB0, EN = RB1, D4-D7 = RB2-RB5
    ;CLK = RA0, Latch = RA1, Data = RA2

Begin
    call LongDelay
    call LongDelay
   
;initialize LCD
    movlw b'00001010'    ;Out EN high
    call Out  ;;;;
    movlw b'00001000'    ;Out to 4 bit operation (note: 1 nibble

operation)
    call Out  ;;;;      ;Out EN low

    movlw b'00001010'    ;Out EN high
    call Out  ;;;;
    movlw b'00001000'    ;Function Out, 8 bit
    call Out  ;;;;        ;Out EN low
    movlw b'00100010'    ;Out EN high
    call Out  ;;;;
    movlw b'00100000'    ;2nd nibble
    call Out  ;;;;      ;Out EN low

    movlw b'00000010'    ;Out EN high
    call Out  ;;;;
    movlw b'00000000'    ;Display ON, Cursor On, Cursor Blinking
    call Out  ;;;;      ;Out EN low
    movlw b'00111110'    ;Out EN high
    call Out  ;;;;
    movlw b'00111100'    ;2nd nibble
    call Out  ;;;;      ;Out EN low

    movlw b'00000010'    ;Out EN high
    call Out  ;;;;
    movlw b'00000000'    ;Entry Mode, Increment cursor position, No

display shift
    call Out  ;;;;      ;Out EN low
    movlw b'00011010'    ;Out EN high
    call Out  ;;;;
    movlw b'00011000'    ;2nd nibble
    call Out  ;;;;      ;Out EN low
;initialize SNES controller and read data
SNES
    movlw b'00011'        ;set Latch, CLK high
    movwf 05h
    call Delay
    movlw b'00001'        ;set Latch low
    movwf 05h
    call Delay
    movlw b'00000'        ;set CLK low
    movwf 05h
    call Delay
    movlw b'00010'        ;pulse Latch high
    movwf 05h
    call Delay
    movwf b'00000'
    movwf 05h
    btfss 05h,2            ;read B
    call buttonB
    call Delay
    call Delay
    movlw b'00001'        ;Pulse CLK
    movwf 05h
    call Delay
    call Delay
    movlw b'00000'
    movwf 05h
    call Delay
    call Delay
    btfss 05h,2            ;read Y
    call buttonY
    call Delay
    call Delay
    movlw b'00001'        ;Pulse CLK
    movwf 05h
    call Delay
    call Delay
    movlw b'00000'
    movwf 05h
    call Delay
    call Delay
    btfss 05h,2            ;read Select
    call Clear
    call Delay
    call Delay
    movlw b'00001'        ;Pulse CLK
    movwf 05h
    call Delay
    call Delay
    movlw b'00000'
    movwf 05h
    call Delay
    call Delay
    btfss 05h,2            ;read Start
    call Clear
    call Delay
    call Delay
    movlw b'00001'        ;Pulse CLK
    movwf 05h
    call Delay
    call Delay
    movlw b'00000'
    movwf 05h
    call Delay
    call Delay
    btfss 05h,2            ;read Up
    call buttonUp
    call Delay
    call Delay
    movlw b'00001'        ;Pulse CLK
    movwf 05h
    call Delay
    call Delay
    movlw b'00000'
    movwf 05h
    call Delay
    call Delay
    btfss 05h,2            ;read Down
    call buttonDown
    call Delay
    call Delay
    movlw b'00001'        ;Pulse CLK
    movwf 05h
    call Delay
    call Delay
    movlw b'00000'
    movwf 05h
    call Delay
    call Delay
    btfss 05h,2            ;read Left
    call buttonLeft
    call Delay
    call Delay
    movlw b'00001'        ;Pulse CLK
    movwf 05h
    call Delay
    call Delay
    movlw b'00000'
    movwf 05h
    call Delay
    call Delay
    btfss 05h,2            ;read Right
    call buttonRight
    call Delay
    call Delay
    movlw b'00001'        ;Pulse CLK
    movwf 05h
    call Delay
    call Delay
    movlw b'00000'
    movwf 05h
    call Delay
    call Delay
    btfss 05h,2            ;read A
    call buttonA
    call Delay
    call Delay
    movlw b'00001'        ;Pulse CLK
    movwf 05h
    call Delay
    call Delay
    movlw b'00000'
    movwf 05h
    call Delay
    call Delay
    btfss 05h,2            ;read X
    call buttonX
    call Delay
    call Delay
    movlw b'00001'        ;Pulse CLK
    movwf 05h
    call Delay
    call Delay
    movlw b'00000'
    movwf 05h
    call Delay
    call Delay
    btfss 05h,2            ;read L
    call buttonL
    call Delay
    call Delay
    movlw b'00001'        ;Pulse CLK
    movwf 05h
    call Delay
    call Delay
    movlw b'00000'
    movwf 05h
    call Delay
    call Delay
    btfss 05h,2            ;read R
    call buttonR
    call Delay
    call Delay
    goto SNES

;--------------------------------------------
buttonB
    movlw b'00010011'    ;Out EN,RS high
    call Out  ;;;;
    movlw b'00010001'    ;B
    call Out  ;;;;      ;Out EN low
    movlw b'00001011'    ;Out EN,RS high
    call Out  ;;;;
    movlw b'00001001'    ;2nd nibble
    call Out  ;;;;      ;Out EN low
    movlw b'00000010'    ;Clear outputs, EN high
    movwf 06h
return

buttonY
    movlw b'00010111'    ;Out EN,RS high
    call Out  ;;;;
    movlw b'00010101'    ;Y
    call Out  ;;;;      ;Out EN low
    movlw b'00100111'    ;Out EN,RS high
    call Out  ;;;;
    movlw b'00100101'    ;2nd nibble
    call Out  ;;;;      ;Out EN low
    movlw b'00000010'    ;Clear outputs, EN high
    movwf 06h
return

Clear
    movlw b'00000010'    ;Out EN,RS high
    call Out  ;;;;
    movlw b'00000000'    ;Clear
    call Out  ;;;;      ;Out EN low
    movlw b'00000110'    ;Out EN,RS high
    call Out  ;;;;
    movlw b'00000100'    ;2nd nibble
    call Out  ;;;;      ;Out EN low
    movlw b'00000010'    ;Clear outputs, EN high
    movwf 06h
return

buttonUp
    movlw b'00010111'    ;Out EN,RS high
    call Out  ;;;;
    movlw b'00010101'    ;Up
    call Out  ;;;;      ;Out EN low
    movlw b'00010111'    ;Out EN,RS high
    call Out  ;;;;
    movlw b'00010101'    ;2nd nibble
    call Out  ;;;;      ;Out EN low
    movlw b'00000010'    ;Clear outputs, EN high
    movwf 06h
return

buttonDown
    movlw b'00010011'    ;Out EN,RS high
    call Out  ;;;;
    movlw b'00010001'    ;Down
    call Out  ;;;;      ;Out EN low
    movlw b'00010011'    ;Out EN,RS high
    call Out  ;;;;
    movlw b'00010001'    ;2nd nibble
    call Out  ;;;;      ;Out EN low
    movlw b'00000010'    ;Clear outputs, EN high
    movwf 06h
return

buttonLeft
    movlw b'00011111'    ;Out EN,RS high
    call Out  ;;;;
    movlw b'00011101'    ;Left
    call Out  ;;;;      ;Out EN low
    movlw b'00111111'    ;Out EN,RS high
    call Out  ;;;;
    movlw b'00111101'    ;2nd nibble
    call Out  ;;;;      ;Out EN low
    movlw b'00000010'    ;Clear outputs, EN high
    movwf 06h
return

buttonRight
    movlw b'00011111'    ;Out EN,RS high
    call Out  ;;;;
    movlw b'00011101'    ;Right
    call Out  ;;;;      ;Out EN low
    movlw b'00111011'    ;Out EN,RS high
    call Out  ;;;;
    movlw b'00111001'    ;2nd nibble
    call Out  ;;;;      ;Out EN low
    movlw b'00000010'    ;Clear outputs, EN high
    movwf 06h
return

buttonA
    movlw b'00010011'    ;Out EN,RS high
    call Out  ;;;;
    movlw b'00010001'    ;A
    call Out  ;;;;      ;Out EN low
    movlw b'00000111'    ;Out EN,RS high
    call Out  ;;;;
    movlw b'00000101'    ;2nd nibble
    call Out  ;;;;      ;Out EN low
    movlw b'00000010'    ;Clear outputs, EN high
    movwf 06h
return

buttonX
    movlw b'00010111'    ;Out EN,RS high
    call Out  ;;;;
    movlw b'00010101'    ;X
    call Out  ;;;;      ;Out EN low
    movlw b'00100011'    ;Out EN,RS high
    call Out  ;;;;
    movlw b'00100001'    ;2nd nibble
    call Out  ;;;;      ;Out EN low
    movlw b'00000010'    ;Clear outputs, EN high
    movwf 06h
return

buttonL
    movlw b'00010011'    ;Out EN,RS high
    call Out  ;;;;
    movlw b'00010001'    ;L
    call Out  ;;;;      ;Out EN low
    movlw b'00110011'    ;Out EN,RS high
    call Out  ;;;;
    movlw b'00110001'    ;2nd nibble
    call Out  ;;;;      ;Out EN low
    movlw b'00000010'    ;Clear outputs, EN high
    movwf 06h
return

buttonR
    movlw b'00010111'    ;Out EN,RS high
    call Out  ;;;;
    movlw b'00010101'    ;R
    call Out  ;;;;      ;Out EN low
    movlw b'00001011'    ;Out EN,RS high
    call Out  ;;;;
    movlw b'00001001'    ;2nd nibble
    call Out  ;;;;      ;Out EN low
    movlw b'00000010'    ;Clear outputs, EN high
    movwf 06h
return
   
Out
    movwf 06h
Loop01  decfsz COUNT1,1
        goto   Loop01
Loop02    decfsz COUNT1,1
    goto   Loop02
return

Delay
Loop1   decfsz COUNT1,1
        goto   Loop1
Loop2    decfsz COUNT1,1
    goto   Loop2
return

LongDelay
loop1   decfsz COUNT1,1
        goto   loop1
loop2    decfsz COUNT1,1
    goto   loop2
loop3    decfsz COUNT1,1
    goto   loop3
loop4    decfsz COUNT1,1
    goto   loop4
loop5    decfsz COUNT1,1
    goto   loop5
loop6    decfsz COUNT1,1
    goto   loop6
loop7    decfsz COUNT1,1
    goto   loop7
loop8    decfsz COUNT1,1
    goto   loop8
loop9    decfsz COUNT1,1
    goto   loop9
loop10    decfsz COUNT1,1
    goto   loop10
loop11    decfsz COUNT1,1
    goto   loop11
loop12    decfsz COUNT1,1
    goto   loop12
loop13    decfsz COUNT1,1
    goto   loop13
loop14    decfsz COUNT1,1
    goto   loop14
loop15    decfsz COUNT1,1
    goto   loop15
loop16    decfsz COUNT1,1
    goto   loop16
loop17    decfsz COUNT1,1
    goto   loop17
loop18    decfsz COUNT1,1
    goto   loop18
loop19    decfsz COUNT1,1
    goto   loop19
loop20    decfsz COUNT1,1
    goto   loop20
return

end