;************************************************************************ ; TaPRK IR-LINK-TRANSMITTER BUTTON 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 ;************************************************************************ ; +---+_+---+ ; N/C PORTA.2 ->|1 18|<- PORTA.1 N/C ; N/C PORTA.3 ->|2 17|-> PORTA.0 IR-LED act.hi ; N/C PORTA.4 ->|3 PIC 16|-- XTAL (4MHz) ; (+5V) MCLR --|4 16F 15|-- XTAL ; (GND) Vss --|5 84A 14|-- Vdd (+5V) ; ACCEL. SW PORTB.0 ->|6 13|<- PORTB.7 N/C ; BRAKE SW PORTB.1 ->|7 12|<- PORTB.6 N/C ; DIR. BUTTON (R) PORTB.2 ->|8 11|<- PORTB.5 N/C ; F0/5 BUTTON (Y) PORTB.3 ->|9 10|<- PORTB.4 F1 BUTTON (G) ; +---------+ ;************************************************************************ ; 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. ; ; 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 count_0 ;typematic counter ENDC ;************************************************************************ ; STATICS ;************************************************************************ #DEFINE IRLED PORTA, 0 ;IR LED #DEFINE ACCEL_SW PORTB, 0 ;!Faster #DEFINE BRAKE_SW PORTB, 1 ;!Slower #DEFINE DIR_BUTTON PORTB, 2 ;!Direction/Emg.Stop #DEFINE FL_BUTTON PORTB, 3 ;!FL/F5 #DEFINE F1_BUTTON PORTB, 4 ;!F1 #DEFINE ADDRLO PORTB, 6 ;!Address, low bit #DEFINE ADDRHI PORTB, 7 ;!Address, high bit #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'00000010' ;RA0=out, RA1=in RA2:4=out tris porta movlw b'11111111' ;RB0..7=in tris portb CLRWDT ; bsf STATUS, RP0 ; movlw b'00000010' ;Pullup=on, Prescaler= 1:8 movwf OPTION_REG ; bcf STATUS, RP0 ; clrf potvalue ;nopeus nollaan movlw .10 ; movwf nulcount ;start by sending 10 packets ;------------------------------------------------------------------------ ; Increment throttle's typematic counters ;------------------------------------------------------------------------ IncCounters tstf count_0 ;set zero flag from counter skpz ;skip if zero incf count_0, f ;not yet -> increment 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 switch ;------------------------------------------------------------------------ read_sw tstf potvalue ;check if speed skpnz ;is zero? goto ad1 ;yes, no need for emg.stop btfss DIR_BUTTON ;no, check if button is pressed clrf potvalue ;yes, speed -> 0 ad1 btfsc ACCEL_SW ;faster-bit cleared? goto ad1s ;goto cab_1 slower ad1f tstf count_0 ;check if typematic still on skpz ;skip if typematic clear return ;no, pass movlw .240 ;Typematic seed is now 200 movwf count_0 ;start typematic incf potvalue, f ;accelerate btfss potvalue, 4 ;going too fast return ;no, done with this movlw 0x0f ;top speed is 15 movwf potvalue ;and we settle for that! return ;done! ad1s btfsc BRAKE_SW ;slower-bit cleared? goto ad1nop ;goto cab_1 nop tstf count_0 ;check if typematic still on skpz ;skip if typematic clear return ;no, pass movlw .240 ;Typematic seed is now 200 movwf count_0 ;start typematic tstf potvalue ;accelerate skpz ;already standstill? decf potvalue, f ;no, let's put on brakes return ;done! ad1nop clrf count_0 ;clear typematic counter return ;and done! ;------------------------------------------------------------------------ ; 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 IncCounters ; call read_sw ;read the accel/brake buttons (switch) ;to potvalue m1 comf PORTB, w ;copy and invert inputs to w andlw b'00111111' ;mask address bytes away to see skpz ;if any buttons pressed? goto m2 ;yes, out with it! tstf nulcount ;none! Test if all null packets sent? skpnz ; goto m0 ;yes, back to square one decf nulcount, f ;no, decrement nul packet count goto m2nul ;and send one! m2 movlw .3 ;prepare to send X null packets movwf nulcount ;in case no buttons pressed m2nul ;---------------------------------------------------------- ; 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: BUTTONS 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 DIR_BUTTON ;Check for direction button bsf DATA1, 4 ;set resp. bit in data1 if grounded! btfss FL_BUTTON ;Check for FL button (simplified) bsf DATA1, 4 ;set dir. bit in data1 if grounded! btfss F1_BUTTON ;Check for F1 button (simplified) bsf DATA1, 4 ;set dir. 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 ;------------------------------------------------------------- call IncCounters ; 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