;************************************************************************ ; TaPRK IR-LINK-TRANSMITTER POT VERSION ;************************************************************************ LIST P = 16F84A, R = HEX ;Prosessor type, radix INCLUDE "p16f84A.inc" ;w,f,porta,portb etc. ERRORLEVEL -224 ;Prevent error message ;from "tris"-command __CONFIG _PWRTE_OFF & _HS_OSC & _WDT_OFF;4MHz crystal ;************************************************************************ ; SCHEMATIC DIAGRAM ;************************************************************************ ; +---+_+---+ ; ADDR LOW PORTA.2 ->|1 18|<- PORTA.1 BUTTON act.low ; ADDR HIGH PORTA.3 ->|2 17|-> PORTA.0 IR-LED act.high ; POT&CAP PORTA.4 <>|3 16|-- XTAL ; Vdd --|4 15|-- XTAL ; Vss(GND)--|5 14|-- Vdd (+5V) ; SPEED LED 0 PORTB.0 <-|6 13|-> PORTB.7 ; SPEED LED 1 PORTB.1 <-|7 12|-> PORTB.6 ; SPEED LED 2 PORTB.2 <-|8 11|-> PORTB.5 ; SPEED LED 3 PORTB.3 <-|9 10|-> PORTB.4 ; +---------+ ;************************************************************************ ; MAIN IDEA ;************************************************************************ ; This is based on Holger Klabunde's design, but is completely ; rewritten in assembler. ; ; Sender timing, carrier, packet format ; ===================================== ; 26us cycle of IR-LED on/off gives 38,5kHz ; 16 cycles for 1/2 bit -> 16 x 26us= 416 us ; Prescaler of 1:8 makes TMR0 advance every 8us (@4MHz crystal) ; 1/2 bit needs 416/8 = 52 ticks of TMR0 ; 1/4 bit needs 52/2 = 26 ticks of TMR0 ; ; [2002-03-07] Error in number of "nop"s, in off-section: ; had 1 too many. Also noted that (acc. to datasheet) ; adding to TMR0 will clear prescaler contents, so always ; a bit late in timing! Hint: Use "MPLAB/Window/Stopwatch"! ; ; This is loosely following Philips RC5, exept: ; Bit length now 832us instead of 1798us. ; Only one start bit, and it is "0", only 8 data bits and ; Added parity bit -> Total of 10 bits. ; ; This is presumably similar to Lorell Joiner's ; setup, done with hardwired UART some 10 years ago, (MR Jan 1990) ; but instead of using 250 kHz carrier and on/off bits, I use the ; Bit formation similar to RC5 at 36...38 kHz carrier: ; ; +++++ +++++ ; ||||| =0 ||||| =1 ; +++++---+ +---+++++ ; ; Interval of packets needs to be somewhat random. ; 1 bit takes approx. 1 ms, one packet about 10 ms ; 1 sec => max. 100 packets ; Sending now at 50ms + (10 * address) interval: ; Address 0...3 -> 40...70 ms interval. ; ; Reading the pot ; =============== ; Reading pot values in much the same way as PC-compatible's ; joystick port! ; ; 1) Make PORTA.4 output and discharge Cap through port. ; 2) Make PORTA.4 input (schmitt!) and wait for going high ; 3) Send number of loop counts it took to go high ; ; More about PC-joystick port, see: ; http://www.epanorama.net/documents/joystick/pc_joystick.html ; ; Datasheet states max. capacitance to be connected ; to any 16F84-port as 50 pF. ; ; Time constant: T(63%)=RC close to schmitt trip level ; ; Connecting Cap from PORTA.4 to gnd, and Pot through ; 22k resistor from Vhi to PORTA.4 ; ; Looping through counter takes approx 4 inst.cycles (4us) ; so min. time (count 1) should be about 4us, ; and max. time (count 255) about 1ms. ; ; 0-> 4us / 33pF = 121 Kohm ; 15-> 60us / 33pF = 2 Mohm ; 255-> 1ms / 33pF = 30 Mohm ; NOTE: will stick to 4 bit resolution for now! ;************************************************************************ ; VARIABLES ;************************************************************************ CBLOCK H'0C' Data1 ;Data from IR-receiver Parity ;Parity bitcount ;bit counter nulcount ;repeat packet counter potvalue ;pot position oldpot ;previous pot value ENDC ;************************************************************************ ; STATICS ;************************************************************************ #DEFINE IRLED PORTA, 0 ;IR LED #DEFINE BUTTON PORTA, 1 ;DIR-button #DEFINE ADDRLO PORTA, 2 ;Address, low bit #DEFINE ADDRHI PORTA, 3 ;Address, high bit #DEFINE POT PORTA, 4 ;potentiometer #DEFINE HALFBIT .203 ;= 255-52 #DEFINE QUADBIT .229 ;= 255-26 constant MAXSPEED =.15 ;max reading for pot ;************************************************************************ ;RESTART/INT-START ;************************************************************************ ORG 0 ; Restart vector goto main ORG 4 ; INT vector retfie ;------------------------------------------------------------------------ ; Initialize I/O ports, Interrupts, Timers etc ;------------------------------------------------------------------------ init movlw b'00011110' ;RA0 =out IR-LED, ;RA1 =in BUTTON, ;RA2:3=in ADDRESS, ;RA4 =in CAP&POT tris porta movlw b'00000000' ;RB0..7=out (TEST LEDS!) tris portb CLRWDT ; bsf STATUS, RP0 ; movlw b'10000010' ;Pullup=off, Prescaler= 1:8 movwf OPTION_REG ; bcf STATUS, RP0 ; clrf nulcount ;clear null packet counter return ;------------------------------------------------------------------------ ; Send 0 [###___] ;------------------------------------------------------------------------ send0 s01 bsf IRLED ;IR-LED on for 13 instr. cycles nop nop nop nop nop nop nop nop nop nop nop nop bcf IRLED ;IR-LED off for 13 instr. cycles nop nop nop nop nop nop nop nop nop btfss INTCON, T0IF ;1/2 bit time gone? goto s01 ;not yet bcf INTCON, T0IF ;clear overflow flag movlw HALFBIT ;new timer base addwf TMR0, f ;add to just overflowed timer s02 btfss INTCON, T0IF ;1/2 bit time gone? goto s02 ;not yet bcf INTCON, T0IF ;clear overflow flag movlw HALFBIT ;new timer base addwf TMR0, f ;add to just overflowed timer return ;------------------------------------------------------------------------ ; Send 1 [___###] ;------------------------------------------------------------------------ send1 s11 btfss INTCON, T0IF ;1/2 bit time gone? goto s11 ;not yet incf PARITY, F ;parity++ bcf INTCON, T0IF ;clear overflow flag movlw HALFBIT ;new timer base addwf TMR0, f ;add to just overflowed timer s12 bsf IRLED ;IR-LED on for 13 instr. cycles nop nop nop nop nop nop nop nop nop nop nop nop bcf IRLED ;IR-LED off for 13 instr. cycles nop nop nop nop nop nop nop nop nop btfss INTCON, T0IF ;1/2 bit time gone? goto s12 ;not yet bcf INTCON, T0IF ;clear overflow flag movlw HALFBIT ;new timer base addwf TMR0, f ;add to just overflowed timer return ;------------------------------------------------------------------------ ;Read pot ;------------------------------------------------------------------------ read_pot bsf STATUS, RP0 ;Select Bank1 and bcf TRISA, 4 ;choose RA4 -> output bcf STATUS, RP0 ;Select Bank0 bcf POT ;discharge cap by grounding nop ;RA4 and keep it down nop ;for a while in case of nop ;current limiting resistor clrf potvalue ;clear previous pot position bsf STATUS, RP0 ;Select Bank1 and choose bsf TRISA, 4 ;RA4 -> input for reading cap bcf STATUS, RP0 ;Select Bank0 nop test_pot btfsc POT ;test if cap charged return ;yes, done! incf potvalue, f ;no, increment counter goto test_pot ;and test again return ;------------------------------------------------------------------------ ; 1ms delay ;------------------------------------------------------------------------ delay1ms bcf INTCON, T0IF ;clear overflow flag movlw .130 ;new timer base addwf TMR0, f ;add to timer d11 btfss INTCON, T0IF ;1ms gone? goto d11 ;not yet return ;------------------------------------------------------------------------ ; MAIN PROGRAMME ;------------------------------------------------------------------------ main call init ;intialize ports m0 call read_pot ;read the pot value ;to potvalue movlw MAXSPEED ;get FF-max_speed to w sublw .255 ;255-MAXSPEED to w addwf potvalue, w ;and add pot value to this. btfss status, c ;Did it go over the top (too fast)? goto m1 ;no, proceed movlw maxspeed ;yes, put maxspeed movwf potvalue ;to potvalue m1 ;##################################################################### ;#TO CREATE MORE TRAFFIC TO TEST COLLISIONS => JUMP TO m2 ; goto m2 ;##################################################################### movfw oldpot ;load old pot value to w xorwf potvalue, w ;and compare with present value. btfss status, z ;Was it equal? goto m2ne ;no, send it! btfss BUTTON ;Check for direction button goto m2ne ;pressed (clear), send it! m2eq tstf nulcount ;Equal! Test if all repeat skpnz ;packets are already sent? goto m0 ;yes, back to square one decf nulcount, f ;no, decrement nul packet count goto m2 ;and send one! m2ne movfw potvalue ;yes, copy present pot value movwf oldpot ;to old pot. movlw .10 ;prepare to send it x times movwf nulcount ;in case not immediately noticed m2 ;---------------------------------------------------------- ; prepare to send packet "AAWDSSSS" ; "AA" =Address ; "W" =0 speed+dir ; =1 F buttons ; "D" =direction button ; or FL ; "SSSS"=Speed from potvalue ; or F0...F4 ; NO F-buttons yet! ;---------------------------------------------------------- ;##### ERROR: BUTTON not polled in oldvalues! ########### ;---------------------------------------------------------- clrf DATA1 ;clear byte to be sent btfss ADDRHI ;Check for address hi bit bsf DATA1, 7 ;set resp. bit in data1 if grounded! btfss ADDRLO ;Check for address lo bit bsf DATA1, 6 ;set resp. bit in data1 if grounded! btfss BUTTON ;Check for direction button bsf DATA1, 4 ;set resp. bit in data1 if grounded! movfw potvalue ;copy pot value to w andlw 0x0F ;clear top bits just to be safe iorwf data1, f ;and set resp. bits in data1 comf DATA1, w ;invert outgoing data and movwf PORTB ;send to LEDs as well! ;------------------------------------------------------------- clrf Parity ;clear Parity, 1's will increment movlw .8 ;all 8 bits movwf BITCOUNT ; bcf INTCON, T0IF ;clear overflow flag movlw HALFBIT ;new timer base movwf TMR0 ;move initial timer base (first round!) call Send0 ;send startbit (won't affect parity!) m3 rlf DATA1, F ;rotate through carry (MSB first) and btfsc STATUS, C ;in case of carry send 1 instead of 0 goto m4 ;carry=1 call Send0 ;carry=0 goto m5 m4 call Send1 m5 decfsz BITCOUNT, F ;all bits sent? goto m3 ;not yet, send more btfsc Parity, 0 ;in case Parity 1 send 1 instead of 0 goto m6 ;Parity=1 call Send0 ;Parity=0 goto m7 m6 call Send1 m7 movlw .40 ;count 40 ms movwf BITCOUNT ;bitcount counts ms now btfss ADDRHI ;Check for address hi bit goto m7_ ;not grounded, goto see lo bit movlw .20 ;was grounded, add 20 ms to loop addwf BITCOUNT, f ; m7_ btfss ADDRLO ;Check for address lo bit goto m8 ;not grounded, out with it! movlw .10 ;was grounded, add 10 ms to loop addwf BITCOUNT, f ; m8 call delay1ms decfsz BITCOUNT, F ;packet interval gone yet? goto m8 ;not yet, wait another millisec! goto m0 ;done, back to square one end