; ************************************************************************** ; * * ; * Railway Receiver Module for the PICAXE-08 PICAXERW.BAS * ; * * ; ************************************************************************** SYMBOL UNIT_ADDRESS = $FFFF ; Must be unique for all receivers ; 4321 ; Output bit settings ... SYMBOL ACTIVE_LOWS = %0000 ; Active low outputs SYMBOL AUTO_PULSED = %0000 ; Outputs must pulse SYMBOL PULSE_LENGTH = 20 ; Pulse length in 1mS units ; .------------------------------------------------------------------------. ; | | ; | Version 2.0 | ; | Last Update 2004-08-26 | ; | | ; | Target PICAXE-08 | ; | Compiler Used Revolution Programming Editor 4.1.4 | ; | Memory Used 120 bytes of 128, 8 unused | ; | | ; | Author The Happy Hippy | ; | Web Site www.hippy.freeserve.co.uk/picaxerw.htm | ; | Email hippy@psynet.net | ; | | ; | Copyright (C) 2004, The Happy Hippy | ; | | ; `------------------------------------------------------------------------' ; ************************************************************************** ; * * ; * Receiver Module Circuit Diagram * ; * * ; ************************************************************************** ; 5V >----.-----------------------------.----> 5V ; | | ; | 100nF PICAXE-08 | ; __|__ .----.----. | ; --.-- .---.---| 0V +V |---' ; | | `---| SI O0 |--------> OUT1 ; | | .---| D4 A1 |--------> OUT2 ; RX >----|-------|---|---| I3 D2 |--------> OUT3 ; | | | `---------' .----> OUT4 ; | | `-----------------' ; | | ; 0V >----^-------^--------------------------> 0V ; ************************************************************************** ; * * ; * Network Configuration * ; * * ; ************************************************************************** ; 9600 2400 ; baud baud ; PSU Controller Receiver ; .------. .--------. .--------. ; | +V |---.------------>| +V 5V |----.--------->| 5V |---> OUT1 ; | 0V |---|--. .------>| RX CX |----|--.------>| RX |---> OUT2 ; `------' | | | .----| TX | | | | |---> OUT3 ; | }--|--|--->| 0V 0V |----|--|--.--->| 0V |---> OUT4 ; | | | | `---.----' | | | `--------' ; PC | | | | | : : : ; .------. | | | | .--^--. : : : Receiver ; | TX |---|--|--{ | | LCD | | | | .--------. ; | RX |<--|--|--|--{ `-----' }--|--|--->| 5V |---> OUT1 ; | 0V |---|--{ | | | }--|--->| RX |---> OUT2 ; `------' | | | | | | | | |---> OUT3 ; | | | | | | }--->| 0V |---> OUT4 ; KEYPAD | | | | | | | `--------' ; .------. | | | | : : : ; | +V |<--' | | | : : : Receiver ; | TX |------|--' | | | | .--------. ; | RX |<-----|-----' `--|--|--->| 5V |---> OUT1 ; | 0V |<-----' `--|--->| RX |---> OUT2 ; `--.---' | | |---> OUT3 ; | `--->| 0V |---> OUT4 ; .--^---. `--------' ; |[][][]| ; |[][][]| ; |[][][]| ; `------' ; ; Note that the network uses its own protocol which is not compatible ; with other model railway communications systems ( DCC etc ). The ; network is based upon a serial communications network running at ; 2400 baud, 1 stop bit and no parity. Reveived data normally comes ; from a dedicated controller but can also be driven from a PC using ; a suitable resistor buffer to convert the voltages ... ; ; 5V >---------------------------. ; | Receiver ; PC | .--------. ; .------. ___ `---.--------->| 5V |---> OUT1 ; | TX |----------.---|___|--------|--.------>| RX |---> OUT2 ; | RX | .|. 22K | | | |---> OUT3 ; | 0V |---. | | .---|--|--.--->| 0V |---> OUT4 ; `------' | |_| 10K | | | | `--------' ; | | | : : : ; 0V >-------^------^------------' ; ************************************************************************** ; * * ; * Constant Definitions * ; * * ; ************************************************************************** SYMBOL RX = 3 SYMBOL RX_BAUD = N2400 ; ************************************************************************** ; * * ; * Variable Definitions * ; * * ; ************************************************************************** SYMBOL byte = b0 SYMBOL outBits = b1 SYMBOL matchAdr = w1 ; b3:b2 SYMBOL matchAdrLsb = b2 SYMBOL matchAdrMsb = b3 SYMBOL adr = w2 ; b5:b4 SYMBOL adrLsb = b4 SYMBOL adrMsb = b5 SYMBOL action = b6 ; ************************************************************************** ; * * ; * Power-On Reset Initialisation * ; * * ; ************************************************************************** ; Because the PICAXE-08M has reversable input and outpins, we set the ; output pins and force them to low levels. PowerOnReset: LOW 0 ; OUT1 is output, low LOW 1 ; OUT2 is output, low LOW 2 ; OUT3 is output, low LOW 4 ; OUT4 is output, low ; ************************************************************************** ; * * ; * Read a command, and check if intended for this receiver module * ; * * ; ************************************************************************** ; All commands are three bytes long, with two nibbles in each byte, ; giving a six nibble command ... ; ; adrMsb adrLsb action ; .-------------.-------------.-------------. ; | aaaa | bbbb | cccc | dddd | wxyz | WXYZ | ; `-------------^-------------^-------------' ; ; The first four nibbles 'abcd' is the address of the receiver module ; which is to respond to the command. We compare 'abcd' with that set ; by 'SYMBOL UNIT_ADDRESS = $abcd' at the top of this source. If the ; address matches we obey the action. If any of the nibbles 'abcd' ; are zero, we consider that digit of the address matched with ours ; regardless of what this unit's address is. This allows 'wildcard ; addressing' so a single action can be sent to multiple receivers. ; ; The addressing scheme allows 50,625 separate receiver units to used ; on a single network. Over 200,000 lights, 100,000 points and 50,000 ; signals can be controlled by a single network. This receiver unit ; can be used to control lights, points and signals. WaitForCommand: ; Read the three byte, six nibble command packet SERIN RX,RX_BAUD,adrMsb,adrLsb,action ; Get this receiver's address and modify it so that any wildcard ; addresses will be accepted. matchAdr = UNIT_ADDRESS IF adrMsb > $0F THEN NoWildCardFirstDigit matchAdrMsb = matchAdrMsb & $0F NoWildCardFirstDigit: byte = adrMsb & $0F IF byte <> $00 THEN NoWildCardSecondDigit matchAdrMsb = matchAdrMsb & $F0 NoWildCardSecondDigit: IF adrLsb > $0F THEN NoWildCardThirdDigit matchAdrLsb = matchAdrLsb & $0F NoWildCardThirdDigit: byte = adrLsb & $0F IF byte <> $00 THEN NoWildCardFourthDigit matchAdrLsb = matchAdrLsb & $F0 NoWildCardFourthDigit: ; If the command is directed at us specifically, or because a ; wildcard address matches with our receiver address then the ; command is obeyed, otherwise we simply ignore it and wait for ; the next command. IF matchAdr <> adr THEN WaitForCommand ; ************************************************************************** ; * * ; * Obey a command * ; * * ; ************************************************************************** ; Every command includes an action byte, two nibbles which indicates ; what the receiver should do when the command is received ... ; ; action ; .-------------. ; | wxyz | WXYZ | ; `-------------' ; ; The bits of each nibble 'wxyz' and 'WXYZ' relate to each of the ; receiver units digital outputs; w/W is OUT4, x/X is OUT2, y/Y is ; OUT2 and z/Z is OUT1. ; ; When a bit is set (1) in 'wxyz' the corresponding output bit is set ; high. ; ; When a bit is set (1) in 'WXYZ' the corresponding output bit is set ; low. ; ; When a bit is set (1) in both 'wxyz' and 'WXYZ' the corresponding ; output bit is set high for a period defined by 'SYMBOL PULSE_LENGTH' ; at the the top of this source and is then set low again. ; ; Examples ... ; ; .-------------. ; | 1000 | 0000 | Sets OUT4 high ; `-------------' ; .-------------. ; | 0000 | 0100 | Sets OUT3 low ; `-------------' ; .-------------. ; | 0000 | 1111 | Sets OUT4, OUT3, OUT2 and OUT1 low ; `-------------' ; .-------------. ; | 1010 | 1001 | Pulses OUT4, sets OUT2 high and sets OUT1 low ; `-------------' ; .-------------. ; | 0000 | 0000 | No changes made ; `-------------' ; ; For specific point and signal configurations, the following ; commands could be used ... ; ; Points - OUT1/OUT2 to solenoids, OUT3/OUT4 routing indicators ; ; 0101 1011 Pulse OUT1, set OUT3, clear OUT4 ; 1010 0111 Pulse OUT2, clear OUT3, set OUT4 ; ; Dual Points - OUT1/OUT2 to solenoids #1, OUT3/OUT4 to solenoids #2 ; ; 0001 0011 Pulse OUT1 - Points #1 through ; 0010 0011 Pulse OUT2 - Points #1 turned ; 0100 1100 Pulse OUT3 - Points #2 through ; 1000 1100 Pulse OUT4 - Points #2 turned ; ; Three light signals - OUT1=Red, OUT2=Yellow, OUT4=Green ; ; 0001 1110 Set Red ; 0010 1101 Set Yellow ; 1000 0111 Set Green ; ; Four light signals - OUT1=Red, OUT2/OUT3=Yellow, OUT4=Green ; ; 0001 1110 Set Red ; 0010 1101 Set Yellow Top ; 0100 1011 Set Yellow Bottom ; 0110 1001 Set both Yellow ; 1000 0111 Set Green ObeyCommand: ; Handle the 'wxyz' bits. If none of the 'wxyz' bits are set then ; we don't set any outputs and we won't need to do any pulsing. IF action <= $0F THEN DoClearBits ; Some of the outputs we have may always need to be pulsed ( such as ; those driving points solenoids which burn out if activated for too ; long ). If we set an output which must be pulsed, we automatically ; set the output to be cleared as well, which invokes the pulse, ; rather than allowing it to be set permanently on. action = action / 16 & AUTO_PULSED | action ; Set the bits which need setting. DoSetBits: outBits = action / 16 | outBits ; Set the output bits byte = outBits ^ ACTIVE_LOWS ; Set correct polarity bit4 = bit3 ; Put OUT4 on correct pin pins = byte ; Update the output pins ; If we set a bit then we need to check if we are also clearing ; that bit, and if we are, it is a pulse, so we need to make sure ; the pulse happens. byte = action / 16 ^ action & action IF byte = 0 THEN DoClearBits ; The pulse length is set by 'SYMBOL PULSE_LENGTH' at the top of this ; source and is specified in 1mS intervals. DoPulseDelay: PAUSE PULSE_LENGTH ; Handle the 'WXYZ' bits. If none of the 'WXYZ' bits are set then ; we won't clear any outputs. We execute the code regardless rather ; than checking if we actually do anything because it keeps the ; program space shorter and saves some execution time. DoClearBits: outBits = action & $0F ^ $0F & outBits ; Clear the output bits byte = outBits ^ ACTIVE_LOWS ; Set correct polarity bit4 = bit3 ; Put OUT4 on correct pin pins = byte ; Update the output pins GOTO WaitForCommand ; ************************************************************************** ; * * ; * End of Railway Receiver Module for the PICAXE-08 * ; * * ; **************************************************************************