📄 receiver.asm
字号:
retlw 0
START_PACKET PACKET_BUFFER ; send id and status
PACK_CONST 09h
PACK_CONST 00h
PACK_CONST 00h
END_PACKET PACKET_BUFFER, 3
call send_packet
START_PACKET CONSOLE_BUTTONS ; initialize the buttons packet
PACK_CONST 00h ; 0 0 0 S Y X B A
PACK_CONST 80h ; 1 L R Z D-UP D-DOWN D-RIGHT D-LEFT
PACK_CONST 80h ; Joystick X
PACK_CONST 80h ; Joystick Y
PACK_CONST 80h ; C-Stick X
PACK_CONST 80h ; C-Stick Y
PACK_CONST 00h ; Left shoulder toggle
PACK_CONST 00h ; Right shoulder toggle
END_PACKET CONSOLE_BUTTONS, 8
retlw 1
; ================================================================================================
; check_41h - checks to see if we've received a "request origins" command,
; calibration is easy on this controller...everything's digital.
; ================================================================================================
check_41h
movfw BITS_READ ; must be an 8-bit packet
sublw 8h
btfss STATUS, Z
retlw 0
movfw PACKET_BUFFER ; first byte must be 41h
sublw 41h
btfss STATUS, Z
retlw 0
START_PACKET PACKET_BUFFER ; send origins/calibration packet
PACK_CONST 00h
PACK_CONST 80h
PACK_CONST 80h
PACK_CONST 80h
PACK_CONST 80h
PACK_CONST 80h
PACK_CONST 00h
PACK_CONST 00h
PACK_CONST 02h
PACK_CONST 02h
END_PACKET PACKET_BUFFER, 0Ah ; 10 bytes in this packet
call send_packet
retlw 1
; ================================================================================================
; initialization - sets up the ports, synchs with the console, enables interrupts and
; falls through to the wireless_disconnected routine
; ================================================================================================
initialization
bsf STATUS, RP0 ; select bank 1
bsf WIRELESS_PORT, WIRELESS_BIT ; input from the wireless module
bsf REC_PORT, REC_BIT ; read data line from the console
bcf SEND_PORT, SEND_BIT ; open collector output to the console
bcf GREEN_LED_PORT, GREEN_LED_BIT ; LED pin 1
bcf RED_LED_PORT, RED_LED_BIT ; LED pin 2
bcf TEST_PORT, TEST_BIT ; test point pin
errorlevel -302
bcf OPTION_REG, INTEDG ; select interrupt on falling edge for PORTB, bit0
errorlevel +302
bcf STATUS, RP0 ; select bank 0
TEST_SIGNAL_OFF ; test signal off by default
clrf BITS_READ ; we dont' have time to do this in the interrupt initialization
bsf SEND_PORT, SEND_BIT ; maintain high output by default
bcf INTCON, INTF ; make sure the bit0 interrupt bit is clear
bsf INTCON, INTE ; enable external interrupt
; ================================================================================================
; wireless_disconnected - this function is called by the main loop whenever it detects a
; lost wireless signal. the function disables interrupts (thus breaking
; off communication with the console) and then sits in a tight loop
; until it reads several valid packets in a row. a packet is considered
; valid when we detect the start bit followed by a little less than
; 3.5ms of 0s after the packet.
; ================================================================================================
wireless_disconnected
bcf INTCON, GIE ; disable global interrupts
LED_RED ; show we're in a disconnected state
disconnected_loop
btfss WIRELESS_PORT, WIRELESS_BIT ; wait for the start of a wireless pulse
call wireless_half_pulse_delay ; advance to the center of the pulse
movlw VALID_SIGNAL_COUNT ; we want several good wireless packets in a row
movwf PACKET_COUNTER ; before we assume we're reconnected
packet_loop
btfss WIRELESS_PORT, WIRELESS_BIT ; picking up a 1 on the wireless pin?
goto disconnected_loop ; no, so start over
call wireless_packet_delay ; yep, could be a start bit. skip over the packet.
movlw 03Bh ; outer loop
movwf TIMER1
movlw 03Ah
movwf TIMER2 ; inner loop
btfsc WIRELESS_PORT, WIRELESS_BIT ; picking up a 0 on the wireless pin?
goto disconnected_loop ; no, so start all over again
decfsz TIMER2, F ; dec inner loop
goto $-3
decfsz TIMER1, F
goto $-7 ; dec outer loop
movlw 31h ; burn off a few more cycles to make it 3500 exactly
movwf TIMER1
decfsz TIMER1, F
goto $-1
decfsz PACKET_COUNTER, F ; we received a clean packet, decrement the counter
goto packet_loop ; if we haven't got them all then loop back for more
clrf TIMEOUT_COUNTER ; reset the timeout counter
bsf INTCON, GIE ; reenable interrupts
LED_GREEN ; show we're picking up a valid wireless signal again
; ================================================================================================
; main_loop - sits in a tight loop polling the wireless module and updating the buttons array.
; the main loop often gets interrupted by the console when it requests button data
; be sent to it. these interrupts are long enough to push the detection of the stop
; bit past the end of the packet so that a 0 is read instead of a 1. when this
; happens the entire packet is ignored, and a fresh attempt is made to read in the
; next wireless packet. control is passed to the disconnected handler when
; too many bad packets in a row are received.
; ================================================================================================
main_loop
movfw TIMEOUT_COUNTER ; get the packet counter
sublw 0Ah ; have we had at least 10 interrupts since
btfss STATUS, C ; the last wireless packet?
goto wireless_disconnected ; yes, so we've lost the wireless signal
clrf WIRELESS_BUTTONS ; initialize the bytes we'll used to
clrf WIRELESS_BUTTONS+1 ; double-buffer the button data
call wait_for_wireless_packet ; wait for the next start bit to arrive
sublw 0 ; if we timed out then transfer control
btfsc STATUS, Z ; to the disconnected handler
goto wireless_disconnected
call wireless_half_pulse_delay ; advance half-way into the pulse
; read each button pulse and store the result in the WIRELESS_BUTTONS array. each iteration
; of the READ_WIRELESS_BUTTON macro lasts exactly 625uS, i.e. the length of a wireless bit
; pulse.
TEST_SIGNAL_ON
READ_WIRELESS_BUTTON WIRELESS_BUTTONS+1, 7, FALSE ; start bit
READ_WIRELESS_BUTTON WIRELESS_BUTTONS, 1, FALSE ; B
READ_WIRELESS_BUTTON WIRELESS_BUTTONS, 3, TRUE ; Y
READ_WIRELESS_BUTTON WIRELESS_BUTTONS+1, 4, FALSE ; SELECT (Z)
READ_WIRELESS_BUTTON WIRELESS_BUTTONS, 4, TRUE ; START
READ_WIRELESS_BUTTON WIRELESS_BUTTONS+1, 3, FALSE ; D-UP
READ_WIRELESS_BUTTON WIRELESS_BUTTONS+1, 2, TRUE ; D-DOWN
READ_WIRELESS_BUTTON WIRELESS_BUTTONS+1, 0, FALSE ; D-LEFT
READ_WIRELESS_BUTTON WIRELESS_BUTTONS+1, 1, TRUE ; D-RIGHT
READ_WIRELESS_BUTTON WIRELESS_BUTTONS, 0, FALSE ; A
READ_WIRELESS_BUTTON WIRELESS_BUTTONS, 2, TRUE ; X
READ_WIRELESS_BUTTON WIRELESS_BUTTONS+1, 6, FALSE ; L
READ_WIRELESS_BUTTON WIRELESS_BUTTONS+1, 5, TRUE ; R
TEST_SIGNAL_OFF
; at this point we should be at the stop bit, unless we've lost the signal or an interrupt
; has occurred mid-packet. in either case this wireless packet is invalid and so we ignore it.
; the TIMEOUT_COUNTER will eventually overflow and control will be passed to the disconnected
; handler.
btfss WIRELESS_PORT, WIRELESS_BIT ; we should be in the middle of the stop bit, is it a 1?
goto main_loop ; nope, so ignore this packet
call wireless_pulse_delay ; skip over the stop bit
; if we made it this far then we managed to receive a complete wireless packet,
; including start and stop bits. it's unlikely we've lost the wireless connection,
; so copy the button data into the CONSOLE_BUTTONS packet so that it gets sent
; to the console.
save_buttons
movfw WIRELESS_BUTTONS
movwf CONSOLE_BUTTONS
movfw WIRELESS_BUTTONS+1
movwf CONSOLE_BUTTONS+1
clrf TIMEOUT_COUNTER ; reset the packet counter
goto main_loop
; ================================================================================================
; send_packet - sends a stream of bits to the console. 0 is sent as a 1uS low pulse followed by
; a 3uS high pulse. 1 is sent as a 3uS low pulse followed by a 1uS high pulse.
; this function should be called with the number of bits to send loaded into W
; and the address of the send buffer loaded into FSR. execution time is exactly
; numbits*20+8 instructions, including the call to and return from function.
; ================================================================================================
send_packet
movwf BITS_TO_SEND ; store the number of bytes to send
clrf BIT_NUM ; haven't sent any bytes yet
movfw INDF ; make a copy of the first byte to send so we don't trash it
movwf CURRENT_BYTE
incf FSR, F ; and advance the ptr
send_bit
SEND_0 ; 0uS
nop
incf BIT_NUM, F ; add one to the bytes sent counter
rlf CURRENT_BYTE, F
btfsc STATUS, C
SEND_1 ; 1uS, send the MSB of CURRENT_BYTE to the console
btfsc BIT_NUM, 3 ; have we sent 8 bits yet?
goto advance_byte
nop
nop
nop ; 2uS
nop
nop
nop
nop
end_bit
SEND_1 ; 3uS, either way, the pulse should be 1 at this stage
bit_sent
decf BITS_TO_SEND, F ; one bit less to send
btfss STATUS, Z ; finished yet?
goto send_bit ; nah
return ; yup
advance_byte
movfw INDF ; make a copy of the first byte to send so we don't trash it
movwf CURRENT_BYTE
incf FSR, F ; and advance the ptr
clrf BIT_NUM ; haven't sent any bytes yet
goto end_bit
; ================================================================================================
; timing routines
; ================================================================================================
; spends roughly 7ms polling the wireless bit to see if a 1 has arrived.
; returns 1 in W when a pulse is detected, otherwise returns 0 to
; signify a time-out (i.e. wireless disconnected state)
wait_for_wireless_packet
movlw 053h
movwf TIMER1
movlw 053h
movwf TIMER2
btfsc WIRELESS_PORT, WIRELESS_BIT ; wait for the start of a wireless pulse
retlw 1
decfsz TIMER2, F
goto $-3
decfsz TIMER1, F
goto $-7
retlw 0
; delays the length of a wireless packet, i.e. exactly 3.5ms
; including the call-to and return-from. at 20MHz
; 3.5mS == 17500 cycles
wireless_packet_delay
movlw 04Bh
movwf TIMER1
movlw 04Bh
movwf TIMER2
decfsz TIMER2, F
goto $-1
decfsz TIMER1, F
goto $-5
movlw 6Ah
movwf TIMER1
decfsz TIMER1, F
goto $-1
nop
return
; waits the length of each RF receiver pulse minus 3, i.e. exactly 1247 cycles
; including the call-to and return-from. the 3 is taken off so that the
; calling prodecure has a few cycles spare to grab the button state
wireless_pulse_delay
movlw 0FFh
movwf TIMER1
decfsz TIMER1, F
goto $-1
movlw 09Eh
movwf TIMER1
decfsz TIMER1, F
goto $-1
nop
nop
return
; waits the length of half an RF pulse, i.e. exactly 625 cycles,
; including the call-to and return-from. this is called so that
; readings are taken in the center of the wireless pulses so
; that they can accommadate some drift.
wireless_half_pulse_delay
movlw 0CEh
movwf TIMER1
decfsz TIMER1, F
goto $-1
nop
nop
return
end
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -