⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 receiver.asm

📁 WII游戏机无线手柄SNES通讯模块
💻 ASM
📖 第 1 页 / 共 2 页
字号:
; ================================================================================================
; PROJECT:		SnesHack - A wireless/Wii-enabled SNES and NES controller hack.
; FILENAME:		Receiver.asm
; DESCRIPTION:	Code for the 16F84A receiver firmware.
; COPYRIGHT:	Copyright (c) 2007 Mark Feldman. All Rights Reserved.
; ================================================================================================

	list	p=16F84A
	radix	hex

	#include "C:\Program Files\Microchip\MPASM Suite\p16f84a.inc"

	__config	_HS_OSC & _PWRTE_OFF & _WDT_OFF & _CP_OFF

; ================================================================================================
; constants
; ================================================================================================

FALSE					equ	0
TRUE					equ	(!FALSE)

; used when we've lost the wireless signal. this is the number of good packets in a row we need
; to receive before assuming that we're picking up a good signal again.
VALID_SIGNAL_COUNT		equ 3

; REC_PORT/REC_BIT reads data from the console, it needs to be a pin that can trigger an interrupt.
; SEND_PORT/SEND_BIT sends data to the console on the same line, it needs to be open collector.
; these pins are both connected directly to the console's data line; if this program is ported
; to another type of PIC then there is no reason why they can't be implemented with a single pin,
; provided that pin supports interrupt-on-falling-edge and is open collector output.
REC_PORT				equ	PORTB
REC_BIT					equ 0
SEND_PORT				equ PORTA
SEND_BIT				equ 4

; this pin reads incoming data packets from the wireless receiver module.
WIRELESS_PORT			equ PORTB
WIRELESS_BIT			equ 1

; these pins are used to control the bidirectional red/green LED used to indicate whether or
; not we are receiving a valid wireless signal. they have no other function and can be safely
; removed if needed.
RED_LED_PORT			equ PORTB
RED_LED_BIT				equ 2
GREEN_LED_PORT			equ PORTB
GREEN_LED_BIT			equ 3

; this pin is used to generate a test signal that is held high while a wireless packet is being read.
; it has no other function, and can be safely removed if needed.
TEST_PORT				equ PORTB
TEST_BIT				equ 4

; ================================================================================================
; variables
; ================================================================================================

; variables used by the interrupt handler when receiving console packets
W_TEMP					equ 0Ch				; saves W
STATUS_TEMP				equ 0Dh				; saves STATUS
RECEIVED_PACKET			equ 0Eh				; lets main loop know that a packet was just received
BITS_READ				equ 0Fh				; total number of bits read so far
BITS_TO_SEND			equ	10h				; total number of bits to send to the console
BIT_NUM					equ	11h				; total number of bits in the current byte read/sent
CURRENT_BYTE			equ	12h				; curent byte being sent (so we don't trash the value in INDF)

; scratch variables used by the wireless timing routines
TIMER1					equ	14h
TIMER2					equ	15h

; used when we've lost the wireless signal, counts the number of good packets
; in a row that we've received
PACKET_COUNTER			equ	16h

; counts the number of interrupts we've had since the last valid wireless packet was received.
; when this number exceeds some critical value (hard-coded to 10) then the receiver assumes
; we've lost the wireless signal.
TIMEOUT_COUNTER			equ	17h

; temporary 2-byte buffer used to store button data read in from the wireless packets.
; the data is then copied into the WIRELESS_BUTTONS packet for sending to the console.
WIRELESS_BUTTONS		equ 18h

; an 11-byte packet sent to the console containing the button press states. the first
; two bytes of this structure are filled with the data from WIRELESS_BUTTONS after a
; complete, uncorrupted packet has been received from the wireless module. this
; double-buffering helps avoid random button messages being sent to the controller
; when the wireless signal is disconnected mid-packet.
CONSOLE_BUTTONS			equ 20h

; a general buffer area used to store packet data sent to and received from the console
PACKET_BUFFER			equ 30h

; ================================================================================================
; macros
; ================================================================================================

; sets the open collector output data line low
SEND_0					MACRO
						bcf		SEND_PORT, SEND_BIT
            			ENDM

; sets the open collector output data line high
SEND_1					MACRO
						bsf		SEND_PORT, SEND_BIT
            			ENDM

; initializes FSR to point to a buffer that will be used to store a packet destined for the console
START_PACKET			MACRO	BUFFER_ADDR
						movlw	BUFFER_ADDR
						movwf	FSR
						ENDM

; packs a constant value into the buffer pointed to by FSR and increments the buffer pointer
PACK_CONST				MACRO	CONST
						movlw	CONST
						movwf	INDF
						incf	FSR,F
						ENDM

; finishes off a packet by adding a 1 bit to the end of it and gets the buffer ready to
; send by pointing FSR to the start of it
END_PACKET				MACRO	BUFFER_ADDR, NUM_BYTES
						PACK_CONST 08h
						movlw	BUFFER_ADDR
						movwf	FSR
						movlw	NUM_BYTES*8+1
						ENDM

; reads a button state from an incoming wireless packet, sets the appropriate bit in the
; buffer, waits for the next bit to arrive and then checks to make sure that an interrupt
; hasn't occurred (interrupts throw off the timing, so the rest of the wireless packet has
; to be ignored; skipping a packet doesn't matter though, as we receive at least two wireless 
; packets for every console packet).
READ_WIRELESS_BUTTON	MACRO	ADDR, BIT, REVERSE_POLARITY
						bcf		ADDR, BIT							; clear the buffer bit
#if REVERSE_POLARITY
						btfss	WIRELESS_PORT, WIRELESS_BIT			; read the wireless port, is it 1?
#else
						btfsc	WIRELESS_PORT, WIRELESS_BIT			; read the wireless port, is it 0?
#endif
						bsf		ADDR, BIT							; yes, so set the buffer bit
						call	wireless_pulse_delay				; wait for the next pulse
						ENDM

; turns the LED off
LED_OFF					MACRO
						bcf		RED_LED_PORT, RED_LED_BIT
						bcf		GREEN_LED_PORT, GREEN_LED_BIT
						ENDM

; sets the LED to red to indicate we have power but not a valid wireless signal
LED_RED					MACRO
						bcf		GREEN_LED_PORT, GREEN_LED_BIT
						bsf		RED_LED_PORT, RED_LED_BIT
						ENDM

; sets the LED to green to indicate we have power and a valid wireless signal
LED_GREEN				MACRO
						bcf		RED_LED_PORT, RED_LED_BIT
						bsf		GREEN_LED_PORT, GREEN_LED_BIT
						ENDM

; these macros are used to generate a test signal that goes high when we're reading
; a packet from the wireless port. used solely for testing on an oscilloscope.

TEST_SIGNAL_ON			MACRO
						bsf		TEST_PORT, TEST_BIT
						ENDM

TEST_SIGNAL_OFF			MACRO
						bcf		TEST_PORT, TEST_BIT
						ENDM

; ================================================================================================
; entry point -	jumps to the initialization and main loop
; ================================================================================================
	org	0000h
		goto	initialization

; ================================================================================================
; interrupt handler -	there's only one type of interrupt used in this program; it gets
;						triggered when the console sends a command. this function reads the
;						command, parses it, dispatches control to the appropriate handler,
;						and re-enables interrupts before returning. timing is critical in this
;						function...we don't have time to jump to a handler, so the handler code
;						has to appear here.
; ================================================================================================
	org	0004h
		
		; get the next packet from the console	  (cycle #)
		movwf	W_TEMP							; ( 2/3) save W register
		swapf	STATUS, W						; ( 3/4) save STATUS register
		movwf	STATUS_TEMP						; ( 4/5)
		movlw	PACKET_BUFFER					; ( 5/6) FSR <- buffer address
		movwf	FSR								; ( 6/7)
		clrf	BIT_NUM							; ( 7/8)
read_bit
		incf	BITS_READ, F					; (8) increment bits read
		bcf		STATUS, C						; (9)		clear carry flag
		btfsc	REC_PORT, REC_BIT				; (10)		is this bit a 1?
		bsf		STATUS, C						; (11)		if yes then set carry bit
		rlf		INDF, F							; (12)		rotate carry bit into the current 

byte
		incf	BIT_NUM, F						; (13) increment current bit number
		btfsc	BIT_NUM, 3						; (14) have we set 8 bits yet?
		incf	FSR, F							; (15) if yes then advance the buffer ptr
		btfsc	BIT_NUM, 3						; (16) have we set 8 bits yet?
		clrf	BIT_NUM							; (17) if yes then reset the current bit number to 0
		nop										; (18)
		nop										; (19)
		btfss	REC_PORT, REC_BIT				; (20) has the data line returned to 0?
		goto	start_bit						; (21) if yes then go read another bit
		btfss	REC_PORT, REC_BIT				; (22) that check is too early, this one is more likely...
		goto	start_bit						; (23) 
		btfss	REC_PORT, REC_BIT				; (22) and sometimes it can appear here...
		goto	start_bit						; (23) 
		btfss	REC_PORT, REC_BIT				; (24) last chance...
		goto	start_bit						; (25) 
		decf	BITS_READ, F					; (34) ok, we've timed out. knock off the last bit
		goto	finished_packet					; (35) (which should be a 1) and we're done.
start_bit
		movfw	BITS_READ						; (3) safety check
		addlw	-22h							; (4)	have we read 34 bits?
		btfss	STATUS, Z						; (5)	if yes then don't read any more
		goto	read_bit						; (6) go read in the next bit

finished_packet
		call	check_4003XXh					; request button states?
		iorlw	0
		btfss	STATUS, Z
		goto	end_interrupt

		call	check_00h						; request id/status?
		iorlw	0
		btfss	STATUS, Z
		goto	end_interrupt

		call	check_41h						; request origins?
		iorlw	0
		btfss	STATUS, Z
		goto	end_interrupt
		
end_interrupt
		bsf		RECEIVED_PACKET, 0				; signal that we've just received a console packet
		clrf	BITS_READ						; we dont' have time to do this in the interrupt initialization
		swapf	STATUS_TEMP, W					; restore STATUS
		movwf	STATUS
		swapf	W_TEMP, F						; restore W
		swapf	W_TEMP, W
		bcf		INTCON, INTF					; clear the pin interrupt flag
		retfie									; return from interrupt

; ================================================================================================
; check_4003XXh -	checks to see if we've received a "request button states" command,
;					if we have then the button buffer is sent to the console.
; ================================================================================================

check_4003XXh
		movfw	BITS_READ						; must be a 24-bit packet
		sublw	18h
		btfss	STATUS, Z
		retlw	0
		movfw	PACKET_BUFFER
		sublw	40h
		btfss	STATUS, Z
		retlw	0
		movfw	PACKET_BUFFER+1					; second byte must be 03h
		sublw	03h
		btfss	STATUS, Z
		retlw	0

		movlw	CONSOLE_BUTTONS					; send the button data packet to the console
		movwf	FSR
		movlw	41h								; = 65 bits
		call	send_packet
		incf	TIMEOUT_COUNTER					; increment the time-out counter
		retlw	1

; ================================================================================================
; check_00h -	checks to see if we've received a "request id/status" command,
;				if we have then send the standard controller id word and status byte are sent
;				to the console
; ================================================================================================

check_00h
		movfw	BITS_READ						; must be an 8-bit packet
		sublw	8h
		btfss	STATUS, Z
		retlw	0
		movfw	PACKET_BUFFER					; first byte must be 00h
		sublw	00h
		btfss	STATUS, Z

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -