title dccace1.asm LIST P = 16F84A, R = HEX ;Prosessortype, radix INCLUDE "p16f84A.inc" ;w,f,porta,portb etc. ERRORLEVEL -224, -302 ;prevents error from ;"tris"-command __CONFIG _PWRTE_ON & _HS_OSC & _WDT_OFF ;************************************************************************ ; SCHEMATIC DIAGRAM ;************************************************************************ ; ; +---+_+---+ ; Col addr.C PORTA.2 <-|1 18|-> PORTA.1 Col addr.B ; Col addr.D PORTA.3 <-|2 17|-> PORTA.0 Col addr.A ; DCC OUT PORTA.4 <-|3 16|-- XTAL ; RESET Vdd --|4 15|-- XTAL ; Vss(GND)--|5 14|-- Vdd (+5V) ; ROW 1 PORTB.0 ->|6 13|-> PORTB.7 ROW 8 ; ROW 2 PORTB.1 <-|7 12|-> PORTB.6 ROW 7 ; ROW 3 PORTB.2 <-|8 11|-> PORTB.5 ROW 6 ; ROW 4 PORTB.3 <-|9 10|-> PORTB.4 ROW 5 ; +---------+ ; ;=========================================================================== ; Original system has on-off switches, my attempt is to convert ; into (on)-off-(on) switches, first switch found off zero will will be sent ; until released. Must send some idles between packets and only ; idles if no switches are turned ; ; Original addressing scheme: ; ; COL 1 COL2 COL3 ... ; ; ROW 1: A0.1 A2.1 A4.1 ... ; ROW 2: A0.2 A2.2 A4.2 ... ; ROW 3: A0.3 A2.3 A4.3 ... ; ROW 4: A0.4 A2.4 A4.4 ... ; ROW 5: A1.1 A3.1 A5.1 ... ; ROW 6: A1.2 A3.2 A5.2 ... ; ROW 7: A1.3 A3.3 A5.3 ... ; ROW 8: A1.4 A3.4 A5.4 ... ; ; ; Revised scheme ; ; COL 1 COL2 COL3 COL4 COL5 ... COL16 ; ; ROW 1: A1.1+ A1.2+ A1.3+ A1.4+ A2.1+ ... A4.4+ ; ROW 2: A1.1- A1.2- A1.3- A1.4- A2.1- ... A4.4- ; ROW 3: A5.1+ A5.2+ A5.3+ A5.4+ A6.1+ ... A8.4+ ; ROW 4: A5.1- A5.2- A5.3- A5.4- A6.1- ... A8.4- ; ... ; ; Accessory decoder packet format: ; ================================ ; PPPPPP 0 10AA-AAAA 0 1aaa-DCCX 0 EEEE-EEEE 1 PPP... ; ; Where: ; ------ ; P = Preamble min. 14 ones ; A = Address LSB bits ; a = Address MSB bits complemented (0=>1, 1=>0) ; D = Data, w. turnouts must be 1 (lenz requires no resetting to 0) ; C = Turnout number within decoder ; X = which coil within turnout ; E = Error detection byte ; ;********************************************************************************************** ; Original written by Mike Bolton: ; ; This program is for an accessory only encoder. It scans a matrix of ; on / off switches, each with series diodes and detects changes in the ; switch position. Accessory packets are sent to set one of each ; output pair dependent on the switch position. Only one packet is sent ; for each change. If there has been no change, an idle packet is sent. ; A 4 to 16 line multiplexer is used to drive 16 columns. 8 rows are ; sensed by the PIC input lines. This gives a maximum of 128 switches. ; Each set of four switches has a unique DCC address. Column 1 rows 1 to 4 ; are address 0, column 1 rows 5 to 8 are address 1 etc. allowing for upto ; 32 separate decoders, each with 4 output pairs. ; When the encoder is first switched on, all switches are interrogated and ; their positions complemented. This gives the impression that each has changed ; so the encoder sends packets to all outputs to set them to the switch positions ; This is essential for solenoid point motors as they can be in any position ; at switch-on. There is a manual reset button which also sets all points ; correctly in case any have stuck in the wrong position. ; The present program only sends 'activate' packets. It assumes the decoder will ; 'time out' quickly as for solenoid drives. It may be modified for true on / off ; actions for lights. ; ; No aspects of the program are copyright and it may be freely used ; copied, modified or distributed in whole or part. Acknowledgement of the original ; author would be appreciated. ; ; Hardware schematics are also freely available from the author ; email bolton@fs1.with.man.ac.uk ; ; 03/05/02 Corrections and timimg changes ; Working with one decoder 04/05/02 ; Not tested with any more (I only have one!) ;********************************************************************* ; ; Registers used predefined ; ; working registers temp equ 0E ;temp spare equ 0F ;spare colcnt equ 10 ;column counter byte1 equ 11 ;first bute of packet byte2 equ 12 ;second byte of packet byte3 equ 13 ;third byte of packet (for future use) err1 equ 14 ;error byte bitcnt equ 15 ;bit count in packet bytcnt equ 16 ;in packet temp1 equ 17 temp2 equ 18 row equ 19 fcrtmp equ 1A pktcnt equ 1B ;number of packets count4 equ 1C ;extra counter rowcnt equ 1D ;row counter bitnum equ 1E ;sets bit in row (shift register) adrcnt equ 1F ;address counter #DEFINE DCC_OUT porta,4 ;DCC signal out ;************************************************************************* ; org 0 goto setup ;reset vector ; org 04 ;interrupt vector retfie ;return from interrupt ; ;************************************************************************ ; ;start of program. Sets up ports etc. org 10 setup movlw b'11111111' ;RB.1..7=in tris portb ; movlw b'00000000' ;RA.0..4=out tris porta ; ;easy to recall: ;Input -> I -> 1 ;Output-> O -> 0 clrf porta ;clear Port A (Shift reg output) clrf portb ;Port B on (LED test) CLRWDT ; bsf STATUS, RP0 ; movlw b'00000000' ;PullUp=on, int. clk, PreScaler on TMR0=1:2 movwf OPTION_REG ; bcf STATUS, RP0 ; clrf colcnt ; end of setup movlw 0 ;goto init routine goto loop ;*************************************************************** ; ; main jump table main bcf intcon,2 ;clear TMR0 flag main1 addwf pcl,f goto init ;0 goto p2 ;1 packet routine goto one1 ;2 -"- goto zero1 ;3 -"- goto zero2 ;4 -"- goto one2 ;5 -"- goto nxtby1 ;6 -"- goto pr1 ;7 preamble goto pr3 ;8 -"- goto pr4 ;9 -"- goto scand ;10 scan goto scanu ;11 -"- goto c1 ;12 change ;****************************************************************** ; ; timing loop. Waits for TMR0, resets and jumps loop btfss intcon,2 ;wait loop goto loop movwf temp ;save w movlw 0xE6 ;reset TMR0 movwf TMR0 movf temp,w ;recover w goto main ; ;****************************************************************** ; ; Initialise sequence ; reads all switches and complements them ; so it appears as if they have all changed ; cycles through all outputs of all decoders ; so starting settings are correct init movlw .10 movwf pktcnt ;send 10 reset packets call reset movlw .10 movwf pktcnt ;send 10 reset packets call idle clrf pktcnt ;maybe not necessary ;*********************************************************** ; ; main read loop ; movlw b'00010000' ;dcc_out set, row=0 movwf porta ;set out clrf row ;clear row clrf colcnt ;clear col count clrf rowcnt ;clear row count scan movlw .10 ;wait before scand goto loop ;in the loop scand bcf DCC_OUT ;output down comf portb, w ;get row data movwf row ;save in row skpz ;no change goto change ;yes, out with it scan1 movlw .11 ;wait before scanu goto loop ;in the loop scanu bsf DCC_OUT ;output up incf colcnt,w ;increment column andlw B'00001111' ;columns 0 to 15 movwf colcnt movf porta,w ;get port a andlw B'11110000' ;save DCC_OUT, discard address iorwf colcnt,w ;get new column address iorlw B'00010000' ;keep dcc output movwf porta ;select new column incf pktcnt,f ;one packet call idle ;to give delay goto scan ;------------------------------------------------------------ ; Here if switch set ; ------------------ ; PPPPPP 0 10AA-AAAA 0 1aaa-DCCX 0 EEEE-EEEE 1 ; ; Create packet from colcnt and rowcnt: ; ; colcnt low nibble => A1, A0, C1, C0 ; rowcnt low nibble => A4, A3, A2, X ;----------------------------------------------------------- change clrf rowcnt ;row's bit pos denotes decf rowcnt, f ;rowcnt value c_loop incf rowcnt, f ;value converted to binary w. rrf row, f ;rotate right throuh carry skpc ;if carry is not found goto c_loop ;we'll rotate more movlw B'10000000' ;Byte 1: 10AA-AAAA movwf byte1 ;-------------------- btfsc colcnt, 2 ;Test column bit 2 (A0) bsf byte1, 0 ;yes set A0 btfsc colcnt, 3 ;Test column bit 3 (A1) bsf byte1, 1 ;yes set A1 btfsc rowcnt, 1 ;Test row bit 1 (A2) bsf byte1, 2 ;yes set A2 btfsc rowcnt, 2 ;Test row bit 2 (A3) bsf byte1, 3 ;yes set A3 incf byte1, f ;shift to Lenz addressing movlw .12 ;wait before jumping to c1 goto loop ;inside loop c1 bsf DCC_OUT ;output up movlw B'11111000' ;Byte 2: 1111-1CCX movwf byte2 ;-------------------- btfsc colcnt, 0 ;Test column bit 0 (C0) bsf byte2, 1 ;yes set C0 btfsc colcnt, 1 ;Test column bit 1 (C1) bsf byte2, 2 ;yes, set C1 btfsc rowcnt, 0 ;Test row bit 0 (X) bsf byte2, 0 ;yes, set X movlw 3 ;total 3 bytes (E inclusive) movwf bytcnt ;to bytecount call preamb ;send preamble call packet ;send the packet proper goto scan ;loop again ;***************************************************** ; ; subroutines ; ; ;****************************************************** ; ; sends a complete reset packet ; number of packets in pktcnt ; reset movlw B'00000000' movwf byte1 movlw B'00000000' movwf byte2 movlw 3 movwf bytcnt call preamb call packet decfsz pktcnt,f goto reset return ; ;****************************************************** ; ; sends a complete idle packet ; number of packets in pktcnt idle movlw B'11111111' movwf byte1 movlw B'00000000' movwf byte2 movlw 3 movwf bytcnt call preamb call packet decfsz pktcnt,f goto idle return ; ;**************************************************************** ; ; main packet routine ; ; sends a packet without preamble ; data to be set in byte1 to byte3 etc ; number of bytes in packet in bytcnt ; routine works out the error byte itself ; adds start bits ; must arrive with the DCC output high ; ; packet movlw byte1 ;point FSR to start of bytes movwf FSR movf bytcnt,w ;get no of bytes movwf temp decf temp,f decf temp,f movf INDF,w ;get 1st byte incf FSR,f p1 xorwf INDF,w ;work out error incf FSR,f decfsz temp,f goto p1 movwf INDF ;error byte movlw byte1 ;reset index movwf FSR ploopa btfss intcon,2 ;wait for TMR0 goto ploopa movlw 0xED ;sets zero for 100 usec. movwf TMR0 bcf intcon,2 movlw .9 movwf bitcnt ;set bitcount (8 bits) movlw .1 ;wait for TMR0 in main loop goto loop ;jump to p2 p2 bcf DCC_OUT ;output lo (first half of start bit complete) ; ; second half of start bit ; ploop2 btfss intcon,2 goto ploop2 movlw 0xED ;reset TMR0 movwf TMR0 bcf intcon,2 ; ; setup for a byte before end of start bit ; nxt1 decfsz bitcnt,f ;last bit? goto nxtbit ;no so next bit goto nxtbyt ;yes so next byte nxtbit rlf INDF,f ;roll the data skpc goto zero ;wait for TMR0 then jump to ;a one or a zero movlw .2 ;one1 goto loop ; ; bit is a zero ; zero movlw .3 ;zero1 goto loop zero1 bsf DCC_OUT ;output up z1 btfss intcon,2 ;miss a count as it is a zero goto z1 movlw 0xED ;reset TMR0 movwf TMR0 ;value to make zero = 100usec. bcf intcon,2 movlw .4 ;wait again then goto zero2 goto loop zero2 bcf DCC_OUT ;output down (end of first half) ; ; second half of a zero ; z2 btfss intcon,2 ;miss a count goto z2 movlw 0xED ;reset TMR0 movwf TMR0 bcf intcon,2 z3 goto nxt1 ; ; bit is a one ; one1 bsf DCC_OUT ;output up movlw .5 ;one2 goto loop ; ; second half of a one ; one2 bcf DCC_OUT ;output down goto nxt1 ; ; get next byte ; nxtbyt incf FSR,f movlw .9 movwf bitcnt movlw .6 ;nxtby1 goto loop nxtby1 bsf DCC_OUT ;output up decfsz bytcnt,f ;last byte goto ploopa ;start bit of next byte return ;no more bytes in packet ;************************************************************* ; ;sends a passive preamble of 10 cycles ;arrive with output hi ;leaves with output hi (ready for packet) preamb movlw .14 ;14 preamb cycles movwf count4 movlw .7 ;pr1 goto loop pr1 bcf DCC_OUT ;output down decfsz count4,f goto pr2 movlw .8 ;pr3 goto loop pr3 bsf DCC_OUT ;output up return ;end of preamble pr2 movlw .9 ;pr4 goto loop pr4 bsf DCC_OUT ;output up movlw .7 ;pr1 goto loop end