;************************************************************************** ; mixer.src Copyright (C) 1997-2008 Chris Hellyar. Some rights reservered. ; This source file for the Ohmark Elevon Mixer Mk1.0 is released into the ; public domain for personal use only. ; ; Because of the age of the beast, I make no warranty as to the usefulness ; or fitness for purpose of any of this code, if I were to do it again it ; would almost certainly look nothing like this!! ; ; You can contact me at: chris@trash.co.nz ; Details of about this are at: http://www.ohmark.co.nz/rcmixer.html ; ;************************************************************************** ; NOTE: This file may not be microchip assembler compatible, it was assembled ; using parallax inc's MPASM utilities, back when they made PIC programmers. ; A long time ago. :-). ; The .hex file for a PIC16C54 is on http://www.ohmark.co.nz/rcmixer.html if ; if you want to program one of them. Alternately I'd suggest studying the ; code here, and re-writing for your favourite micro if you're keen. ;************************************************************************** ; Version 1.06 ; 6/1/99 ; Changed processor type to PIC16C54a ;Version 1.03 ; 1/1/97 ; fix bug for over lenght pulse ( >2.14ms ) ; Version 1.02 ; 22/12/97 ; Converted code to PIC16C54 for OTP devices ; Version 1.01 ; 20/12/97 ; First production units. batch of 5, still PIC16C84. ; device pic16c84,xt_osc,wdt_on,pwrt_on,protect_off device pic16c54a,xt_osc,wdt_on,protect_on ; when using pic 54's change all returns to ret, for 84's use return. ; ID in PIC. For my version info. ID 1006h ; for pic54 remove single quotes, for 84 it needs them ; Equates for the codey thing These are the bits to change! ; inputs first.. in1 equ ra.2 ; input from "RX" channel 1 in2 equ ra.3 ; input channel 2 rev1in equ rb.4 ; reversing switch, channel 1 rev2in equ rb.5 ; reversing swithc, channel 2 rate11 equ rb.6 ; rate setting switch 1.1 rate12 equ rb.7 ; rate setting switch 1.2 rate21 equ rb.1 ; rate setting swtich 2.1 rate22 equ ra.0 ; rate setting switch 2.2 ; rev1in = 0 is normal, 1 is reversed. same for rev2in. ; rateX1 rateX2 ; 0 0 100% ; 1 0 75% ; 0 1 50% ; 1 1 25% ; outputs. out1 equ rb.3 ; output to servo channel 1 out2 equ rb.2 ; output channel 2 led equ rb.0 ; test output for LED ; I/O mode stuff, unused (0V on pcb) are inputs, keeps it tidy. ; 0 is output, 1 is input. ; for real life the LED pin (b0) should be an input. It's for debugging only. amode equ 11111111b ; Port A bmode equ 11110011b ; Port B ; misc equates pack equ 172 ; number of 6E-6 loops ops equ 00001110b ; definitions of "Variables" org 12 ; start of data areas. x ds 1 ; temp counter used in loops y ds 1 ; another temp counter inp1 ds 1 ; input pulse width 1 inp2 ds 1 ; " 2 inp11 ds 1 ; ones compliment of input 1 for calculations inp22 ds 1 ; " 2 outp1 ds 1 ; the pulse width 1 outp2 ds 1 ; " 2 ;********************************************************** ; The code starts here.. ; reset is only required for the pic54 comment this out for the 84. ; RESET begin org 0 ; reset vector begin call delay ; startup delay, just for saftey sake. mov w,#ops ; setup wdt prescaler before pic resets! option ; these two lines for PIC54 ;mov option,#ops ; setup options, for PIC84 just this line. call delay mov ra,#0 ; turn outputs off! mov rb,#0 mov !ra,#amode ; set pin modes for port a. mov !rb,#bmode ; port b mov outp1,#127 ; initialise inputs for output in input? mov outp2,#127 setb led ; for testing watch dog jmp start ; skips over subroutines. Subs have to be ; in first 256 byte pate for PIC54 ;********************************************************* ; subroutines under here ; subroutines are in first 256 byte page for pic54. Skip dow to next ; line of '*'s for code. ; output ; sends pulse to outputs as per vairables outp1 and outp2 ; channel one then two. output mov x,#pack ; padding of pulse mov y,outp1 ; set second temp counter for output width setb out1 ; set output on. :loop1 nop ; nop to pad delay loop. nop djnz y,:loop1 :loop2 nop nop djnz x,:loop2 clrb out1 ; turn off output pin. ; now channel two mov x,#pack ; packing for start of pulse mov y,outp2 ; set second temp counter for output width setb out2 ; set output on. :loop3 nop ; nop to pad delay loop. nop djnz y,:loop3 :loop4 nop nop djnz x,:loop4 clrb out2 ; turn off output pin. ret ; outa here. ; delay ; gives roughly a 1ms delay. delay mov x,#250 :loop nop djnz x,:loop ret ; Input. ; reads in the input pulses (duh!) ; port one first input mov inp1,#0 ; set count to 0 mov x,#pack ; offset for intro. :wait jb in1,:wait ; if the input is 1 wait for it to 0 :high jnb in1,:high ; wait for pin to go high. :loop nop ; pad for delay nop djnz x,:loop ; wait 1ms :incr sb in1 ; check input pin, skip if it's 1 jmp :fin ; finshed reading input 1 incsz inp1 ; inc input count, skip if it's 0 (overflow) jmp :incr ; do it again. mov inp1,#255 ; it overflowed :fin call output ; sets output, for better frame rate! ; port two. mov inp2,#0 ; set count to 0 mov x,#pack ; offset for intro. :wait1 jb in2,:wait1 ; if the input is 1 wait for it to 0 :high1 jnb in2,:high1 ; wait for pin to go high. :loop1 nop ; pad for delay nop djnz x,:loop1 ; wait 1ms :incr1 sb in2 ; check input pin, skip if it's 1 jmp :fin1 ; finshed reading input 1 incsz inp2 ; inc input count, skip if it's 0 (overflow) jmp :incr1 ; loop mov inp2,#255 ; it overflowed. :fin1 call output ; sets output for better frame rate! ret ; halfx ; takes x in and halves it for rate control. halfx mov y,x ; backup input value. sub x,#127 ; is it 127? jz :halfdn ; if so exit routine jc :bigger ; if it's bigger go there... mov x,#127 sub x,y ; x=127-inp clc ; clear carry so it isn'r rr'd in. rr x ; halve it. mov y,x mov x,#127 sub x,y ; re center it. ret ; outahere :bigger clc ; clear carry so it dosn't get rr'd in. rr x ; halve x, which is already input - 127 add x,#127 ; re-center it after halving ret ; outahere. :halfdn mov x,y ; get back the backup. ret ; outa here. ; perx ; takes X and returns 75% of it centered around 127 perx mov y,x ; backup input value. sub x,#127 ; is it 127? jz :halfdn ; if so exit routine jc :bigger ; if it's bigger go there... mov x,#127 sub x,y ; x=127-inp clc ; clear carry so it isn'r rr'd in. rr x ; quater it. clc rr x add x,y ret ; outahere :bigger clc ; clear carry so it dosn't get rr'd in. rr x ; quater x, which is already input - 127 clc rr x sub y,x ; y is now 75%. mov x,y ; put it in x. ret ; outahere. :halfdn mov x,y ; get back the backup. ret ; outa here. ;***************************************************** ; code starts here. start call input ; get input results clr wdt ; clear watch dog. clrb led ; testing code for watchdog. ;---------------------------- ; temp checking code to turn onLED at 50% on in1 ; ; clrb led ; mov x,inp1 ; sub x,#127 ; snz ; setb led ;---------------------------- ; rate switch code... ; excuse the "nX" jump points, ugly I know.. jnb rate11,n1 ; check rate switch 1.1 ; could be either 75 or 25% if it's on. jnb rate12,n2 ; check rate switch 1.2 mov x,inp1 ; 25% channel one. call halfx ; halve outp1 via x call halfx ; halve it again! mov inp1,x jmp n3 n2 mov x,inp1 ; 75% channel one. (inp1-25% of inp1) call perx ; halve outp1 via x mov inp1,x jmp n3 n1 jnb rate12,n3 ; check for 50% mov x,inp1 ; 50% channel one. call halfx ; halve outp1 via x mov inp1,x n3 jnb rate21,n4 ; check rate switch 2.1 ; could be either 75 or 25% if it's on. jnb rate22,n5 ; check rate switch 2.2 mov x,inp2 ; 25% channel one. call halfx ; halve outp1 via x call halfx ; halve it again! mov inp2,x jmp mixthem n5 mov x,inp2 ; 75% channel one. (inp1-25% of inp1) call perx ; halve outp1 via x mov inp2,x jmp mixthem n4 jnb rate22,mixthem ; check for 50% mov x,inp2 ; 50% channel one. call halfx ; halve outp1 via x mov inp2,x ; inp1 and inp2 are offset around 127 and inp11 and inp22 are around 0 mixthem mov inp11,inp1 mov inp22,inp2 sub inp11,#127 sub inp22,#127 ; mixing code here (yahoo) ; channel one is inp2+inp1 (elevator+Aileron) mov outp1,inp22 add outp1,inp11 mov x,inp1 ; check for case where inp 1+inp 2 < 382 add x,inp2 ; x=inp2+inp1 jnc test1 ; inp2+inp1 < 255 is OK sub x,#127 ; compare x to 127 jnc test1 ; if x < 127 get outa here. mov outp1,#128 ; make outp1 255 at output test1 mov x,inp1 ; check for case where inp1+inp2<127 add x,inp2 ; X=inp1+inp2 jc mix2 ; inp1+inp2 > 255 is OK. sub x,#127 ; compare to 127 jc mix2 ; if x !< 127 get outa here. mov outp1,#130 ; makes out1 1 at output. ; channel two is inp2-inp1 (Elevator-Aileron) mix2 mov outp2,inp22 sub outp2,inp11 mov x,inp1 ; check for case inp1-inp2 > 127 sub x,inp2 ; x=inp1-inp2 jnc test2 ; inp1-inp2= < 0 is OK. sub x,#127 ; compare x to 127 jnc test2 ; if x !> 127 get outa here mov outp2,#130 ; makes out2 1 at output. test2 mov x,inp2 ; check for case inp2-inp1 > 127 sub x,inp1 ; x=inp2-inp1 jnc addup ; inp2-inp1 < 0 is OK. sub x,#127 ; compare x to 127 jnc addup ; if x !> 127 get outa here. mov outp2,#128 ; makes out2 255 at output. ; shift the offset to 127 again addup add outp1,#127 snz inc outp1 add outp2,#127 snz inc outp2 ; reversing code below here. jnb rev1in,rev2chk ; if channel one is not reversed go to two mov x,#255 ; temp for reversing sub x,outp1 ; subtract outp1 from 255 mov outp1,x ; put result in outp1 snz ; check for 0 inc outp1 ; make it 1 rev2chk jnb rev2in,start ; if channel 2 isn't reversed go to begining! mov x,#255 ; temp for reversing sub x,outp2 ; subtract outp1 from 255 mov outp2,x ; put result in outp1 snz ; check for 0 skip if it isn't inc outp2 jmp start ; do it all over.