📄 rx5675_ptj.asm
字号:
;***************************************************************************
; 6 Channel Pulse Position Modulation Decoder
;***************************************************************************
; Bruce Abbott bhabbott@paradise.net.nz
;
; for Microchip 12F629/75 (5 channels) or 16F630/76 (6 channels)
;
;============================= Description =================================
;
; PPM DECODER:
;
; Each frame consists of 4 to 6 channels (5 to 7 pulses), followed by a sync
; gap.
;
; The width of each channel is 1 to 2mS (1.5mS when sticks centered). The
; sync gap is at least 2.5mS long, and frame length is approximately 20mS.
;
; The input signal should look something like this:-
;
; |<------------------ 1 frame (~20mS) -------------------->|
; |< 1~2mS >|
; _ _ _ _ _ _
; ___________| |_______| |______| |______| |______| |__ // ____________| |____
; sync gap ch1 ch2 ch3 ch4 etc. sync gap ch1
;
; NOTE: Pulse polarity (shift) is assumed to be positive. If your Rx produces
; negative pulses, then either change the polarity of instructions that
; test the input signal (BTFSS<->BTFSC), or add an invertor to the input
; circuit!
;
; After receiving channel 6, channels 1, 3, and 5 are output simultaneously,
; followed by channels 2, 4 and 6.
;
; FILTERING:
;
; Each channel is averaged with the value from the previous frame, reducing
; servo jitter on weak signals. If any channel in a frame is corrupted, the
; whole frame is discarded and the last good frame is used instead.
;
; FAILSAFE:
;
; On receiving a sufficient number of good frames we save it for failsafe.
; Then, if the signal is corrupted for too long, we output the failsafe frame
; instead of the last good frame.
;
; THROTTLE ARMING:
;
; When entering failsafe the throttle is cut, and it will not be restarted
; until a good signal is detected AND the throttle is manually reset. This
; should prevent the situation where motor-induced RF interference causes
; the decoder to cycle in and out of failsafe repeatedly.
;
; For this feature to work the throttle channel has to be determined. Futaba
; and Hitec tranmitters assign the throttle to channel 3. JR and GWS use
; channel 1. If channel 1 measures less than 1.3mS or more than 1.7mS at
; startup then it is assigned to the throttle, otherwise channel 3 will be
; assumed.
;
; =============================================================================
; Summary of Changes
;
; 2004/6/21 V0.00 - modified code from rxdec6 v0.10
; 2005/2/11 V0.01 - Relaxed input pulse width timing
; 2005/2/27 V0.02 - bugs fixed; 51X,42X not outputting all required channels.
; - bug fixed; failsafe throttle was not set.
; - PIC16F676 PPM_in assigned to RA5 (MCLR reserved for ICSP)
; - Enabled Watchdog timer
; 2005/6/3 V0.03 - Negative 'Shift' assembly option.
; (NOTE: only required if input pulses are negative-going!)
;
;
;
; -----------------------------------------------------------------------------
;
#DEFINE ARM_THROTTLE ; enable if throttle arming control wanted.
#DEFINE DETECT_JR ; enable if JR tranmitter detection required.
;#DEFINE NEGATIVE_SHIFT ; enable if input pulses are negative going
ifdef NEGATIVE_SHIFT
#DEFINE SKIP_PPM_HI btfsc GPIO,PPM_in
#DEFINE SKIP_PPM_LO btfss GPIO,PPM_in
else
#DEFINE SKIP_PPM_HI btfss GPIO,PPM_in
#DEFINE SKIP_PPM_LO btfsc GPIO,PPM_in
endif
#DEFINE version "0.03"
; Make sure that PROCESSOR and <include> file are compatible with your CPU.
; 12F629 uses 12F675 defines, 16F630 uses 16F676 definitions (just don't try
; to use the A/D module...)
; Enable one of the DEFINEs below if your assembler requires it.
; MPLab users should select the device from the "Configure" menu.
;#DEFINE __12F675
;#DEFINE __16F676
;#DEFINE OSCAL_NO 0x70 ; set this if OSCCAL value was erased!
ifdef __12F675
PROCESSOR PIC12F675
INCLUDE <P12F675.inc>
__CONFIG _MCLRE_OFF&_CP_OFF&_WDT_ON&_BODEN_ON&_INTRC_OSC_NOCLKOUT
endif
ifdef __16F676
PROCESSOR PIC16F676
INCLUDE <P16F676.inc>
__CONFIG _MCLRE_OFF&_CP_OFF&_WDT_ON&_INTRC_OSC_NOCLKOUT
endif
radix dec
errorlevel 0,-305,-302
; Bit definitions for the GPIO register and the TRIS register
ifdef __16F676
#DEFINE PPM_in 5 ; pin 2 input pulse stream
#DEFINE CH_1 0 ; pin 10 Channel 1 output
#DEFINE CH_2 1 ; pin 9 Channel 2 output
#DEFINE CH_3 2 ; pin 8 Channel 3 output
#DEFINE CH_4 3 ; pin 7 Channel 4 Output
#DEFINE CH_5 4 ; pin 6 Channel 5 Output
#DEFINE CH_6 5 ; pin 5 Channel 6 Output
#DEFINE GPIO PORTA
#DEFINE TRISIO TRISA
else ; 12F629/75
#DEFINE PPM_in 3 ; pin 4 input pulse stream
#DEFINE CH_1 0 ; pin 7 Channel 1 output
#DEFINE CH_2 1 ; pin 6 Channel 2 output
#DEFINE CH_3 2 ; pin 5 Channel 3 output
#DEFINE CH_4 4 ; pin 3 Channel 4 Output
#DEFINE CH_5 5 ; pin 2 CHannel 5 Output
#DEFINE PORTC GPIO
endif
#DEFINE TrisBits (1<<PPM_in)
; Bits to be set with the OPTION instruction
; No wake up
; No weak pullups
; Timer 0 source internal
; Which edge is don't care
;
; Prescaler to Timer 0, divide by 256.
;
;
#DEFINE OptionBits B'11000111'
; =========================================================================
; Macro for generating short time delays
;
NO_OP MACRO count
NO_OP_COUNT SET count
WHILE NO_OP_COUNT>1
goto $+1 ; 2 clocks
NO_OP_COUNT SET NO_OP_COUNT-2
ENDW
IF NO_OP_COUNT
nop ; 1 clock
ENDIF
ENDM
;===========================================================================
; Macro to create offsets for variables in RAM
;
ifdef __12C509
ByteAddr SET 7
else
ByteAddr SET 32 ; user RAM starts here
endif
BYTE MACRO ByteName
ByteName EQU ByteAddr
ByteAddr SET ByteAddr+1
ENDM
; ==========================================================================
; RAM Variable Definitions
;
BYTE Flags ; various boolean flags
BYTE PPMcount ; pulse length. 1~255 = 0.75~2.28mS
BYTE Channels ; number of channels in current frame
BYTE NumChannels ; number of channels detected at startup
BYTE GoodFrames ; No. of good frames to go
; before accepting failsafe frame.
BYTE HoldFrames ; No. of bad frames to go
; before switching to failsafe.
BYTE ArmFrames ; No. of low throttle frames to go
; before arming throttle.
BYTE Temp1 ; general purpose storage
BYTE Temp2 ; '' '' ''
BYTE PPI_1 ; channel 1 in
BYTE PPI_2 ; channel 2 in
BYTE PPI_3 ; channel 3 in
BYTE PPI_4 ; channel 4 in
BYTE PPI_5 ; channel 5 in
ifdef CH_6
BYTE PPI_6 ; channel 6 in
endif
BYTE FLS_1 ; channel 1 failsafe
BYTE FLS_2 ; channel 2 failsafe
BYTE FLS_3 ; channel 3 failsafe
BYTE FLS_4 ; channel 4 failsafe
BYTE FLS_5 ; channel 5 failsafe
ifdef CH_6
BYTE FLS_6 ; channel 6 failsafe
endif
BYTE PPA_1 ; channel 1 average
BYTE PPA_2 ; channel 2 average
BYTE PPA_3 ; channel 3 average
BYTE PPA_4 ; channel 4 average
BYTE PPA_5 ; channel 5 average
ifdef CH_6
BYTE PPA_6 ; channel 6 memory
endif
BYTE PPM_1 ; channel 1 memory
BYTE PPM_2 ; channel 2 memory
BYTE PPM_3 ; channel 3 memory
BYTE PPM_4 ; channel 4 memory
BYTE PPM_5 ; channel 5 memory
ifdef CH_6
BYTE PPM_6 ; channel 6 memory
endif
BYTE PWM_1 ; channel 1 out
BYTE PWM_2 ; channel 2 out
BYTE PWM_3 ; channel 3 out
BYTE PWM_4 ; channel 4 out
BYTE PWM_5 ; channel 5 out
ifdef CH_6
BYTE PWM_6 ; channel 6 out
endif
;-------------------------------------------------------------------------
; flag bit assignments
;-------------------------------------------------------------------------
;
#DEFINE WATCH 0 ; Watchdog timeout
#DEFINE GOT_FS 1 ; failsafe frame has been captured
#DEFINE BAD_FRAME 2 ; error detected in frame
#DEFINE JR 3 ; JR throttle detection option
#DEFINE ARMED 4 ; throttle armed
#DEFINE OutED 5 ; Out done
;-------------------------------------------------------------------------
; Constants
;-------------------------------------------------------------------------
; number of good frames required before accepting failsafe values.
#DEFINE GOODCOUNT 10
; number of bad frames acceptable before going to failsafe.
#DEFINE HOLDCOUNT 25
; number of consecutive low throttle frames required before arming.
#DEFINE ARMCOUNT 5
;****************************************************************************
; Code
;
ORG 0
goto ColdStart
ORG 8
ifdef __16F676
dt "-RXD676-"
else
dt "-RXD675-"
endif
dt "--V"
dt version
dt "-"
;============================================================================
ColdStart:
bcf Flags,WATCH
btfss STATUS,NOT_TO ; copy Watchdog timeout flag
bsf Flags,WATCH
; get oscillator calibration value and use it to fine-tune clock frequency.
bsf STATUS,RP0
call 0x3ff ; get OSCCAL value
movwf OSCCAL ; set oscillator calibration
movlw OptionBits
movwf OPTION_REG
bcf STATUS,RP0
clrwdt
; initialise I/O registers
clrf GPIO ; all GPIO (PORTA) outputs low
ifdef __16F676
clrf PORTC ; all PORTC outputs low (12F630/76)
endif
bsf STATUS,RP0
movlw TrisBits
movwf TRISIO ; set GPIO (PORTA) directions
ifdef __16F676
movlw 0
movwf TRISC ; set portc directions (12F630/76)
endif
ifdef ANSEL
clrf ANSEL ; disable analog inputs (12F675/16F676)
endif
bcf STATUS,RP0
movlw b'00000111'
movwf CMCON ; Comparator off
; CPU specific stuff done, now we can start the main program!
goto Main
;----------------------------------------------------------------------------
; GetPPM: Get time to next PPM pulse
;----------------------------------------------------------------------------
;
; input: PPM signal has just gone high.
; output: PPMcount = Pulse Width * 6uS, next pulse has just started
; error: PPMcount = XX and error code in W.
;
; Error Codes
; 0 = pulse too short, too long, or next pulse too soon
; 1 = no next pulse (ie. no channel)
; 2 = good channel
PRECHARGE = ((750-12)/6) ; = 0.75mS
GetPPM: movlw PRECHARGE ; preset count for signal high length
movwf PPMcount
movlw (30/6)
movwf Temp1
high_delay: NO_OP 2
decf PPMcount ; wait 30uS to skip short glitches
decfsz Temp1
goto high_delay
hiloop: SKIP_PPM_HI ; signal gone low ?
goto pulselo
nop ; 6uS per loop
decfsz PPMcount ; count down
goto hiloop
retlw 0 ; timed out, signal high
pulselo: movlw PRECHARGE-(180/6)
subwf PPMcount,W
skpnc ; less than minimum pulse width ?
retlw 0
movlw PRECHARGE-(690/6)
subwf PPMcount,W
skpc ; greater than maximum pulse width ?
retlw 0
movlw (30/6)
movwf Temp1
low_delay: NO_OP 2
decf PPMcount ; wait 30uS to skip short glitches
decfsz Temp1
goto low_delay
to750uS: SKIP_PPM_LO ; signal should stay low until 0.75mS
retlw 0
nop ; 6uS per loop
decfsz PPMcount ; count down to zero @ 0.75mS
goto to750uS
incf PPMcount ; count up, start at 1
to2280uS: SKIP_PPM_LO ; start of next channel pulse ?
retlw 2 ; return OK
nop ; 6uS per loop
incfsz PPMcount ; count up to 256 @ 2.28mS
goto to2280uS
retlw 1 ; return error @ 2.28mS
;-------------------------------------------------------------------------------
; Millisecond Delay Timer
;-------------------------------------------------------------------------------
; Input: W = number of milliseconds to wait (max 256mS)
;
dx1k: movwf Temp1
_dx1k1: movlw (1000-5)/5
movwf Temp2
_dx1k2: clrwdt ; avoid watchdog timeout
nop
decfsz Temp2 ; wait 1mS
goto _dx1k2
decfsz Temp1
goto _dx1k1
retlw 0
;----------------------------------------------------------------------------
; Begin Channels 1,3,5 Output Pulses
;----------------------------------------------------------------------------
Start135: movlw (1<<CH_1)|(1<<CH_3)|(1<<CH_5)
movwf PORTC ; start all outputs
movlw (750-9)/6
movwf Temp1
NO_OP 3 ; wait 750uS
decfsz Temp1
goto $-3
retlw 0
ifdef CH_6
;----------------------------------------------------------------------------
; Begin Channels 2,4,6 Output Pulses
;----------------------------------------------------------------------------
Start246: movlw (1<<CH_2)|(1<<CH_4)|(1<<CH_6)
movwf PORTC ; start all outputs
movlw (750-9)/6
movwf Temp1
NO_OP 3 ; wait 750uS
decfsz Temp1
goto $-3
retlw 0
else
;----------------------------------------------------------------------------
; Begin Channels 2,4 Output Pulses
;----------------------------------------------------------------------------
Start24: movlw (1<<CH_2)|(1<<CH_4)
movwf PORTC ; start all outputs
movlw (750-9)/6
movwf Temp1
NO_OP 3 ; wait 750uS
decfsz Temp1
goto $-3
retlw 0
endif
;----------------------------------------------------------------------------
; Output Frame to Servos
;----------------------------------------------------------------------------
;
; There is not enough time left in the frame to output all the servo pulses
; sequentially. Therefore, channels 1, 3, and 5 are output simultaneously,
; followed by channels 2, 4, and 6.
;
; To produce 3 pulses simultaneously with maximum resolution, we convert the
; PWM times to increments, eg. if the times for each channel were 10, 11, and
; 13, their increments would be 10, 1, and 2.
;
Output: movf PWM_1,w ; which channel will be first?
subwf PWM_3,w
skpnz
goto Out15 ; 1=3
skpc
goto Out31 ; 3<1
movf PWM_3,w
subwf PWM_5,w
skpnz
goto Out13X ; 1<3=5
skpnc
goto Out135 ; 1<3<5
movf PWM_1,w
subwf PWM_5,w
skpnz
goto Out1X3 ; 1=5<3
skpc
goto Out513 ; 5<1<3
goto Out153 ; 1<5<3
Out15: movf PWM_1,w
subwf PWM_5,w
skpnz
goto Out1XX ; 1=3=5
skpc
goto Out51X ; 5<1=3
goto Out1X5 ; 1=3<5
Out31: movf PWM_5,w
subwf PWM_1,w
skpnz
goto Out31X ; 3<1=5
skpc
goto Out315 ; 3<1<5
movf PWM_3,w
subwf PWM_5,w
skpnz
goto Out3X1 ; 3=5<1
skpc
goto Out531 ; 5<3<1
goto Out351 ; 3<5<1
Out135: movf PWM_1,w
subwf PWM_3
addwf PWM_3,w
subwf PWM_5
call Start135 ; start ch1,ch3,ch5 servo pulses
nop
movlw (1<<CH_3)|(1<<CH_5)
nop
decfsz PWM_1 ; wait 6uS * PWM_1
goto $-4
movwf PORTC ; end ch1 servo pulse
nop
movlw (1<<CH_5)
nop
decfsz PWM_3 ; wait 6uS * PWM_3
goto $-4
movwf PORTC ; end ch3 servo pulse
nop
movlw 0
nop
decfsz PWM_5 ; wait 6uS * PWM_5
goto $-4
movwf PORTC ; end ch5 servo pulse
goto Out2
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -