Subject: here is the file for X10 (to put on your site) Date: Friday, June 04, 1999 6:25 AM OK....here is the rather unorganized, but in chronological order of the X10 stuff I have kept. You might want to clean up the formatting some...? I appreciate your offer to put on your site, as I know that many are not interested and would hate to have to download. ------------------------------------------ cut here -------------------------------------------- I'm sure hoping code is available. This seems like such a natural thing to do for a microcontroller project (given the prices of much of the more versatile home automation stuff) that I hadn't really considered the possibility that it hadn't been done yet. A quick web search finds at least one page selling PIC X10 code and power line interfaces: http://users1.ee.net/web_surf/Mchip.htm Also the PIC C compiler from CCS for the MicroChip PIC16 processors includes software drivers for X10 (and a whole load of other stuff) for $99 http://ccsinfo.com/picc.html So, apparently this is not an uncommon application. Anybody know of any free X10 code or power line interfaces? You may want to look at http://www.x10.com/products/x10_tw523.htm The TW523 module connects to the wall - all you need to do is provide the data with the correct timing (TX and RX). This device frees you from having to deal with the AC line (hazardous). Somewhere on that page there is link to a PDF file that describes the device in detail, including timing, etc. As I recall, there may have also been a schematic. Try using ST7537 or TDA5051 (better) instead of X10. It΄s safer, allows bigger systems, and cheaper. have now added a PIC resources page to my home page. Most of it is directly related to home automation. Look at http://www.xs4all.nl/~falstaff/ihome.html or http://www.xs4all.nl/~falstaff/picres.html The basic stamp 2 has built in BSR module controller commands, I See in home automation catalogs a module with a 4 pin phone type connector made to interface the signals to the power lines. look at http://www.micromint.com/plix.html they sell a custom IC that does it all for you.... don't know if this was mentioned before but a new protocol is emerging called CEBus. This is supposed to handle things like home automation using many transmission mediums including power lines. I don't know if anything is available yet. Try http://www.intellon.com http://www.cebus.org http://www.hometoys.com I have uploaded to SimTel, the Coast to Coast Software Repository (tm), (available by anonymous ftp from ftp.coast.net and other SimTel mirrors): http://www.coast.net/SimTel/msdos/x_10.html irdc240.zip Send commands to a ONE FOR ALL Remote Control IRDC - INFRA-RED Direct Control-Version 2.40. Control your ONE-FOR-ALL (Supported Models: URC2005, URC4000, URC4005, URC4050, URC5000, URC6050) remote control from your PC. Full screen Point & Click DOS character interface. Your PC screen becomes a large remote keypad. This shareware version will run with or without a ONE-FOR-ALL remote control & special serial cable (the cable can be ordered from Home Automation Dealers). IRDC when used with an I/R extender(eg.X-10 Powermid) is an inexpensive way to automate I/R signal distribution. Includes IRDQ, a command line version. CIS Reg. ID# 1449. PsL Program #14461. Uploaded by Author. Special requirements: ONE FOR ALL Remote Control & Special Serial Cable Changes: Support for upgraded URC-4050 chipsets added. Replaces: irdc220.zip ShareWare. Uploaded by the author. David Huras davidhuras@inforamp.net >If you just need to send a simple RUT or on/off via the >powerline - no data, etc, why not just modulate the 60cycle >with some tone. Use a tone decoder at the other end. You'll >need a transformer and associated parts for isolation and >filtering. Best way is to use LM1893 from National Semiconductor. It include Power stage, FM modulator / Demodulator, limiter and auto-level setup to receive. This circuit is specially design to do such transmission through AC power line. It's old enought to be available anywhere. >I have looked at the PLIX controller and TW-523 interface. They seem >to solve my problem, yet they are very expensive. Over $100 for >2 of each device. The list price for a TW523 is $30 US. Contact Worthington Distribution Talk to Richard (Tell him I sent you) and he will sell you one for $18 The unit comes with a good description of the X10 protocol. It is quite slow. About 1 second to send each message. The TW523 does not allow arbitrary messages to be received, they must conform to the protocol exactly. I tried the NE5050N a couple of years ago and it worked just fine to transmitt serial data on the mains (managed to go up to 1200 bps) but I also suggest you take a closer look at SGS-Thomson's ST7536 and the newer ST7537HS1 Power Line Modems, ST7537HS1 is capable to transmitt at 2400 bps. Have you concidered using a Power Line Modem like the NE5050N. This device cost about 10 dollars (from a Swedish pricelist). You can transmit any binary serial datastream up to 300 kbit/s over a twisted pair cable and typical 1 kbit/s over a mains wire (with the suggested circuit). To make it work, you have to buy the NE5050N and a few discrete components like coils, a simple mains separating transformer, a current generator (matched transistor pair) and the usual components, resitors, capacitors ... Before you get lulled into the novelty of homebrew device control, Please take a long and healthy look at the strategy for 'Networking' your PIC nodes. How will you manage the address of each node? Will they be grouped or segmented? How will they get 'broadcast-to-all/group' system updates from host? How will you handle the shifting priorities of arising emergency conditions? How will the system & network handle accidental collisions of data on the network. Each PIC node unit will need to do the device control and manage network comm protocol. You may want to use an LSI chip to handle network overhead. How will you load sfwr changes to the node MCUs and call/schedule their data feeds to the host? Can nodes exchange/share/control devices by interacting between themselves? How will the host moderate/assign such 'distributed processing'? Good reading is the Byte & Circuit Cellar Ink magazine articles on the development of Home Control System by Steve Ciarcia. His ongoing discussion of path choices will save you from reinventing the wheel. Also get info on LON-Local Operating Network and CEBus. Then you can better establish the architecture of your system   ;*************************************** ; READ.ME FILE FOR ; ; LIBRARY OF UTILITIES FOR PIC ; ; EDWARD CHEUNG, PH.D. ; ; 14505 DOLBROOK LANE ; ; MITCHELLVILLE, MD 20721 ; ; ebc714@rs710.gsfc.nasa.gov ; ;*************************************** Introduction This library of utilities was written for the 16C71 microcontroller, but can be adapted for use on other PIC chips. The library is fully interrupt based: sending and receiving of data in various formats occurs in the background using interrupts. The 'main' program just sets some variables and calls the appropriate routine. The data will be sent in the background at the proper rate and time. The included demo.asm program runs a simple RS232 controlled Infra Red remote with LCD display. See the end if this file for more info. General Description The functions that interface to each type of hardware are arranged into modules. Each of these modules can be disabled or enabled at the top of the main program (see demo.asm) in order to include only those that you need for the particular PIC that you are using. Being a first time assembly programmer, I wrote the code in C, which is then hand compiled to PIC mnemonics. The C code is included at the end of each line, allowing me to quickly read a section to find out what the code does. It also made debugging a lot easier because I could follow the program flow (if - then - else - else etc.). My naming convention is to add three common characters to all labels and function names in a module. For example, all names in the RS232 module start with R2_, all of those in the IR module starts with IR_. This is in order to facilitate the reading of my code. As mentioned above when you want to send data (IR,RS232 etc) you call the appropriate routine in the associated module. For example, to send a character down the RS232 line, you call R2_SEND. This is then placed into a FIFO, and then sent according to the correct timing. If the FIFO is full, the function will wait until there is a spot open in the FIFO before returning to the main program. Whenever new data is received, the function XX_NEW is called (where XX is the module abbreviation). Look for these functions in the lib.h file. In these functions is where you add your code to do the processing of new incoming data. Currently incoming data is either sent to the LCD display or the RS232 line. Specifically, incoming data is processed as follows: Incoming data Displayed on Comments RS232 RS232 Typing characters to PIC causes simple echo RS422 RS422 Typing characters to PIC causes simple echo IR LCD Displays device and key code of IR command X-10 LCD Displays house and unit code of command By customizing R2_NEW_BYTE, IR_NEW, TW_NEW etc. you can tailor the response to incoming data. I have written some memory management routines that automatically assign register locations to variables. Here is an example. To allocate a register location to the variable TEMP_W, and TEMP_STAT, you use the syntax: ALLOC TEMP_W ALLOC TEMP_STAT Since this is the first ALLOC statement, TEMP_W is assigned the register 0CH, and TEMP_STAT is assigned the location 0DH. You can continue to do this for all your variables until you run out of memory. When this occurs, the compiler will hit the statement: CALL OUT_OF_MEMORY This is a dummy call, and will cause an error message with the words OUT_OF_MEMORY. When you see this, you know that you have run out of RAM. The above mechanism allows you to enable and disable modules and have the memory locations be allocated efficiently. In other words, you can have a PIC with just the RS232 module enabled, and expand the FIFO to use as much RAM as possible. Don't forget to set the variables FXTAL and INTSEC at the top of the lib.h file. The former is your clock frequency, the latter is the desired number of interrupts/second. Bugs As mentioned above, to send something, you just set some variables, and call the appropriate routine. If the send queue is full, the routine has to wait until the interrupt handler empties a spot. The problem occurs when the interrupt handler itself needs to send data. If the queue is full, the microprocessor will hang (since the queue will never empty). In that case, the watchdog timer will timeout, and the chip resets. The above problem can occur especially with the IR and X-10 modules. Their send queues are only one command deep (due to limited memory on PICs). You must be careful not to send too many commands per second. One way to prevent the watchdog from timing out is to write a second version of the send initiate routine--one that is called by the interrupt service routine only. This version does not wait until the queue has an open spot, but returns immediately. With or without this second version of the send routine, data is lost anyway. This situation can be properly remedied by allocated more memory to their send routines and writing larger FIFOs for them. Modification History. See lib.h for mod history. Circuit Connection for 16C71 I am working on a circuit schematic. In any case, the circuit is simple enough that you can wire it up with the info below. 1 (X-10) TW523 data output (see Note 1) 2 (IR) input (see Note 4) 3 (IR) output 4 +5 Volt (Mclr) 5 Ground 6 (LCD) DB4 (see Note 2) 7 (LCD) DB5 8 (LCD) DB6 9 (LCD) DB7 10 (LCD) ENABLE 11 (LCD) Register Select 12 (RS232) input (see Note 3 13 (RS232) output 14 +5 Volt 15 crystal 16 crystal 17 (X-10) TW523 zero crossing input 18 (X-10) TW523 data input Notes. 1) TW523 pin 2 goes to ground. 2) LCD is an Optrex DMC Series 16x1 line display from ALL ELECTRONICS. Supply power and ground according to spec, add a contrast control pot. Be sure R/W input of LCD is grounded. 3) Use an RS232 driver such as the Maxim MAX203. 4) IR input is from a 'cube' such as Radio Shack 276-137. IR output goes to a 40KHz gated IRED flasher. When the output goes 'high', the IRED should flash. I use a 555 oscillator (has high current sourcing capability) by applying the gate input to pin 4. Distribution Policy This software is intended for non commercial use and as shareware. Your contribution can be anything you wish, but I think that $15 to $30 is a common shareware fee. Please mail to the address at the top of this file. The files follow in text format. The top of each file is marked by a line of asterisks *******. The following files are in the package: read.me ;you are reading this file. irdemo.asm ;assemble this file - starts with some simple demos, and ;continues with an RS232 controlled IR remote. The mapping ;of RS232 characters to IR function is as follows: ;U - Volume Up. D - Volume Down. ;u - Channel Up. d - Channel Down. ;Send the above characters to the chip, and it sends out the ;corresponding IR command. The LCD display shows all received ;IR commands, and characters typed from the RS232 port. x10demo.asm ;assemble this file - has RS232 controlled X10 interface. ;format of commands is: XC_NN, where NN is the X10 ;command. Example 'Et' is Housecode E and Keycode ON. ;Response is CX_NN, format similar to commands. p16cxx.inc ;file from Microchip, contains defs for P16 family of registers. lib.h ;pic library. The last line in this message should be: ;***** END OF FILE ***** Let me know if it isn't. All the best! ;*************************************** TITLE "Library Demo Program" ; Edward Cheung, Ph.D. ; ; Compiled with MPASM 1.20 ; ; Loaded with PICSTART 4.02 ; ;*************************************** ;Select library modules. Use 1/0, TRUE/FALSE not defined yet. CONSTANT AD_ENABLE = 0 CONSTANT R2_ENABLE = 1 CONSTANT R4_ENABLE = 0 CONSTANT LCD_ENABLE = 1 CONSTANT IR_ENABLE = 1 CONSTANT TW_ENABLE = 0 INCLUDE "LIB.H" ;pic library MAIN ;Initializations CALL GEN_INIT ;simple module demos IF LCD_ENABLE == TRUE MOVLW 'H' ;Print 'Hi' on LCD CALL LCD_PRINT MOVLW 'i' CALL LCD_PRINT MOVLW H'10' ;Put cursor at start CALL LCD_PRINT CLRWDT ENDIF IF R2_ENABLE == TRUE ;Print 'Hi' on terminal MOVLW 'H' CALL R2_SEND MOVLW 'i' CALL R2_SEND CLRWDT ENDIF IF TW_ENABLE == TRUE MOVLW 'E' ; tw_o_house = E; MOVWF TW_T_HOUSE MOVLW '1' ; tw_o_key = 1; MOVWF TW_T_KEY CALL TW_SEND MOVLW 'E' ; tw_o_house = E; MOVWF TW_T_HOUSE MOVLW 't' ; tw_o_key = on; MOVWF TW_T_KEY CALL TW_SEND ; Send CLRWDT ENDIF IF IR_ENABLE == TRUE MOVLW D'1' ; TV = 1 MOVWF IR_T_DEV MOVLW D'19' ; Volume Down = 19 MOVWF IR_T_DATA CALL IR_SEND ; Send CLRWDT ENDIF ;Do some real work with the library ;vars for RS232->IR command interpreter ALLOC COM_BYTE ;int com_byte; //received byte to interpret MAIN_LOOP GOTO MAIN_LOOP ;//do foreground processing here IF R2_ENABLE == TRUE ;This gets called when there is a new byte from rs232 serial line. ;A 'U' causes a 'Volume Up' command to be sent, a 'D' causes a ;'Volume Down' to be sent, a 'u' causes a Channel Up, and a 'd' ;a Channel Down (in SONY SIRCS format). R2_NEW_BYTE MOVWF COM_BYTE ;com_byte = W; CALL R2_SEND ;//echo to serial out R2_TEST_VOUP ;if (com_byte == 'U') MOVFW COM_BYTE SUBLW 'U' SKPZ GOTO R2_TEST_VODN MOVLW D'1' ; TV = 1 MOVWF IR_T_DEV MOVLW D'18' ; Volume Up = 18 MOVWF IR_T_DATA CALL IR_SEND ; // Send IR GOTO R2_NEW_END R2_TEST_VODN ;else if (com_byte == 'D') MOVFW COM_BYTE SUBLW 'D' SKPZ GOTO R2_TEST_CHUP MOVLW D'1' ; TV = 1 MOVWF IR_T_DEV MOVLW D'19' ; Volume Down = 19 MOVWF IR_T_DATA CALL IR_SEND ; // Send IR GOTO R2_NEW_END R2_TEST_CHUP MOVFW COM_BYTE ;if (com_byte == 'u') SUBLW 'u' SKPZ GOTO R2_TEST_CHDN MOVLW D'1' ; TV = 1 MOVWF IR_T_DEV MOVLW D'16' ; Channel Up = 16 MOVWF IR_T_DATA CALL IR_SEND ; // Send IR GOTO R2_NEW_END R2_TEST_CHDN ;else if (com_byte == 'd') MOVFW COM_BYTE SUBLW 'd' SKPZ GOTO R2_PRINT MOVLW D'1' ; TV = 1 MOVWF IR_T_DEV MOVLW D'17' ; Channel Down = 17 MOVWF IR_T_DATA CALL IR_SEND ; // Send IR GOTO R2_NEW_END R2_PRINT ;else MOVFW COM_BYTE CALL LCD_PRINT ; //display on lcd R2_NEW_END RETURN ENDIF END ;*************************************** TITLE "Library Demo Program" ; Edward Cheung, Ph.D. ; ; Compiled with MPASM 1.20 ; ; Loaded with PICSTART 4.02 ; ;*************************************** ;Select library modules. Use 1/0, TRUE/FALSE not defined yet. CONSTANT AD_ENABLE = 0 CONSTANT R2_ENABLE = 1 CONSTANT R4_ENABLE = 0 CONSTANT LCD_ENABLE = 0 CONSTANT IR_ENABLE = 0 CONSTANT TW_ENABLE = 1 INCLUDE "LIB.H" ;pic library MAIN ;Initializations CALL GEN_INIT ;Do some real work with the library ;vars for RS232->IR command interpreter ALLOC COM_BYTE ;int com_byte; //received byte to interpret ALLOC COM_STATE ;int com_state; //state of command state machine CONSTANT ADDRESS = 'X' ALLOC TW_P_HOUSE ALLOC TW_P_KEY ;inits for main program CLRF COM_STATE ;com_state = 0; MAIN_LOOP GOTO MAIN_LOOP ;//do foreground processing here ;This gets called when there is a new byte from rs232 serial line. R2_NEW_BYTE MOVWF COM_BYTE ;com_byte = W; ; CALL R2_SEND ;//echo to serial out R2_STATE0 ;if (com_state == 0) MOVFW COM_STATE SUBLW D'0' SKPZ GOTO R2_STATE1 MOVFW COM_BYTE ; if (com_byte == address) SUBLW ADDRESS SKPNZ INCF COM_STATE,F ; com_state ++; GOTO R2_END_NEW R2_STATE1 ;else if (com_state == 1) MOVFW COM_STATE SUBLW D'1' SKPZ GOTO R2_STATE2 INCF COM_STATE,F ; com_state ++; GOTO R2_END_NEW R2_STATE2 ;else if (com_state == 2) MOVFW COM_STATE SUBLW D'2' SKPZ GOTO R2_STATE3 MOVFW COM_BYTE ; if (com_byte == '_') SUBLW '_' SKPZ GOTO R2_STATE2_ELSE INCF COM_STATE,F ; com_state ++; GOTO R2_END_NEW R2_STATE2_ELSE ; else CLRF COM_STATE ; com_state = 0; GOTO R2_END_NEW R2_STATE3 ;else if (com_state == 3) MOVFW COM_STATE SUBLW D'3' SKPZ GOTO R2_STATE4 MOVFW COM_BYTE ; tw_t_house = com_byte MOVWF TW_T_HOUSE INCF COM_STATE,F ; com_state ++; GOTO R2_END_NEW R2_STATE4 ;else if (com_state == 4) MOVFW COM_STATE SUBLW D'4' SKPZ GOTO R2_STATE5 MOVFW COM_BYTE ; tw_t_key = com_byte MOVWF TW_T_KEY INCF COM_STATE,F ; com_state ++; GOTO R2_END_NEW R2_STATE5 ;else MOVFW COM_BYTE ; if (com_byte == 13) SUBLW D'13' SKPZ GOTO R2_ABORT CALL TW_SEND ; // send x-10 CALL R2_ECHO ; // send status R2_ABORT CLRF COM_STATE ; com_state = 0; R2_END_NEW RETURN ;This is called when an X10 command is received. House code will be ;in tw_house, and key code in tw_key. TW_NEW MOVFW TW_HOUSE ;tw_p_house = converted(tw_house); CALL TW_TO_HOUSE MOVWF TW_P_HOUSE MOVFW TW_KEY ;tw_p_key = converted(tw_key); CALL TW_TO_KEY MOVWF TW_P_KEY RETURN R2_ECHO MOVLW 'C' ;Format of reply: CALL R2_SEND ;CX_E1 MOVLW 'X' ;^^^^^^ CALL R2_SEND ;|||||| MOVLW '_' ;|||||+- return character (0x13) CALL R2_SEND ;||||+-- 2nd response character MOVFW TW_P_HOUSE ;|||+--- 1st response character CALL R2_SEND ;||+---- underscore MOVFW TW_P_KEY ;|+----- from X-10 module CALL R2_SEND ;+------ to Computer MOVLW D'13' CALL R2_SEND MOVLW ' ' MOVWF TW_P_HOUSE ;//erase house and key code MOVWF TW_P_KEY RETURN END ;*************************************** LIST ; P16CXX.INC Standard Header File, Version 2.04 Microchip Technology, Inc. NOLIST ; This header file defines configurations, registers, and other useful bits of ; information for the 16CXX microcontrollers. These names are taken to match ; the data sheets as closely as possible. The microcontrollers included ; in this file are: ; 16C61 ; 16C62 ; 16C620 ; 16C621 ; 16C622 ; 16C63 ; 16C64 ; 16C65 ; 16C71 ; 16C73 ; 16C74 ; 16C84 ; There is one group of defines that is valid for all microcontrollers. ; Each microcontroller in this family also has its own section of special ; defines. Note that the processor must be selected before this file is ; included. The processor may be selected the following ways: ; 1. Command line switch: ; C:\ MPASM MYFILE.ASM /P16C71 ; 2. LIST directive in the source file ; LIST P=16C71 ; 3. Processor Type entry in the MPASM full-screen interface ;========================================================================== ; ; Generic Definitions ; ;========================================================================== W EQU H'0000' F EQU H'0001' ;----- Register Files------------------------------------------------------ INDF EQU H'0000' TMR0 EQU H'0001' PCL EQU H'0002' STATUS EQU H'0003' FSR EQU H'0004' PORTA EQU H'0005' PORTB EQU H'0006' PCLATH EQU H'000A' INTCON EQU H'000B' OPTION_REG EQU H'0081' TRISA EQU H'0085' TRISB EQU H'0086' ;----- INTCON Bits (except ADC/Periph) ------------------------------------ GIE EQU H'0007' T0IE EQU H'0005' INTE EQU H'0004' RBIE EQU H'0003' T0IF EQU H'0002' INTF EQU H'0001' RBIF EQU H'0000' ;----- OPTION Bits -------------------------------------------------------- NOT_RBPU EQU H'0007' INTEDG EQU H'0006' T0CS EQU H'0005' T0SE EQU H'0004' PSA EQU H'0003' PS2 EQU H'0002' PS1 EQU H'0001' PS0 EQU H'0000' ;----- STATUS Bits -------------------------------------------------------- IRP EQU H'0007' RP1 EQU H'0006' RP0 EQU H'0005' NOT_TO EQU H'0004' NOT_PD EQU H'0003' Z EQU H'0002' DC EQU H'0001' C EQU H'0000' ;========================================================================== ; ; Processor-dependent Definitions ; ;========================================================================== IFDEF __16C61 __MAXRAM H'0AF' __BADRAM H'07'-H'09', H'030'-H'07F', H'087'-H'089' #define __CONFIG_0 ENDIF IFDEF __16C62 PORTC EQU H'0007' __MAXRAM H'0BF' __BADRAM H'08'-H'09',H'0D',H'018'-H'01F',H'08D',H'08F'-H'091',H'095'-H'09F' #define __CONFIG_2 ENDIF IFDEF __16C620 ;----- Register Files -------------------------------------------------- PIR1 EQU H'000C' CMCON EQU H'001F' PIE1 EQU H'008C' PCON EQU H'008E' VRCON EQU H'009F' __MAXRAM H'09F' __BADRAM H'07'-H'09', H'0D'-H'01E', H'070'-H'07F', H'087'-H'089', H'08D', H'08F'-H'09E' #define __CONFIG_6 ENDIF IFDEF __16C621 ;----- Register Files -------------------------------------------------- PIR1 EQU H'000C' CMCON EQU H'001F' PIE1 EQU H'008C' PCON EQU H'008E' VRCON EQU H'009F' __MAXRAM H'09F' __BADRAM H'07'-H'09', H'0D'-H'01E', H'70'-H'07F', H'087'-H'089', H'08D', H'08F'-H'09E' #define __CONFIG_4 ENDIF IFDEF __16C622 ;----- Register Files -------------------------------------------------- PIR1 EQU H'000C' CMCON EQU H'001F' PIE1 EQU H'008C' PCON EQU H'008E' VRCON EQU H'009F' __MAXRAM H'0BF' __BADRAM H'07'-H'09', H'0D'-H'01E', H'087'-H'089', H'08D', H'08F'-H'09E' #define __CONFIG_5 ENDIF IFDEF __16C63 ;----- Register Files -------------------------------------------------- PORTC EQU H'0007' PIR1 EQU H'000C' TMR1L EQU H'000E' TMR1H EQU H'000F' T1CON EQU H'0010' TMR2 EQU H'0011' T2CON EQU H'0012' SSPBUF EQU H'0013' SSPCON EQU H'0014' CCPR1L EQU H'0015' CCPR1H EQU H'0016' CCP1CON EQU H'0017' TRISC EQU H'0087' PIE1 EQU H'008C' PCON EQU H'008E' PR2 EQU H'0092' SSPADD EQU H'0093' SSPSTAT EQU H'0094' __MAXRAM H'0BF' __BADRAM H'08'-H'09', H'0D', H'18'-H'1F', H'88', H'89', H'8D', H'8F'-H'91', H'95'-H'9F' #define __CONFIG_5 ENDIF IFDEF __16C64 ;----- Register Files -------------------------------------------------- PORTC EQU H'0007' PORTD EQU H'0008' PORTE EQU H'0009' PIR1 EQU H'000C' TMR1L EQU H'000E' TMR1H EQU H'000F' T1CON EQU H'0010' TMR2 EQU H'0011' T2CON EQU H'0012' SSPBUF EQU H'0013' SSPCON EQU H'0014' CCPR1L EQU H'0015' CCPR1H EQU H'0016' CCP1CON EQU H'0017' TRISC EQU H'0087' TRISD EQU H'0088' TRISE EQU H'0089' PIE1 EQU H'008C' PCON EQU H'008E' PR2 EQU H'0092' SSPADD EQU H'0093' SSPSTAT EQU H'0094' __MAXRAM H'0BF' __BADRAM H'0D', H'018'-H'01F', H'08D', H'08F'-H'091', H'095'-H'09F' #define __CONFIG_2 ENDIF IFDEF __16C65 ;----- Register Files -------------------------------------------------- PORTC EQU H'0007' PORTD EQU H'0008' PORTE EQU H'0009' PIR1 EQU H'000C' PIR2 EQU H'000D' TMR1L EQU H'000E' TMR1H EQU H'000F' T1CON EQU H'0010' TMR2 EQU H'0011' T2CON EQU H'0012' SSPBUF EQU H'0013' SSPCON EQU H'0014' CCPR1L EQU H'0015' CCPR1H EQU H'0016' CCP1CON EQU H'0017' RCSTA EQU H'0018' TXREG EQU H'0019' RCREG EQU H'001A' CCPR2L EQU H'001B' CCPR2H EQU H'001C' CCP2CON EQU H'001D' TRISC EQU H'0087' TRISD EQU H'0088' TRISE EQU H'0089' PIE1 EQU H'008C' PIE2 EQU H'008D' PCON EQU H'008E' PR2 EQU H'0092' SSPADD EQU H'0093' SSPSTAT EQU H'0094' TXSTA EQU H'0098' SPBRG EQU H'0099' __MAXRAM H'0FF' __BADRAM H'1E'-H'1F',H'08F'-H'091', H'095'-H'097', H'09A'-H'09F' #define __CONFIG_2 ENDIF IFDEF __16C71 __MAXRAM H'0AF' __BADRAM H'07', H'030'-H'07F', H'087' #define __ADC_CONFIG_0 #define __CONFIG_0 ENDIF IFDEF __16C73 ;----- Register Files -------------------------------------------------- PORTC EQU H'0007' PIR1 EQU H'000C' PIR2 EQU H'000D' TMR1L EQU H'000E' TMR1H EQU H'000F' T1CON EQU H'0010' TMR2 EQU H'0011' T2CON EQU H'0012' SSPBUF EQU H'0013' SSPCON EQU H'0014' CCPR1L EQU H'0015' CCPR1H EQU H'0016' CCP1CON EQU H'0017' RCSTA EQU H'0018' TXREG EQU H'0019' RCREG EQU H'001A' CCPR2L EQU H'001B' CCPR2H EQU H'001C' CCP2CON EQU H'001D' TRISC EQU H'0087' PIE1 EQU H'008C' PIE2 EQU H'008D' PCON EQU H'008E' PR2 EQU H'0092' SSPADD EQU H'0093' SSPSTAT EQU H'0094' TXSTA EQU H'0098' SPBRG EQU H'0099' __MAXRAM H'0FF' __BADRAM H'08F'-H'091', H'095'-H'097', H'09A'-H'09E' #define __ADC_CONFIG_1 #define __CONFIG_2 ENDIF IFDEF __16C74 ;----- Register Files -------------------------------------------------- PORTC EQU H'0007' PORTD EQU H'0008' PORTE EQU H'0009' PIR1 EQU H'000C' PIR2 EQU H'000D' TMR1L EQU H'000E' TMR1H EQU H'000F' T1CON EQU H'0010' TMR2 EQU H'0011' T2CON EQU H'0012' SSPBUF EQU H'0013' SSPCON EQU H'0014' CCPR1L EQU H'0015' CCPR1H EQU H'0016' CCP1CON EQU H'0017' RCSTA EQU H'0018' TXREG EQU H'0019' RCREG EQU H'001A' CCPR2L EQU H'001B' CCPR2H EQU H'001C' CCP2CON EQU H'001D' TRISC EQU H'0087' TRISD EQU H'0088' TRISE EQU H'0089' PIE1 EQU H'008C' PIE2 EQU H'008D' PCON EQU H'008E' PR2 EQU H'0092' SSPADD EQU H'0093' SSPSTAT EQU H'0094' TXSTA EQU H'0098' SPBRG EQU H'0099' __MAXRAM H'0FF' __BADRAM H'08F'-H'091', H'095'-H'097', H'09A'-H'09E' #define __ADC_CONFIG_1 #define __CONFIG_2 ENDIF IFDEF __16C84 ;----- Register Files -------------------------------------------------- EEDATA EQU H'0008' EEADR EQU H'0009' EECON1 EQU H'0088' EECON2 EQU H'0089' __MAXRAM H'0AF' __BADRAM H'07', H'030'-H'07F', H'087' #define __CONFIG_0 ENDIF ;========================================================================== ; ; Configuration Bits ; ;========================================================================== IFDEF __CONFIG_0 _CP_ON EQU H'3FEF' _CP_OFF EQU H'3FFF' _PWRTE_ON EQU H'3FFF' _PWRTE_OFF EQU H'3FF7' _WDT_ON EQU H'3FFF' _WDT_OFF EQU H'3FFB' _LP_OSC EQU H'3FFC' _XT_OSC EQU H'3FFD' _HS_OSC EQU H'3FFE' _RC_OSC EQU H'3FFF' #undefine __CONFIG_0 ENDIF IFDEF __CONFIG_1 _BODEN_ON EQU H'3FFF' _BODEN_OFF EQU H'3FBF' _CP_ON EQU H'004F' _CP_OFF EQU H'3FFF' _PWRTE_OFF EQU H'3FFF' _PWRTE_ON EQU H'3FF7' _WDT_ON EQU H'3FFF' _WDT_OFF EQU H'3FFB' _LP_OSC EQU H'3FFC' _XT_OSC EQU H'3FFD' _HS_OSC EQU H'3FFE' _RC_OSC EQU H'3FFF' #undefine __CONFIG_1 ENDIF IFDEF __CONFIG_2 _CP_ALL EQU H'3F8F' _CP_75 EQU H'3F9F' _CP_50 EQU H'3FAF' _CP_OFF EQU H'3FBF' _PWRTE_ON EQU H'3FBF' _PWRTE_OFF EQU H'3FB7' _WDT_ON EQU H'3FBF' _WDT_OFF EQU H'3FBB' _LP_OSC EQU H'3FBC' _XT_OSC EQU H'3FBD' _HS_OSC EQU H'3FBE' _RC_OSC EQU H'3FBF' #undefine __CONFIG_2 ENDIF IFDEF __CONFIG_3 _CP_ON EQU H'000F' _CP_OFF EQU H'3FFF' _PWRTE_ON EQU H'3FFF' _PWRTE_OFF EQU H'3FF7' _WDT_ON EQU H'3FFF' _WDT_OFF EQU H'3FFB' _LP_OSC EQU H'3FFC' _XT_OSC EQU H'3FFD' _HS_OSC EQU H'3FFE' _RC_OSC EQU H'3FFF' #undefine __CONFIG_3 ENDIF IFDEF __CONFIG_4 _BODEN_ON EQU H'3FFF' _BODEN_OFF EQU H'3FBF' _CP_ALL EQU H'00CF' _CP_50 EQU H'15DF' _CP_OFF EQU H'3FFF' _PWRTE_OFF EQU H'3FFF' _PWRTE_ON EQU H'3FF7' _WDT_ON EQU H'3FFF' _WDT_OFF EQU H'3FFB' _LP_OSC EQU H'3FFC' _XT_OSC EQU H'3FFD' _HS_OSC EQU H'3FFE' _RC_OSC EQU H'3FFF' #undefine __CONFIG_4 ENDIF IFDEF __CONFIG_5 _BODEN_ON EQU H'3FFF' _BODEN_OFF EQU H'3FBF' _CP_ALL EQU H'00CF' _CP_75 EQU H'15DF' _CP_50 EQU H'2AEF' _CP_OFF EQU H'3FFF' _PWRTE_OFF EQU H'3FFF' _PWRTE_ON EQU H'3FF7' _WDT_ON EQU H'3FFF' _WDT_OFF EQU H'3FFB' _LP_OSC EQU H'3FFC' _XT_OSC EQU H'3FFD' _HS_OSC EQU H'3FFE' _RC_OSC EQU H'3FFF' #undefine __CONFIG_5 ENDIF IFDEF __CONFIG_6 _BODEN_ON EQU H'3FFF' _BODEN_OFF EQU H'3FBF' _CP_ON EQU H'00CF' _CP_OFF EQU H'3FFF' _PWRTE_OFF EQU H'3FFF' _PWRTE_ON EQU H'3FF7' _WDT_ON EQU H'3FFF' _WDT_OFF EQU H'3FFB' _LP_OSC EQU H'3FFC' _XT_OSC EQU H'3FFD' _HS_OSC EQU H'3FFE' _RC_OSC EQU H'3FFF' #undefine __CONFIG_6 ENDIF ;========================================================================== ; ; More Bit Definitions ; ;========================================================================== IFDEF __ADC_CONFIG_0 ;---- Register Files --------------------------------------------------- ADCON0 EQU H'0008' ADRES EQU H'0009' ADCON1 EQU H'0088' ;---- Finish INTCON Definition ----------------------------------------- ADIE EQU H'0006' ;----- ADCON0 Bits ----------------------------------------------------- ADCS1 EQU H'0007' ADCS0 EQU H'0006' CHS1 EQU H'0004' CHS0 EQU H'0003' GO EQU H'0002' NOT_DONE EQU H'0002' GO_DONE EQU H'0002' ADIF EQU H'0001' ADON EQU H'0000' ;----- ADCON1 Bits ----------------------------------------------------- PCFG1 EQU H'0001' PCFG0 EQU H'0000' #undefine __ADC_CONFIG_0 ELSE ;---- Finish INTCON Definition ----------------------------------------- PEIE EQU H'0006' ENDIF IFDEF __ADC_CONFIG_1 ;----- Register Files -------------------------------------------------- ADRES EQU H'001E' ADCON0 EQU H'001F' ADCON1 EQU H'009F' ;----- ADCON0 Bits ----------------------------------------------------- ADCS1 EQU H'0007' ADCS0 EQU H'0006' CHS2 EQU H'0005' CHS1 EQU H'0004' CHS0 EQU H'0003' GO EQU H'0002' NOT_DONE EQU H'0002' GO_DONE EQU H'0002' ADON EQU H'0000' ;----- ADCON1 Bits ----------------------------------------------------- PCFG2 EQU H'0002' PCFG1 EQU H'0001' PCFG0 EQU H'0000' ;----- PIE1 and PIR1 ADC Bits ------------------------------------------ ADIE EQU H'0006' ADIF EQU H'0006' #undefine __ADC_CONFIG_1 ENDIF IFDEF CCP1CON CCP1X EQU H'0005' CCP1Y EQU H'0004' CCP1M3 EQU H'0003' CCP1M2 EQU H'0002' CCP1M1 EQU H'0001' CCP1M0 EQU H'0000' ENDIF IFDEF CCP2CON CCP2X EQU H'0005' CCP2Y EQU H'0004' CCP2M3 EQU H'0003' CCP2M2 EQU H'0002' CCP2M1 EQU H'0001' CCP2M0 EQU H'0000' ENDIF IFDEF CMCON C2OUT EQU H'0007' C1OUT EQU H'0006' CIS EQU H'0003' CM2 EQU H'0002' CM1 EQU H'0001' CM0 EQU H'0000' ;----- PIE1 and PIR1 ADC Bits ------------------------------------------ CMIE EQU H'0006' CMIF EQU H'0006' ENDIF IFDEF EECON1 EEIF EQU H'0004' WRERR EQU H'0003' WREN EQU H'0002' WR EQU H'0001' RD EQU H'0000' ENDIF IFDEF PCON NOT_POR EQU H'0001' NOT_BO EQU H'0000' ENDIF IFDEF PIE1 PSPIE EQU H'0007' SSPIE EQU H'0003' CCP1IE EQU H'0002' TMR2IE EQU H'0001' TMR1IE EQU H'0000' ENDIF IFDEF PIR1 PSPIF EQU H'0007' SSPIF EQU H'0003' CCP1IF EQU H'0002' TMR2IF EQU H'0001' TMR1IF EQU H'0000' ENDIF IFDEF PIE2 ; Assumes PIE2 and PIR2 CCP2IE EQU H'0000' CCP2IF EQU H'0000' ENDIF IFDEF RCSTA SPEN EQU H'0007' RC9 EQU H'0006' NOT_RC8 EQU H'0006' RC8_9 EQU H'0006' SREN EQU H'0005' CREN EQU H'0004' FERR EQU H'0002' OERR EQU H'0001' RCD8 EQU H'0000' ;----- PIE1 and PIR1 RC Bits ------------------------------------------ RCIE EQU H'0005' RBFL EQU H'0005' ENDIF IFDEF SSPCON WCOL EQU H'0007' SSPOV EQU H'0006' SSPEN EQU H'0005' CKP EQU H'0004' SSPM3 EQU H'0003' SSPM2 EQU H'0002' SSPM1 EQU H'0001' SSPM0 EQU H'0000' ENDIF IFDEF SSPSTAT D EQU H'0005' I2C_DATA EQU H'0005' NOT_A EQU H'0005' NOT_ADDRESS EQU H'0005' D_A EQU H'0005' DATA_ADDRESS EQU H'0005' P EQU H'0004' I2C_STOP EQU H'0004' S EQU H'0003' I2C_START EQU H'0003' R EQU H'0002' I2C_READ EQU H'0002' NOT_W EQU H'0002' NOT_WRITE EQU H'0002' R_W EQU H'0002' READ_WRITE EQU H'0002' UA EQU H'0001' BF EQU H'0000' ENDIF IFDEF T1CON T1CKPS1 EQU H'0005' T1CKPS0 EQU H'0004' T1OSCEN EQU H'0003' T1INSYNC EQU H'0002' TMR1CS EQU H'0001' TMR1ON EQU H'0000' ENDIF IFDEF T2CON TOUTPS3 EQU H'0006' TOUTPS2 EQU H'0005' TOUTPS1 EQU H'0004' TOUTPS0 EQU H'0003' TMR2ON EQU H'0002' T2CKPS1 EQU H'0001' T2CKPS0 EQU H'0000' ENDIF IFDEF TRISE IBF EQU H'0007' OBF EQU H'0006' IBOV EQU H'0005' PSPMODE EQU H'0004' TRISE2 EQU H'0002' TRISE1 EQU H'0001' TRISE0 EQU H'0000' ENDIF IFDEF TXSTA CSRC EQU H'0007' TX9 EQU H'0006' NOT_TX8 EQU H'0006' TX8_9 EQU H'0006' TXEN EQU H'0005' SYNC EQU H'0004' BRGH EQU H'0002' TRMT EQU H'0001' TXD8 EQU H'0000' ;----- PIE1 and PIR1 TX Bits ------------------------------------------ TXIE EQU H'0004' TXIF EQU H'0004' ENDIF IFDEF VRCON VREN EQU H'0007' VROE EQU H'0006' VRR EQU H'0005' VR3 EQU H'0003' VR2 EQU H'0002' VR1 EQU H'0001' VR0 EQU H'0000' ENDIF LIST ;*************************************** ; LIBRARY OF UTILITIES FOR PIC ; ; EDWARD CHEUNG, PH.D. ; ; MITCHELLVILLE, MD ; ; ebc714@rs710.gsfc.nasa.gov ; ;*************************************** ; MODIFICATION HISTORY ; Version 0.1, July 1995: ; Compiles under MPASM 1.02.05. Loads with PICSTART 4.02. ; Currently available modules are A/D, LCD, X-10, IR, RS422 and RS232. ;The RS485 code remains to be tested, and is awaiting ;driver chips to test the transmit enable line (R4_TRANON). IR module ;supports SONY (aka SIRCS) format. Each module tested using LCD module. ; Version 0.2, July 1995: ; Compiles under mpasm 1.20. Moved interrupt functions into ;main library. Improved INT_HANDLER to call one module per ;interrupt. Previous version called all enabled modules, which caused timing ;problems. Each module was not guaranteed to be called at a stable frequency. ; Fixed bug with computed gotos. Added assembler code that will give a ;warning if code with computed gotos is placed in program memory above ;location 0xff. See Application Note AN556 in Embedded Control Handbook ;for more details. ; Tested with 14.7456Mhz crystal. This is a commonly available ;frequency that is divisible by 9600 and under 16Mhz. ;15.360Mhz and 15.9744Mhz are also good frequencies (not tested). ;At 14.x Mhz, 57600 interrupts/second is probably the fastest you can ;go. If you need more, use a faster crystal. ; Eliminated use of P16C71.INC file and used defs in P16CXX.INC. This ;should improve support for other processors by substituting the proper ;*.inc file. As far as I know, the only thing you will have to change ;for other processors in the MEM_FIRST and the MEM_LAST variables below, ;and don't enable the A/D if it doesn't exist. ; Version 0.21: ; Invalid commands to TW_SEND are rejected. GOTO MAIN ;start execution at 'main' #define __16C71 ;using PIC16C71 #INCLUDE "P16CXX.INC" ;defs for register location __FUSES _WDT_ON&_HS_OSC ;watch dog on, and hs oscillator ;***** General constants FXTAL EQU D'14745600' ;device clock freq INTSEC EQU D'28800' ;desired interrupts/sec. TRUE EQU 1H FALSE EQU 0H ;Set up desired interrupts/sec for chip. A smaller number means more ;operations between interrupts, and more time alotted to the main program. RTC_NUM EQU D'256' - ((FXTAL/(4*INTSEC)) - D'7') ;number of modules that use the interrupt mechanism NUM_MOD EQU R2_ENABLE + R4_ENABLE + IR_ENABLE + IR_ENABLE + TW_ENABLE ;number of times/sec each interrupt module gets control (is run) RUNSEC EQU INTSEC/NUM_MOD ;***** Memory Management ;Assign memory location to input variable 'name' ;Addresses will start at MEM_FIRST, and last one allowed is at MEM_LAST ;0CH to 2FH inclusive are available on '71. ;See .lst file for actual addresses. In that file, ;MEM_INDEX will be one address past the last one. ;Thus max for MEM_INDEX is MEM_LAST + 1 MEM_FIRST EQU 0CH MEM_LAST EQU 2FH MEM_INDEX SET MEM_FIRST ALLOC MACRO NAME NAME EQU MEM_INDEX IF MEM_INDEX > MEM_LAST CALL OUT_OF_MEMORY_ERROR ;Reduce the number of modules in use ELSE MEM_INDEX SET MEM_INDEX + 1 ENDIF ENDM ;Assign memory location to input variable 'name' ;Total number of storage locations is 'spacing', ;which includes memory allocated in previous ALLOC call, ;and the one occupied by 'name'. ALLOC_ARRAY MACRO NAME,SPACING IF SPACING < 2 CALL ARRAY_TOO_SMALL ;Increase size of array to be greater than 2 ENDIF MEM_INDEX SET (MEM_INDEX+SPACING)-2 NAME EQU MEM_INDEX IF MEM_INDEX > MEM_LAST CALL OUT_OF_MEMORY ;Reduce the number of modules in use ELSE MEM_INDEX SET MEM_INDEX + 1 ENDIF ENDM ;Memory location assignment ;register storage for interrupt ALLOC TEMP_W ALLOC TEMP_STAT ALLOC TASK_INDEX ;gen purpose for use in functions that interface to interrupt routines ALLOC SCRATCH_1 ALLOC SCRATCH_2 IF R2_ENABLE == TRUE ;rs232 uart ALLOC R2_OUT_TIMR ;output timer ALLOC R2_OUT_BIT ;index of current output bit ALLOC R2_IN_TIMER ;input timer ALLOC R2_IN_BIT ;index of current input bit ALLOC R2_IN_BYTE ;byte being received ALLOC R2_IN_PTR ;ring buffer pointer in ALLOC R2_OUT_PTR ;ring buffer pointer out ALLOC R2_FIRST_BUF ;ring buffer location ALLOC_ARRAY R2_LAST_BUF,D'07' ;ring buffer end ENDIF IF R4_ENABLE == TRUE ;rs422/485 uart ALLOC R4_OUT_TIMR ;current bit being sent ALLOC R4_OUT_BIT ;output data ALLOC R4_IN_TIMER ;bit counter ALLOC R4_IN_BIT ;data input bit ALLOC R4_IN_BYTE ;byte being received ALLOC R4_IN_PTR ;ring buffer pointer in ALLOC R4_OUT_PTR ;ring buffer pointer out ALLOC R4_FIRST_BUF ;ring buffer location ALLOC_ARRAY R4_LAST_BUF,D'08' ;ring buffer end ENDIF IF LCD_ENABLE == TRUE ;timer ALLOC TIMER_HI ALLOC TIMER_LO ;binary to bcd conversion ALLOC LSD ALLOC MSD ENDIF IF IR_ENABLE == TRUE ;ir uart ALLOC IR_DEV ;received ir device ALLOC IR_DATA ;received ir data ALLOC IR_PHASE ;current ir bit being received ALLOC IR_TIMER ;rx countdown timer ALLOC IR_T_DEV ;tx ir device ALLOC IR_T_DATA ;tx ir data ALLOC IR_O_COUNT ;number of times to send ir data ALLOC IR_O_DEV ;ir device being sent ALLOC IR_O_DATA ;ir data being sent ALLOC IR_O_PHASE ;ir bit being sent ALLOC IR_O_TIMER ;tx countdown timer ENDIF IF TW_ENABLE == TRUE ;x10 uart ;memory ALLOC TW_FLAGS ;for the following booleans: TW_PREV EQU 00H ;boolean, previous 60 hz status TW_STATE EQU 01H ;boolean, current 60 hz status TW_CARRIER EQU 02H ;boolean, data bit TW_O_CARR EQU 03H ;boolean, tw_o_carrier; TW_FIRST EQU 04H ;boolean, first packet of two ALLOC TW_SAMPLE ;countdown and control timer ALLOC TW_PHASE ;which bit current being sampled ALLOC TW_HOUSE ;house code data ALLOC TW_KEY ;key code data ALLOC TW_O_SAMPLE ;countdown and control timer ALLOC TW_O_PHASE ;bit being sent ALLOC TW_O_HOUSE ;house code being sent ALLOC TW_O_KEY ;key code being sent ALLOC TW_T_HOUSE ;next house code to be sent ALLOC TW_T_KEY ;next key code to be sent ALLOC TW_MATCH ;ascii of x10 code sought ALLOC TW_INDEX ;indexing counter ENDIF ;TW_ENABLE ;***** Interrupt related functions ;This is called every time an interrupt occurs. ;Due to computed GOTO, this function must reside in memory range 0-FF. ;One module is called everytime there is an interrupt. Note how the call ;of each module is written. There must be exactly 4 instructions between ;each IF...ENDIF statement. ;Note that IR functions are called in separate interrupts. That is because ;each takes so much time to run. INT_HANDLER MACRO MOVFW TASK_INDEX ;if (task_index == num_mod) SUBLW NUM_MOD SKPNZ CLRF TASK_INDEX ; task_index = 0; CLRC ;// clear carry RLF TASK_INDEX,F ;pc += (task_index++ * 4) RLF TASK_INDEX,W RRF TASK_INDEX,F INCF TASK_INDEX,F ADDWF PCL,F ;//computed goto, run one of the modules below IF TW_ENABLE == TRUE CALL TW_GET ;check x10 input CALL TW_PUT ;check x10 output GOTO INT_H_END GOTO INT_H_END ENDIF IF R2_ENABLE == TRUE CALL R2_SER_IN ;check serial input CALL R2_SER_OUT ;check serial output GOTO INT_H_END GOTO INT_H_END ENDIF IF R4_ENABLE == TRUE CALL R4_SER_IN ;check serial input CALL R4_SER_OUT ;check serial output GOTO INT_H_END GOTO INT_H_END ENDIF IF IR_ENABLE == TRUE CALL IR_GET ;check ir input GOTO INT_H_END GOTO INT_H_END GOTO INT_H_END CALL IR_PUT ;check ir output GOTO INT_H_END GOTO INT_H_END GOTO INT_H_END ENDIF INT_H_END IF INT_H_END > H'FE' CALL PAGE_ERROR ;Due to computed gotos, this should be in program memory below 0xFF ;See Application Note AN556, example 5 for more info. ENDIF ENDM ;Interrupt service routine. INT_VECT ORG H'04' ;Save W and STATUS registers MOVWF TEMP_W ;save W SWAPF STATUS,W ;get swapped status MOVWF TEMP_STAT ;save swapped status ;Reschedule next interrupt MOVLW RTC_NUM MOVWF TMR0 ;setup for next interrupt CLRWDT ;Do interrupt actions INT_HANDLER ;Clear interrupt sources ; BCF INTCON,RBIF ;clear interrupt from RB<7:4> ; BCF INTCON,INTF ;clear interrupt from RB0 BCF INTCON,T0IF ;clear interrupt from timer 0 ;Restore registers and return SWAPF TEMP_STAT,W ;get and unswap STATUS MOVWF STATUS ;restore STATUS SWAPF TEMP_W,F ;swap TEMP_W SWAPF TEMP_W,W ;unswap and restore W RETFIE ;return from interrupt ;***** General Macros and Functions ;Select page 1 PAGE_1 MACRO BSF STATUS,RP0 ENDM ;Select page 0 PAGE_0 MACRO BCF STATUS,RP0 ENDM ;Main Inits GEN_INIT ;Note! This also sets up general operation of Ports. If they ;are digital or analog, pullups enabled or not etc. ;Setup PORTA options IF AD_ENABLE == TRUE PAGE_1 MOVLW B'00000000' ;all pins analog MOVWF ADCON1^H'80' ;setup PORTA function PAGE_0 ELSE PAGE_1 MOVLW B'00000011' ;all pins digital MOVWF ADCON1^H'80' ;setup PORTA function PAGE_0 ENDIF ;PortB no pullup, Prescaler to WDT. See Page 2-355 '94 edition PAGE_1 CLRWDT MOVLW B'10001000' MOVWF OPTION_REG^H'80' PAGE_0 ;other variables CLRF TMR0 CLRF TASK_INDEX ;Call the init functions of modules that are needed IF LCD_ENABLE == TRUE CALL LCD_INIT ENDIF IF R2_ENABLE == TRUE CALL R2_INIT ENDIF IF R4_ENABLE == TRUE CALL R4_INIT ENDIF IF IR_ENABLE == TRUE CALL IR_INIT ENDIF IF TW_ENABLE == TRUE CALL TW_INIT ENDIF ;GIE enable, T0IE enable for interrupt mechanism MOVLW B'10100000' MOVWF INTCON CLRWDT RETURN ;***** X-10 FUNCTIONS. Due to computed gotos, this has to be ;below program memory location FF. Warnings are built in if the above is ;not met. IF TW_ENABLE == TRUE ;defs TW_PORT EQU PORTA TW_60 EQU 00H ;60Hz crossing input TW_FROM EQU 01H ;data from house input TW_TO EQU 02H ;data to house output TW_10 EQU (RUNSEC * D'11')/D'10000' TW_05 EQU (RUNSEC * D'05')/D'10000' ;Returns house code when given x10 code in W TW_TO_HOUSE ANDLW H'F' ;mask upper nibble ADDWF PCL,F ;computed goto RETLW 'M' ;returned if input = 0 RETLW 'N' RETLW 'O' RETLW 'P' RETLW 'C' RETLW 'D' RETLW 'A' RETLW 'B' RETLW 'E' RETLW 'F' RETLW 'G' RETLW 'H' RETLW 'K' RETLW 'L' RETLW 'I' RETLW 'J' ;returned if input = F TW_TOH_END IF TW_TOH_END > H'FE' CALL PAGE_ERROR ;Due to computed gotos, this should be in program memory below 0xFF ;See Application Note AN556, example 5 ENDIF ;Returns unit or function code when given x10 code in W TW_TO_KEY ANDLW H'1F' ;mask upper 3 bits ADDWF PCL,F ;computed goto RETLW 'D' ;returned if input = 0x0 RETLW 'E' RETLW 'F' RETLW 'G' RETLW '3' RETLW '4' RETLW '1' RETLW '2' RETLW '5' RETLW '6' RETLW '7' RETLW '8' RETLW 'B' RETLW 'C' RETLW '9' RETLW 'A' ;returned if input = 0xf RETLW 'u' ;all units off RETLW 'r' ;hail request RETLW 'd' ;dim RETLW 'n' ;extended data (analog) RETLW 't' ;on RETLW 'p' ;pre-set dim RETLW 'a' ;all lights off RETLW 'l' ;status = off RETLW 'o' ;all lights on RETLW 'h' ;hail acknowledge RETLW 'b' ;bright RETLW 's' ;status = on RETLW 'f' ;off RETLW 'p' ;pre-set dim RETLW 'x' ;extended code RETLW 'q' ;status request TW_TOK_END IF TW_TOK_END > H'FE' CALL PAGE_ERROR ;Due to computed gotos, this should be in program memory below 0xFF ;See Application Note AN556, example 5 ENDIF ;Given a key code (in ASCII), this returns the X-10 code TW_TO_XKEY MOVWF TW_MATCH ; match = w; CLRF TW_INDEX ; index = 0; TW_TEST_KEY ; while { MOVFW TW_INDEX CALL TW_TO_KEY ; if (w == match) { SUBWF TW_MATCH,W SKPZ GOTO TW_RETRY_KEY MOVFW TW_INDEX ; return index RETURN TW_RETRY_KEY ; } else { MOVLW D'32' ; if (index < 32) { SUBWF TW_INDEX,W SKPNC GOTO TW_NONE_KEY ; goto none_found INCF TW_INDEX,F ; index ++; GOTO TW_TEST_KEY ; } TW_NONE_KEY ; none_found RETLW H'80' ; return h'80' ;Given a house code (in ASCII), this returns the X-10 code TW_TO_XHOUSE MOVWF TW_MATCH ; match = w; CLRF TW_INDEX ; index = 0; TW_TEST ; while { MOVFW TW_INDEX CALL TW_TO_HOUSE ; if (w == match) { SUBWF TW_MATCH,W SKPZ GOTO TW_RETRY MOVFW TW_INDEX ; return index RETURN TW_RETRY ; } else { MOVLW D'16' ; if (index < 16) { SUBWF TW_INDEX,W SKPNC GOTO TW_NONE_FOUND ; goto none_found INCF TW_INDEX,F ; index ++; GOTO TW_TEST ; } TW_NONE_FOUND ; none_found RETLW H'80' ; return h'80' ;Initialize tw523 stuff TW_INIT ;tw_init() { ;Ports PAGE_1 BSF TW_PORT,TW_60 ; 1 IS INPUT BSF TW_PORT,TW_FROM; 0 IS OUTPUT BCF TW_PORT,TW_TO PAGE_0 CLRF TW_FLAGS ; tw_flags = 0; BCF TW_FLAGS,TW_PREV BTFSC TW_PORT,TW_60 ; tw_prev = input(tw_port,tw_60); BSF TW_FLAGS,TW_PREV CLRF TW_O_PHASE ; tw_o_phase = 0; CLRF TW_O_HOUSE ; tw_o_house = 0; CLRF TW_O_KEY ; tw_o_key = 0; ;Reset variables for start of x10 reception TW_RESET CLRF TW_SAMPLE ; tw_sample = 0; CLRF TW_PHASE ; tw_phase = 0; CLRF TW_HOUSE ; tw_house = 0; CLRF TW_KEY ; tw_key = 0; RETURN ;} ;Get data from X10 interface. New_tw() gets called if a valid ;message is received TW_GET ;tw_get() { TSTF TW_SAMPLE ; if (tw_sample == 0) { SKPZ GOTO TW_SAMPLE_DATA ; //check zero crossing BTFSS TW_PORT,TW_60 ; if (input(tw_port,tw_60) == 1) { GOTO TW_60_LO BTFSC TW_FLAGS,TW_PREV; if (tw_prev == 0) { RETURN MOVLW TW_05 ; tw_sample = tw_05; MOVWF TW_SAMPLE BSF TW_FLAGS,TW_PREV; tw_prev = 1; RETURN ; } TW_60_LO ; } else { BTFSS TW_FLAGS,TW_PREV; if (tw_prev == 1) { RETURN MOVLW TW_05 ; tw_sample = tw_05; MOVWF TW_SAMPLE BCF TW_FLAGS,TW_PREV; tw_prev = 0; RETURN ; } TW_SAMPLE_DATA ; } MOVLW D'1' ; } else if (tw_sample == 1) { SUBWF TW_SAMPLE,W SKPZ GOTO TW_WAIT ; // sample data CLRF TW_SAMPLE ; tw_sample = 0; BSF TW_FLAGS,TW_CARRIER BTFSC TW_PORT,TW_FROM; tw_carrier = ~input(tw_port,tw_from); BCF TW_FLAGS,TW_CARRIER MOVLW D'12' ; if (tw_phase >= 12) { SUBWF TW_PHASE,W SKPC GOTO TW_HOUSECODE ; // sample key code INCF TW_PHASE,F ; tw_phase ++; BTFSS TW_PHASE,W ; if (tw_phase,W == 1) { GOTO TW_KEY_HALF CLRC ; // first half bit RRF TW_KEY,F ; tw_key >> BTFSC TW_FLAGS,TW_CARRIER ; if (tw_carrier = 1) BSF TW_KEY,4 ; set tw_key,4; GOTO TW_SAMPLE_END TW_KEY_HALF ; } else { ; // second half bit BTFSS TW_FLAGS,TW_CARRIER ; if (tw_carrier == 1) { GOTO TW_KEY_ELSE BTFSC TW_KEY,4 ; if (tw_key,4 != 0) CALL TW_RESET ; tw_reset; GOTO TW_SAMPLE_END TW_KEY_ELSE ; } else { BTFSS TW_KEY,4 ; if (tw_key,4 != 1) CALL TW_RESET ; tw_reset; GOTO TW_SAMPLE_END ; } TW_HOUSECODE ; } MOVLW D'4' ; } else if (tw_phase >= 4) { SUBWF TW_PHASE,W ; // sample house code SKPC GOTO TW_SYNC_B INCF TW_PHASE,F ; tw_phase ++; BTFSS TW_PHASE,W ; if (tw_phase,W == 1) { GOTO TW_HOUSE_HALF CLRC ; // first half bit RRF TW_HOUSE,F ; tw_house >> BTFSC TW_FLAGS,TW_CARRIER; if (tw_carrier = 1) BSF TW_HOUSE,3 ; set tw_house,3; GOTO TW_SAMPLE_END TW_HOUSE_HALF ; } else { ; // second half bit BTFSS TW_FLAGS,TW_CARRIER ; if (tw_carrier == 1) { GOTO TW_HOUSE_ELSE BTFSC TW_HOUSE,3 ; if (tw_house,3 != 0) CALL TW_RESET ; tw_reset; GOTO TW_SAMPLE_END TW_HOUSE_ELSE ; } else { BTFSS TW_HOUSE,3 ; if (tw_house,3 != 1) CALL TW_RESET ; tw_reset; GOTO TW_SAMPLE_END ; } TW_SYNC_B MOVLW D'3' ; } else if tw_phase == 3) { SUBWF TW_PHASE,W SKPZ GOTO TW_SYNC_A INCF TW_PHASE,F ; tw_phase ++; BTFSC TW_FLAGS,TW_CARRIER; if (tw_carrier == 1) CLRF TW_PHASE ; tw_phase = 0; GOTO TW_SAMPLE_END ; } TW_SYNC_A ; } else { INCF TW_PHASE,F ; tw_phase ++; BTFSS TW_FLAGS,TW_CARRIER; if (tw_carrier == 0) CLRF TW_PHASE ; tw_phase = 0; GOTO TW_SAMPLE_END TW_SAMPLE_END ; } MOVLW D'22' ; if (tw_phase == 22) { SUBWF TW_PHASE,W SKPZ RETURN CALL TW_NEW ; new_tw(); CALL TW_RESET ; tw_reset(); RETURN ; } TW_WAIT ; } else { ; wait until sample time DECF TW_SAMPLE,F ; tw_sample --; ; } RETURN ;} ;trigger send. Does not restore W register TW_SEND ;tw_send() { ;Store data in converted form MOVFW TW_T_HOUSE ; tw_t_house = converted(tw_t_house); CALL TW_TO_XHOUSE MOVWF TW_T_HOUSE BTFSC TW_T_HOUSE,7 ; if (tw_t_house,7 == 1) RETURN ; return; // invalid command MOVFW TW_T_KEY ; tw_t_key = converted(tw_t_key); CALL TW_TO_XKEY MOVWF TW_T_KEY BTFSC TW_T_KEY,7 ; if (tw_t_key,7 == 1) RETURN ; return; // invalid command ;Wait till no transmissions TW_SEND_WAIT TSTF TW_O_PHASE ; while (tw_o_phase != 0) {} SKPZ GOTO TW_SEND_WAIT ;Put data into transmit queue MOVFW TW_T_HOUSE ; tw_o_house = tw_t_house; MOVWF TW_O_HOUSE MOVFW TW_T_KEY ; tw_o_key = tw_t_key; MOVWF TW_O_KEY BSF TW_FLAGS,TW_FIRST; tw_first = 1; MOVLW D'1' ; tw_o_phase = 1; MOVWF TW_O_PHASE CLRF TW_O_SAMPLE ; tw_o_sample = 0; RETURN ;} ;Interrupt based X10 send function ;Call tw_get before tw_put to get zero crossing TW_PUT ;tw_put(){ TSTF TW_O_PHASE ; if (tw_o_phase == 0) { SKPZ ; // no active transmission GOTO TW_TEST_ZERO BCF TW_PORT,TW_TO ; output (tw_port,tw_to) = 0; RETURN ; return TW_TEST_ZERO MOVLW TW_05 ; } else if (tw_sample == tw_05) { SUBWF TW_SAMPLE,W ; // just had zero crossing SKPZ GOTO TW_ENDBIT TW_ZEROWAIT MOVLW H'55' ; if (tw_o_phase > 0x55) { SUBWF TW_O_PHASE,W SKPNC ; // wait the req'd # of zero crossings GOTO TW_STARTBIT ; // between transmissions TW_SYNC MOVLW D'4' ; } else if (tw_o_phase <= 4) { SUBWF TW_O_PHASE,W ; // send carrier high (sync begin) SKPNC GOTO TW_SECOND BSF TW_PORT,TW_TO ; output (tw_port,tw_to) = 1; BSF TW_FLAGS,TW_O_CARR; tw_o_carr == 1; //for 2nd bit GOTO TW_STARTBIT TW_SECOND BTFSC TW_O_PHASE,W ; } else if (tw_o_phase,W == 0) { GOTO TW_SENDKEY ; // send second half bit BTFSS TW_FLAGS,TW_O_CARR; if (tw_o_carr != 1) BSF TW_PORT,TW_TO ; output (tw_port,tw_to) = 1; GOTO TW_STARTBIT TW_SENDKEY MOVLW D'13' ; } else if (tw_o_phase >= 13) { SUBWF TW_O_PHASE,W ; // send key code SKPC GOTO TW_SENDHOUSE CLRC ; clear carry BCF TW_FLAGS,TW_O_CARR; tw_o_carr = 0; RRF TW_O_KEY,F ; tw_o_key >> SKPC ; if (carry == 1) { GOTO TW_STARTBIT BSF TW_PORT,TW_TO ; output (tw_port,tw_to) = 1; BSF TW_FLAGS,TW_O_CARR; tw_o_carr = 1; BSF TW_O_KEY,4 ; tw_o_key,4 = 1; GOTO TW_STARTBIT ; } TW_SENDHOUSE ; } else { ; // send house code CLRC ; clear carry BCF TW_FLAGS,TW_O_CARR; tw_o_carr = 0; RRF TW_O_HOUSE,F ; tw_o_house >> SKPC ; if (carry == 1) { GOTO TW_STARTBIT BSF TW_PORT,TW_TO ; output (tw_port,tw_to) = 1; BSF TW_FLAGS,TW_O_CARR; tw_o_carr = 1; BSF TW_O_HOUSE,3 ; tw_o_house,3 = 1; ; } TW_STARTBIT ; } INCF TW_O_PHASE,F ; tw_o_phase ++; MOVLW TW_10 ; tw_o_sample = tw_10; MOVWF TW_O_SAMPLE RETURN TW_ENDBIT MOVLW D'1' ; } else if (tw_o_sample == 1) { SUBWF TW_O_SAMPLE,W ; // send carr low, end of bit SKPZ GOTO TW_WAIT_SEND BCF TW_PORT,TW_TO ; output (tw_port,tw_to) = 0; CLRF TW_O_SAMPLE ; tw_o_sample = 0; MOVLW D'23' ; if (tw_o_phase == 23) { SUBWF TW_O_PHASE,W ; // end of tx ? SKPZ RETURN BTFSS TW_FLAGS,TW_FIRST; if (tw_first == 1) { GOTO TW_ENDELSE MOVLW D'1' ; tw_o_phase = 1; MOVWF TW_O_PHASE BCF TW_FLAGS,TW_FIRST; tw_first = 0; RETURN TW_ENDELSE ; } else MOVLW H'FB' ; //end transmission, setup wait time MOVWF TW_O_PHASE ; tw_o_phase = -5; RETURN ; } TW_WAIT_SEND MOVLW D'1' ; } else if (tw_o_sample >= 1) { SUBWF TW_O_SAMPLE,W ; // wait time till end of bit SKPNC DECF TW_O_SAMPLE,F ; tw_o_sample --; TW_SENDEND ; } RETURN ;} ENDIF ;TW_ENABLE ;***** A/D ROUTINES IF AD_ENABLE == TRUE ;A/D CHANNELS CH0 EQU 00H CH1 EQU 08H CH2 EQU 10H CH3 EQU 18H ;Select CHANNEL as the desired A/D input ;Usage: AD_SELECT CH0 AD_SELECT MACRO CHANNEL MOVLW B'11000001' ;use internal clock, ad on IORLW CHANNEL ;program channel MOVWF ADCON0 ;setup ad BCF INTCON,ADIE ;disable A/D interrupt ENDM ;Read the currently selected A/D input into W AD_READ BSF ADCON0,2 ;start conversion AD_TEST BTFSC ADCON0,2 ;test ad done GOTO AD_TEST ;test again MOVF ADRES,W ;put result in W RETURN ENDIF ;AD_ENABLE ;***** RS232 ROUTINES ;Default parameters are no parity, eight bits, one stop bit IF R2_ENABLE == TRUE ;The quiescent state of the line is '1'. A start bit is '0', ;and the data bits follow uninverted. The stop bit is a '1'. ;Constants R2_BAUD EQU RUNSEC/D'2400' IF (RUNSEC != R2_BAUD*D'2400') CALL INTSEC_ERROR ;R2_BAUD must be a whole number - adjust INTSEC or ;the number of modules in use ENDIF R2_PORT EQU PORTB R2_IN EQU 06H R2_OUT EQU 07H R2_DUPLEX EQU TRUE ;True for regular rs232 ;Moves 'index' to next ;int advance_ptr(int *index) ;element in ring buffer ;{ R2_ADV_PTR MACRO INDEX LOCAL R2_END_ADV INCF INDEX,F ; index++ MOVF INDEX,W ; if (index > last_buffer) SUBLW R2_LAST_BUF SKPNC GOTO R2_END_ADV MOVLW R2_FIRST_BUF; index = first_buffer MOVWF INDEX R2_END_ADV ; return index ENDM ;} ;Inits for RS232 serial routines R2_INIT ;serial ring buffer and status variables MOVLW R2_FIRST_BUF ;out_ptr = first_buf; MOVWF R2_OUT_PTR MOVLW R2_FIRST_BUF ;in_ptr = first_buf; MOVWF R2_IN_PTR CLRF R2_OUT_BIT;out_bit = 0; CLRF R2_IN_BIT ;in_bit = 0; MOVLW H'1' ;out_timer = 1; MOVWF R2_OUT_TIMR ;setup serial port pins BSF R2_PORT,R2_OUT ;outp(1); PAGE_1 BSF TRISB^H'80',R2_IN ;1 is input BCF TRISB^H'80',R2_OUT ;0 is output PAGE_0 RETURN ;Serial output routines ;void serial_out() R2_SER_OUT ;{ TSTF R2_OUT_BIT ; if (out_bit == 0) { SKPZ GOTO R2_TIMER ; // idle, not sending IF R2_DUPLEX == FALSE ; // check if currently reading byte TSTF R2_IN_BIT ; if ((in_bit != 0)&&(r2_duplex == false)) SKPZ RETURN ; return; ENDIF ;R2_DUPLEX MOVF R2_OUT_PTR,W ; if (out_ptr != in_ptr) { SUBWF R2_IN_PTR,W SKPNZ RETURN ; // send next byte MOVLW D'1' ; out_bit = 1; MOVWF R2_OUT_BIT R2_ADV_PTR R2_OUT_PTR ; advance_ptr(out_ptr); RETURN ; } R2_TIMER ; } else { DECF R2_OUT_TIMR,F ; out_timer--; MOVFW R2_OUT_TIMR ; if (out_timer <= 0) { SUBLW D'0' SKPC RETURN MOVLW R2_BAUD ; out_timer = rn_baud; MOVWF R2_OUT_TIMR MOVFW R2_OUT_BIT ; if (out_bit == 1) { SUBLW D'1' SKPZ GOTO R2_TEST_1TO8 ; // start bit BCF R2_PORT,R2_OUT ;!0 outp(0); INCF R2_OUT_BIT,F ; out_bit++ RETURN R2_TEST_1TO8 MOVF R2_OUT_BIT,W ; } else if (out_bit <= 9) { SUBLW D'9' SKPC GOTO R2_STOP ; // send bit MOVF R2_OUT_PTR,W ; if (ring_buffer[out_ptr]&&0x01) MOVWF FSR BTFSC INDF,W BSF R2_PORT,R2_OUT ;!1 outp(1); BTFSS INDF,W ; else BCF R2_PORT,R2_OUT ;!0 outp(0); RRF INDF,F ; ring_buffer[out_ptr] = ring_buffer[out_ptr] >> 1; INCF R2_OUT_BIT,F ; out_bit++ RETURN R2_STOP MOVF R2_OUT_BIT,W ; } else if (out_bit <= 10) SUBLW D'10' SKPC GOTO R2_DONE ; // stop bit BSF R2_PORT,R2_OUT ;!1 outp(1); INCF R2_OUT_BIT,F ; out_bit++; RETURN R2_DONE ; } else { ; // done sending CLRF R2_OUT_BIT ; out_bit = 0; ; } ; } ; } RETURN ;} ;Send byte in W ;void byte_send(int data) R2_SEND ;{ MOVWF SCRATCH_1 ; SCRATCH_1 = W; R2_WHILE_SEND ; while (advance_ptr(in_ptr) == out_ptr) {} MOVF R2_IN_PTR,W ; // wait while buffer full MOVWF SCRATCH_2 R2_ADV_PTR SCRATCH_2 MOVF SCRATCH_2,W SUBWF R2_OUT_PTR,W SKPNZ GOTO R2_WHILE_SEND R2_ADV_PTR R2_IN_PTR MOVF R2_IN_PTR,W ; ring_buffer[in_ptr] = SCRATCH_1; MOVWF FSR MOVF SCRATCH_1,W ; W = SCRATCH_1; MOVWF INDF RETURN ;} ;Check serial input ;void ser_in(void) { R2_SER_IN ;{ MOVF R2_IN_BIT,W; if (in_bit == 0) { SKPZ GOTO R2_BUSY_IN ; // not currently receiving IF R2_DUPLEX == FALSE ; // check if currently sending byte TSTF R2_OUT_BIT; if ((out_bit != 0)&&(r2_duplex == false)) SKPZ RETURN ; return; ENDIF ;R2_DUPLEX BTFSC R2_PORT,R2_IN; if (inp == 1) { RETURN ; // start bit detected MOVLW R2_BAUD ; in_timer = r2_baud MOVWF R2_IN_TIMER MOVLW H'1' ; in_bit = 1 MOVWF R2_IN_BIT CLRF R2_IN_BYTE; in_byte = 0 RETURN ; } R2_BUSY_IN ; } else { // busy reading input DECF R2_IN_TIMER,F; in_timer -- MOVF R2_IN_TIMER,W; if (in_timer == 0) { SKPZ RETURN ; // sample input line MOVLW R2_BAUD ; in_timer = r2_baud MOVWF R2_IN_TIMER MOVF R2_IN_BIT,W; if (in_bit == 9) { SUBLW H'9' SKPZ GOTO R2_TEST ; // done sampling CLRF R2_IN_BIT ; in_bit = 0 MOVF R2_IN_BYTE,W CALL R2_NEW_BYTE ; new_byte() RETURN R2_TEST ; } else // sample byte CLRC ; clear carry BTFSC R2_PORT,R2_IN; if (inp == 1) SETC ; set carry RRF R2_IN_BYTE,F; >> data INCF R2_IN_BIT,F; in_bit ++ ; } ; } ; } RETURN ;} ;Gets called when there is a new byte from rs232 serial line ;R2_NEW_BYTE ; CALL R2_SEND ;echo to serial out ; CALL LCD_PRINT ;display ; RETURN ELSE ;R2_ENABLE R2_SEND ;dummies if module not enabled RETURN ENDIF ;R2_ENABLE ;***** RS422/485 ROUTINES ;Default parameters are no parity, eight bits, one stop bit IF R4_ENABLE == TRUE ;The quiescent state of the line is '1'. A start bit is '0', ;and the data bits follow uninverted. The stop bit is a '1'. ;Constants R4_BAUD EQU RUNSEC/D'9600' IF (RUNSEC != R4_BAUD*D'2400') CALL INTSEC_ERROR ;R4_BAUD must be a whole number - adjust INTSEC or ;adjust the number of modules in use ENDIF R4_PORT EQU PORTB R4_IN EQU 06H ;Data input R4_OUT EQU 07H ;Data output R4_TRANON EQU 05H ;Transmit enable line (for RS485 only) R4_DUPLEX EQU TRUE ;True for RS422, False for RS485 ;Moves 'index' to next ;int advance_ptr(int *index) ;element in ring buffer ;{ R4_ADV_PTR MACRO INDEX LOCAL R4_END_ADV INCF INDEX,F ; index++ MOVF INDEX,W ; if (index > last_buffer) SUBLW R4_LAST_BUF SKPNC GOTO R4_END_ADV MOVLW R4_FIRST_BUF ; index = first_buffer MOVWF INDEX R4_END_ADV ; return index ENDM ;} ;Inits for RS422/485 serial routines R4_INIT ;serial ring buffer and status variables MOVLW R4_FIRST_BUF ;out_ptr = first_buf; MOVWF R4_OUT_PTR MOVLW R4_FIRST_BUF ;in_ptr = first_buf; MOVWF R4_IN_PTR CLRF R4_OUT_BIT;out_bit = 0; CLRF R4_IN_BIT ;in_bit = 0; MOVLW H'1' ;out_timer = 1; MOVWF R4_OUT_TIMR ;setup serial port pins BSF R4_PORT,R4_OUT ;outp(1); PAGE_1 BSF TRISB^H'80',R4_IN ;1 is input BCF TRISB^H'80',R4_OUT ;0 is output PAGE_0 RETURN ;Serial output routines ;void serial_out() R4_SER_OUT ;{ TSTF R4_OUT_BIT ; if (out_bit == 0) { SKPZ GOTO R4_TIMER ; // idle, not sending IF R4_DUPLEX == FALSE ; // check if currently reading byte TSTF R4_IN_BIT ; if ((in_bit != 0)&&(r2_duplex == false)) SKPZ RETURN ; return; ENDIF ;R4_DUPLEX MOVF R4_OUT_PTR,W ; if (out_ptr != in_ptr) { SUBWF R4_IN_PTR,W SKPNZ RETURN ; // send next byte MOVLW D'1' ; out_bit = 1; MOVWF R4_OUT_BIT R4_ADV_PTR R4_OUT_PTR ; advance_ptr(out_ptr); RETURN ; } R4_TIMER ; } else { DECF R4_OUT_TIMR,F ; out_timer--; MOVFW R4_OUT_TIMR ; if (out_timer <= 0) { SUBLW D'0' SKPC RETURN MOVLW R4_BAUD ; out_timer = rn_baud; MOVWF R4_OUT_TIMR MOVFW R4_OUT_BIT ; if (out_bit == 1) { SUBLW D'1' SKPZ GOTO R4_TEST_1TO8 ; // start bit IF R4_DUPLEX == FALSE ; // set enable if needed BSF R4_PORT,R4_TRANON; tx_enable = 1; ENDIF ;R4_DUPLEX BCF R4_PORT,R4_OUT ;!0 outp(0); INCF R4_OUT_BIT,F ; out_bit++ RETURN R4_TEST_1TO8 MOVF R4_OUT_BIT,W ; } else if (out_bit <= 9) { SUBLW D'9' SKPC GOTO R4_STOP ; // send bit MOVF R4_OUT_PTR,W ; if (ring_buffer[out_ptr]&&0x01) MOVWF FSR BTFSC INDF,W BSF R4_PORT,R4_OUT ;!1 outp(1); BTFSS INDF,W ; else BCF R4_PORT,R4_OUT ;!0 outp(0); RRF INDF,F ; ring_buffer[out_ptr] = ring_buffer[out_ptr] >> 1; INCF R4_OUT_BIT,F ; out_bit++ RETURN R4_STOP MOVF R4_OUT_BIT,W ; } else if (out_bit <= 10) SUBLW D'10' SKPC GOTO R4_DONE ; // stop bit BSF R4_PORT,R4_OUT ;!1 outp(1); INCF R4_OUT_BIT,F ; out_bit++; RETURN R4_DONE ; } else { ; // done sending CLRF R4_OUT_BIT ; out_bit = 0; IF R4_DUPLEX == FALSE ; // clear enable if needed BCF R4_PORT,R4_TRANON; tx_enable = 0; ENDIF ;R4_DUPLEX ; } ; } ; } RETURN ;} ;Send byte in W ;void byte_send(int data) R4_SEND ;{ MOVWF SCRATCH_1 ; SCRATCH_1 = W; R4_WHILE_SEND ; while (advance_ptr(in_ptr) == out_ptr) {} MOVF R4_IN_PTR,W ; // wait while buffer full MOVWF SCRATCH_2 R4_ADV_PTR SCRATCH_2 MOVF SCRATCH_2,W SUBWF R4_OUT_PTR,W SKPNZ GOTO R4_WHILE_SEND R4_ADV_PTR R4_IN_PTR MOVF R4_IN_PTR,W ; ring_buffer[in_ptr] = SCRATCH_1; MOVWF FSR MOVF SCRATCH_1,W ; W = SCRATCH_1; MOVWF INDF RETURN ;} ;Check serial input ;void ser_in(void) { R4_SER_IN ;{ MOVF R4_IN_BIT,W; if (in_bit == 0) { SKPZ GOTO R4_BUSY_IN ; // not currently receiving IF R4_DUPLEX == FALSE ; // check if currently sending byte TSTF R4_OUT_BIT; if ((out_bit != 0)&&(r2_duplex == false)) SKPZ RETURN ; return; ENDIF ;R4_DUPLEX BTFSC R4_PORT,R4_IN; if (inp == 1) { RETURN ; // start bit detected MOVLW R4_BAUD ; in_timer = r2_baud MOVWF R4_IN_TIMER MOVLW H'1' ; in_bit = 1 MOVWF R4_IN_BIT CLRF R4_IN_BYTE; in_byte = 0 RETURN ; } R4_BUSY_IN ; } else { // busy reading input DECF R4_IN_TIMER,F; in_timer -- MOVF R4_IN_TIMER,W; if (in_timer == 0) { SKPZ RETURN ; // sample input line MOVLW R4_BAUD ; in_timer = r2_baud MOVWF R4_IN_TIMER MOVF R4_IN_BIT,W; if (in_bit == 9) { SUBLW H'9' SKPZ GOTO R4_TEST ; // done sampling CLRF R4_IN_BIT ; in_bit = 0 MOVF R4_IN_BYTE,W CALL R4_NEW_BYTE ; new_byte() RETURN R4_TEST ; } else // sample byte CLRC ; clear carry BTFSC R4_PORT,R4_IN; if (inp == 1) SETC ; set carry RRF R4_IN_BYTE,F; >> data INCF R4_IN_BIT,F; in_bit ++ ; } ; } ; } RETURN ;} ;Gets called when there is a new byte ;from serial line R4_NEW_BYTE CALL R4_SEND ;echo to serial out CALL LCD_PRINT ;display RETURN ELSE ;R4_ENABLE R4_SEND ;dummies if module not enabled RETURN ENDIF ;R4_ENABLE ;***** LCD ROUTINES IF LCD_ENABLE == TRUE ;Constants ; Connections for LCD: LCD_PORT EQU PORTB ;data is on lower nibble of this port LCD_CNTRL EQU PORTB ;control pins are on this port LCD_E EQU 04H ;Pin for Enable LCD_RS EQU 05H ;Pin for Register Select ; LCD_RW make sure this is grounded LCD_I_DELAY EQU 03H ;Delay time for LCD during init process LCD_T_DELAY EQU 01H ;Delay time for LCD between characters ;Initialize lcd port. This cannot be interrupted. ;Make sure General Interrupt Enable is clear. LCD_INIT ;Setup Port direction PAGE_1 BCF LCD_PORT,W ; 1 IS INPUT BCF LCD_PORT,F ; 0 IS OUTPUT BCF LCD_PORT,2 BCF LCD_PORT,3 BCF LCD_CNTRL,LCD_E BCF LCD_CNTRL,LCD_RS PAGE_0 BSF LCD_CNTRL,LCD_E ; E BCF LCD_CNTRL,LCD_RS ; RS ;Init LCD MOVLW B'00000011' ; 1 CALL LCD_NIBBLE MOVLW LCD_I_DELAY CALL LCD_DELAY MOVLW B'00000011' ; 2 CALL LCD_NIBBLE MOVLW LCD_I_DELAY CALL LCD_DELAY MOVLW B'00000011' ; 3 CALL LCD_NIBBLE MOVLW LCD_I_DELAY CALL LCD_DELAY MOVLW B'00000010' ; 4 CALL LCD_NIBBLE MOVLW LCD_I_DELAY CALL LCD_DELAY MOVLW B'00000010' ; 5 CALL LCD_NIBBLE MOVLW LCD_I_DELAY CALL LCD_DELAY MOVLW B'00000100' ; 5B system set ; 0000 also works CALL LCD_NIBBLE MOVLW LCD_I_DELAY CALL LCD_DELAY MOVLW B'00000000' ; 6 CALL LCD_NIBBLE MOVLW LCD_I_DELAY CALL LCD_DELAY MOVLW B'00001000' ; 6B CALL LCD_NIBBLE MOVLW LCD_I_DELAY CALL LCD_DELAY MOVLW B'00000000' ; 7 CALL LCD_NIBBLE MOVLW LCD_I_DELAY CALL LCD_DELAY MOVLW B'00000001' ; 7B CALL LCD_NIBBLE MOVLW LCD_I_DELAY CALL LCD_DELAY MOVLW B'00000000' ; 8 CALL LCD_NIBBLE MOVLW LCD_I_DELAY CALL LCD_DELAY MOVLW B'00000110' ; 8B entry mode set CALL LCD_NIBBLE ; 101 cursor stays put, screen scrolls right MOVLW LCD_I_DELAY CALL LCD_DELAY ; 111 cursor stays put, screen scrolls left ; 110 cursor moves right, screen stays put ; 100 same as 111 MOVLW B'00000000' ; 9 CALL LCD_NIBBLE MOVLW LCD_I_DELAY CALL LCD_DELAY MOVLW B'00001101' ; 9B 1111 cursor on and blink CALL LCD_NIBBLE ; 1101 cursor on and blink MOVLW LCD_I_DELAY CALL LCD_DELAY ; 1110 cursor off ; 1100 cursor off RETURN ;Send command/data byte to lcd port LCD_PRINT ;lcd_print(W) MOVWF SCRATCH_1 ;SCRATCH_1 = W; ;Check if cursor position command ANDLW H'F0' ;if (msb == 1) { SUBLW H'10' SKPZ GOTO LCD_CHAR MOVFW SCRATCH_1 ; position cursor ANDLW H'0F' IORLW H'80' CALL LCD_INSTRUCT MOVFW SCRATCH_1 ; W = SCRATCH_1; RETURN ;} else { LCD_CHAR ;display character BSF LCD_CNTRL,LCD_RS ;data SWAPF SCRATCH_1,W ; get upper nibble CALL LCD_NIBBLE MOVFW SCRATCH_1 ; get lower nibble CALL LCD_NIBBLE MOVLW LCD_T_DELAY CALL LCD_DELAY MOVFW SCRATCH_1 ; W = SCRATCH_1; RETURN ;} ;Send instruction byte to lcd port LCD_INSTRUCT BCF LCD_CNTRL,LCD_RS ;instruction MOVWF SCRATCH_1 ;store byte SWAPF SCRATCH_1,W ;get upper nibble CALL LCD_NIBBLE MOVFW SCRATCH_1 ;get lower nibble CALL LCD_NIBBLE MOVFW SCRATCH_1 ;restore W RETURN ;Send nibble to lcd port LCD_NIBBLE BSF LCD_CNTRL,LCD_E ; latch control ANDLW 0FH MOVWF SCRATCH_2 MOVFW LCD_PORT ANDLW H'F0' IORWF SCRATCH_2,W MOVWF LCD_PORT MOVWF LCD_PORT ; extra delay BCF LCD_CNTRL,LCD_E ; latch data RETURN ;Delay time for lcd, delay constant in W register. 1 = minimum delay LCD_DELAY MOVWF TIMER_HI ; Use TIMER_HI and TIMER_LO CLRF TIMER_LO LCD_TIME_LOOP DECFSZ TIMER_LO,F; Delay time = TIMER_HI * ((3 * 256) + 3) * Tcy GOTO LCD_TIME_LOOP DECFSZ TIMER_HI,F GOTO LCD_TIME_LOOP RETURN ;Print number in W to LCD as three digit BCD LCD_BCD MOVWF SCRATCH_1 MOVWF LSD CLRF MSD MOVLW .200 SUBWF LSD,W SKPC GOTO LCD_BIN_1 MOVWF LSD ;save number<100 MOVLW '2' CALL LCD_PRINT ;print 100s GOTO LCD_TWO_DIGIT LCD_BIN_1 MOVLW .100 SUBWF LSD,W SKPC GOTO LCD_BIN_0 MOVWF LSD ;save number<100 MOVLW '1' CALL LCD_PRINT ;print 100s GOTO LCD_TWO_DIGIT LCD_BIN_0 MOVLW ' ' CALL LCD_PRINT ;print 100s LCD_TWO_DIGIT MOVLW .10 ;check how many 10s SUBWF LSD,W ; in the input SKPC GOTO LCD_DIGITS ;done MOVWF LSD ;move 10 from LSD INCF MSD,F ; to MSD GOTO LCD_TWO_DIGIT LCD_DIGITS MOVFW MSD ADDLW '0' CALL LCD_PRINT MOVFW LSD ADDLW '0' CALL LCD_PRINT MOVFW SCRATCH_1 RETURN ELSE ;LCD_ENABLE LCD_PRINT ;dummies if lcd module not enabled RETURN LCD_BCD RETURN ENDIF ;LCD_ENABLE ;***** INFRA RED ROUTINES IF IR_ENABLE == TRUE ;Constants IR_PORT EQU PORTA ;Port and pins IR_IN EQU 3H ;for IR port IR_OUT EQU 4H ;See GEN_INIT for more IR_DWELL EQU H'FF' ;longest delay IR_30 EQU (RUNSEC * D'30')/D'10000' IR_24 EQU (RUNSEC * D'24')/D'10000' IR_18 EQU (RUNSEC * D'18')/D'10000' IR_12 EQU (RUNSEC * D'12')/D'10000' IR_10 EQU (RUNSEC * D'10')/D'10000' IR_09 EQU (RUNSEC * D'09')/D'10000' IR_06 EQU (RUNSEC * D'06')/D'10000' IR_03 EQU (RUNSEC * D'03')/D'10000' IR_DEBUG EQU FALSE IR_INIT ;Registers CLRF IR_DEV ;ir_dev = 0; CLRF IR_DATA ;ir_data = 0; CLRF IR_PHASE ;ir_phase = 0; BSF IR_PHASE,7 ;ir_phase,7 = 1; MOVLW IR_10 ;ir_timer = IR_10; MOVWF IR_TIMER CLRF IR_O_DEV ;ir_o_dev = 0; CLRF IR_O_DATA ;ir_o_data = 0; CLRF IR_O_PHASE ;ir_o_phase = 0; CLRF IR_O_TIMER ;ir_o_timer = 0; CLRF IR_O_COUNT ;ir_o_count = 0; ;IO Port. See GEN_INIT for background operation of Port PAGE_1 BSF IR_PORT,IR_IN BCF IR_PORT,IR_OUT PAGE_0 BCF IR_PORT,IR_OUT ;output(0); RETURN ;Increment 'ir_timer' until 0xFF IR_INC_COUNT MACRO MOVLW H'FF' ;if(ir_timer != 0xff) SUBWF IR_TIMER,W SKPZ INCF IR_TIMER,F ; ir_timer++; ENDM ;Decode length of pulse IR_BIT MACRO MOVLW IR_30 ;if (ir_timer > IR_30) { SUBWF IR_TIMER,W ; // false trigger SKPC GOTO IR_ELSE_SY CLRF IR_PHASE ; ir_phase = 0; IF IR_DEBUG == TRUE MOVLW 'L' CALL LCD_PRINT ENDIF GOTO IR_ELSE_END IR_ELSE_SY MOVLW IR_18 ;} else if (ir_timer > IR_18) { SUBWF IR_TIMER,W ; // sync pulse is 2.4 msec nominal SKPC GOTO IR_ELSE_LONG CLRF IR_DEV ; ir_dev = 0; CLRF IR_DATA ; ir_data = 0; MOVLW D'1' ; ir_phase = 1; MOVWF IR_PHASE IF IR_DEBUG == TRUE MOVLW 'S' CALL LCD_PRINT ENDIF GOTO IR_ELSE_END IR_ELSE_LONG MOVLW IR_09 ;} else if (ir_timer > IR_09) { SUBWF IR_TIMER,W ; // long hi, logic 1 SKPC GOTO IR_ELSE_SHORT ;Store '1' MOVLW D'8' ; if (ir_phase > 8) { SUBWF IR_PHASE,W SKPC GOTO IR_1_ELSE SETC ; carry set RRF IR_DEV,F ; ir_dev >> GOTO IR_1_END ; } IR_1_ELSE MOVLW D'0' ; else if (ir_phase > 0) { SUBWF IR_PHASE,W SKPC GOTO IR_1_END BSF IR_DATA,7 ; ir_data,7 = 1 CLRC RRF IR_DATA,F IR_1_END ; } INCF IR_PHASE,F ; ir_phase++; IF IR_DEBUG == TRUE MOVLW '1' CALL LCD_PRINT ENDIF GOTO IR_ELSE_END IR_ELSE_SHORT MOVLW IR_03 ;} else if (ir_timer > IR_03) { SUBWF IR_TIMER,W ; // short hi, logic 0 SKPC GOTO IR_ELSE_BAD ;Store '0' MOVLW D'8' ; if (ir_phase > 8) { SUBWF IR_PHASE,W SKPC GOTO IR_0_ELSE CLRC RRF IR_DEV,F ; ir_dev >> with carry clear GOTO IR_0_END ; } IR_0_ELSE MOVLW D'0' ; else if (ir_phase > 0) { SUBWF IR_PHASE,W SKPC GOTO IR_0_END CLRC ; ir_data >> with carry clear RRF IR_DATA,F IR_0_END ; } INCF IR_PHASE,F ; ir_phase++; IF IR_DEBUG == TRUE MOVLW '0' CALL LCD_PRINT ENDIF GOTO IR_ELSE_END IR_ELSE_BAD ;} else { // false trigger CLRF IR_PHASE ; ir_phase = 0; IF IR_DEBUG == TRUE MOVLW 'B' CALL LCD_PRINT ENDIF IR_ELSE_END ;} ENDM ;Long IR off elapsed, check for valid stream IR_CHECK_NEW MACRO MOVLW IR_06 ;if (ir_timer > IR_06) { SUBWF IR_TIMER,W SKPC GOTO IR_C_END MOVLW H'90' ; if (ir_phase == 16) { SUBWF IR_PHASE,W ; // 8 bit device code SKPZ GOTO IR_C_ELSE ; // no further processing needed CALL IR_NEW ; new_ir(); GOTO IR_C_CLEAN IR_C_ELSE MOVLW H'8D' ; else if (ir_phase == 12) SUBWF IR_PHASE,W ; // 5 bit device code SKPZ GOTO IR_C_CLEAN ; // justify properly CLRC ; ir_dev >> 3 RRF IR_DEV,F RRF IR_DEV,F RRF IR_DEV,F CALL IR_NEW ; new_ir(); IR_C_CLEAN ; } MOVLW H'80' MOVWF IR_PHASE ; ir_phase = 0; IR_C_END ENDM ;} ;Sample IR IR_GET BTFSS IR_PORT,IR_IN ;if (ir_input == 1) GOTO IR_ON ;{ // ir off BTFSC IR_PHASE,7 ; if (ir_phase,7 = 0) GOTO IR_WAS_OFF ; { // was on before IR_BIT ; check_bit(ir_timer); BSF IR_PHASE,7 ; ir_phase,7 = 1; CLRF IR_TIMER ; ir_timer = 0; IR_WAS_OFF ; } IR_CHECK_NEW ; check_new(); IR_INC_COUNT ; increment ir_timer if needed GOTO IR_END ;} else IR_ON ;{ // ir on BTFSS IR_PHASE,7 ; if (ir_phase,7 = 1) GOTO IR_WAS_ON ; { // was off before BCF IR_PHASE,7 ; ir_phase,7 = 0; CLRF IR_TIMER ; ir_timer = 0; IR_WAS_ON ; } IR_INC_COUNT ; increment ir_timer if needed IR_END ;} RETURN ;Act on new IR command. Device is in IR_DEV and data is in IR_DATA IR_NEW MOVLW 'D' CALL LCD_PRINT MOVLW '=' CALL LCD_PRINT MOVFW IR_DEV CALL LCD_BCD MOVLW ' ' CALL LCD_PRINT MOVLW 'C' CALL LCD_PRINT MOVLW '=' CALL LCD_PRINT MOVFW IR_DATA CALL LCD_BCD MOVLW H'10' CALL LCD_PRINT RETURN ;Send data in ir_dev and ir_data. Does not restore W register IR_SEND ;// wait until interrupt routine is done TSTF IR_O_PHASE ;while (ir_o_phase != 0) {//wait} SKPZ GOTO IR_SEND TSTF IR_O_TIMER ;while (ir_o_timer != 0) {//wait} SKPZ GOTO IR_SEND TSTF IR_O_COUNT ;while (ir_o_count != 0) {//wait} SKPZ GOTO IR_SEND MOVLW D'2' ;// reload for new tx MOVWF IR_O_COUNT ;ir_o_count = 2; // send twice RETURN ;Use interrupts to transmit IR command IR_PUT MOVLW D'1' ;if (ir_o_timer >= 1) { SUBWF IR_O_TIMER,W ; // wait time in effect SKPC GOTO IR_QUIET DECF IR_O_TIMER,F ; ir_o_timer --; GOTO IR_O_END IR_QUIET ;} else if (ir_o_phase == 0) { TSTF IR_O_PHASE ; // done transmitting packet SKPZ GOTO IR_SYNC ; // check if any more DEBUG_IR BCF IR_PORT,IR_OUT ; output(0); MOVLW D'1' ; if ( ir_o_count >= 1 ) { SUBWF IR_O_COUNT,W SKPC GOTO IR_O_END ; // reload for new tx DECF IR_O_COUNT,F ; ir_t_cout --; MOVFW IR_T_DEV ; ir_o_dev = ir_t_dev; MOVWF IR_O_DEV MOVFW IR_T_DATA ; ir_o_data = ir_t_data; MOVWF IR_O_DATA MOVLW D'1' ; ir_o_phase = 1; MOVWF IR_O_PHASE GOTO IR_O_END ; } IR_SYNC ;} else if (ir_o_phase == 1) { MOVLW D'1' ; // send sync SUBWF IR_O_PHASE,W SKPZ GOTO IR_LOW INCF IR_O_PHASE,F ; ir_o_phase++; BSF IR_PORT,IR_OUT ; output(1); MOVLW IR_24 ; ir_o_timer = IR_24; MOVWF IR_O_TIMER GOTO IR_O_END IR_LOW ;} else if (ir_o_phase,W == 0) { BTFSC IR_O_PHASE,W ; // send low GOTO IR_HIGH ; // ir_phase == 2,4,6, etc. BCF IR_PORT,IR_OUT ; output(0); ;check if transmission over MOVLW D'26' ; if (ir_o_phase == 26) { SUBWF IR_O_PHASE,W SKPZ GOTO IR_DONE15 ; // setup to continue transmission INCF IR_O_PHASE,F ; ir_o_phase++; MOVLW IR_06 ; ir_o_timer = IR_06; TSTF IR_O_DEV ; if (ir_o_dev == 0) { // test if continue tx SKPZ GOTO IR_O_END CLRF IR_O_PHASE ; ir_o_phase = 0; // stop transmission MOVLW IR_DWELL ; ir_o_timer = IR_DWELL; // space out messages MOVWF IR_O_TIMER ; } GOTO IR_O_END ; } IR_DONE15 ; else if (ir_o_phase == 32) { MOVLW D'32' SUBWF IR_O_PHASE,W SKPZ GOTO IR_PROCEED CLRF IR_O_PHASE ; ir_o_phase = 0; // stop transmission MOVLW IR_24 ; ir_o_timer = IR_24; // space out messages MOVWF IR_O_TIMER GOTO IR_O_END IR_PROCEED ; } else { // continue transmission INCF IR_O_PHASE,F ; ir_o_phase++; MOVLW IR_06 ; ir_o_timer = IR_06; MOVWF IR_O_TIMER GOTO IR_O_END ; } IR_HIGH ;} else ;send high BSF IR_PORT,IR_OUT ; output(1); MOVLW IR_06 ; ir_o_timer = IR_06; MOVWF IR_O_TIMER MOVLW D'17' ; if (ir_o_phase >= 17) { SUBWF IR_O_PHASE,W SKPC GOTO IR_SEND_DEV ; // send device bit CLRC ; clear carry RRF IR_O_DEV,F ; ir_o_dev >> GOTO IR_SELECT_OK IR_SEND_DEV ; } else { ; // send data bit CLRC ; clear carry RRF IR_O_DATA,F ; ir_o_data >> IR_SELECT_OK ; } ;select length of pulse SKPC ; if (carry) { GOTO IR_OUTDONE ;output long high (1) MOVLW IR_12 ; ir_o_timer = IR_12; MOVWF IR_O_TIMER IR_OUTDONE ; } INCF IR_O_PHASE,F ; ir_o_phase++; IR_O_END ;} RETURN ENDIF ;IR_ENABLE ;***** END OF FILE ***** Date: Sat, 1 Apr 1995 18:34:20 I developped a home automation program in Visual Basic : James 1.0 You can think of James as a butler. He is capable of controling electrical and IR controled apparatus. James can be controled by voice, by a ζdiaryΖ database, by mouse or by keyboard. James gives information via the Pcscreen or speeks to you : he can say ascii or play wav files. For the voice recognition, I use a Tandy Voice recognition card and the accompanied software Voicekey. The IR module is based on a Siemens SFH50630 and is made according the guidelines of Chris Dodge (See : http://alfred1.u.washington.edu:8080/~pfloyd/ee/circuits/PCIR/Welcome .html) To control the electrical apparatus, you can use the Velleman K8000 kit or use X10 modules and control them via IR. No need for a x10 controler. I use the X10 Powermid transmitters, they are capable of transmitting IR from one room to another. I use a audiopro soundcard but any soundblaster compatible card will do Almost everyting is database controled. I use the MS access 2.0 database engine. When you start the program, James shows you a number of rooms. You can define, create, change the rooms yourself. Each room is represented by a bitmap (changeable via the standard windows software Paintbrush) A mouseclick on a room shows all the apparatus (also represented by bitmaps, two actually, one for the on status and one for the off status) you defined for that room. A mouseclick on an apparatus ( or a a push on a keyboard key you attached to the apparatus) , changes its status. You can define groups of apparatus (for example all the lights in the living room) and attach a key to the group so the status of all the members of the group changes when you press the key. (You can even define groups within groups) In the same way you can group apparatus, you can group IR signals an attach a key to the group. Pushing the key ( or generating it by voicecontrol) results in sending all the IR signals in the group. Every minute, the program checks the ζdiaryΖ database.(Ms access 2.0). In this diary, you can tell James to play a wav file, say an ascci tekst, put an apparatus (or a group) on or off, send an ir signal (or a group of ir signals), say the time, start any external program.. To make it short a few practial examples of what is possible with James 1.0 I call James, he says ζYesΖ , and then I have 5 seconds to say a voice command. fi When I say dollar, James puts on the television ( if it was already on, the television shows the selected channel, goes to BRT 1 (the wanted channel), puts on teletext mode, and selects page 540 where I can find the wanted valuta information. None of this is hard coded, James gets all the information out of the Msaccess database. When my little daughter says ζSamsonΖ ( its a childrens program like big bird), James puts on the televison, selects the video channel, and starts playing the samson video Why this information ? To check the overall interest in a program like James, to see if it is worth putting a shareware version on the internet. To find some place where I can put html-pages about James. I hope to get a lot of reactions . Benny Hooyberghs email : bhooyber@innet.be Date: Tue, 7 Feb 1995 09:00:30 -0700 To all X-10 hackers: I recently posted my intention of uploading, to an FTP site, drawing files of the component placement, PC board layout and schematics for the X-10 2-way and 3-way wallswitches. I have been trying to find out how to get them to the comp.home.automation WWW site, but I haven't heard from the WWW keeper there. However, I just finished uploading them to another FTP site (ftp://ilces.ag.uiuc.edu/tmp/) which is an interim location until they get moved to the ASRE archives at ftp://mrcnext.cso.uiuc.edu/asre/. I don't know when the transfer will take place, but I suppose you can look in both locations. The seven files all have the form: "wall_*.*" and includes a descriptive text file. A cursory inspection reveals that there are two L1s on the component layout drawing. I believe the lower one should be L2. I replaced the triac with Digi-Key's part no.L4008L6-ND. This part is rated for 8 Amps@400V. I refrained from using the often quoted part from Radio Shack (#276-1000) because a Mr. Module article described them as not having an isolated tab. That is VERY important for this application. The unit from Digi-Key has an isolated tab and costs $2.09 I would like to make a few observations. 1) I have heard of and measured (using my cap. meter) a 0.1uF capacitor between the red and blue wire of the companion switch. 2) The -VDC is -15Volts. 3) CR6 should be a 15 Volt Zener, it regulates the -VDC. 4) The fusible link was omitted, it is in series with SW1. 5) There are two L1s in the 'Component Side View'. The smaller one is probably L2. 6) If one considers the black wire to be common (instead of +VDC) analysis of the circuit becomes easier. Repair tips 1) Definitely use a GFCI outlet. 2) Connect Black wire to neutral (wire in lamp according to your preference). The neutral is the wider of the two blades on a plug. 3) For waveform or voltage measurements connect between black wire and node. 4) A convenient point for power supply voltage measurement is the wire ' loop' of R5. This should be at least -15V, if not check R8. 5) Connect to R3 and push the wall switch button to check for low-duty-cycle square wave. This confirms the chip is trying to switch on the load. If the lamp is still not lit, suspect triac. 6) If no square wave at (5), check for 60Hz at pin 6. If none suspect 1/2 watt R7. 6) To reinsert the PC board, remove the metal front, then snap out the slide shutoff switch. 7) While you have the whole thing disassembled, you might as well install the local dimming mod. >Trying to X-10 in my house, I have a number of places where controllers on >on one side can't control a module on the other side - a classic case of >the signal not being able to cross phases correctly. (I've tested this by > >But, an idea occurred to me. I've got an unused 220v dryer outlet (we >switched to gas). Could I put something together, plug it into the >dryer outlet, and Viola! my phases are coupled? Cheap, easy to install, >easy to deinstall if I decide to move. Sounds perfect! Yup, been there, done that. I plugged in a 0.05uF, 600 Volt ceramic capacitor in my dryer outlet to use as my signal bridge. It is supposedly not as good as the real Leviton signal bridge, but it was also nearly free, and has worked for several years. Obdisclaimer: when working near 220V, turn off the breaker, cut off all power to the house, stand on rubber sheets, wear a rubber suit, and hire someone to do the electrical work. An even easier solution worked for me. First, you should use a capacitor that is UL listed for across-the-line connection. Radio Shack sells one that is .01uf, 2kv I think. Next, you can put it across the outputs of any 220v circuit breaker (turn it off first) if you are careful working inside the box there. I found the easiest way was to simply wedge the leads in, and position the capacitor in a stable position where it can't short anything. X10 FAQ version 1.08 (8 Jan 95) CHANGES SINCE LAST VERSION Global FAQ structure changed to aid automatic parsing. Details posted to comp.home.automation or available from address above. This may evolve in future versions of the FAQ. Suggestions and comments welcome. Q107. How do I solve common X10 problems? Rewritten. Q110. Where do I get X10 software for my computer? Added another source. Q113. How do I control fluorescent and halogen lights with X10? Completely rewritten. Q116. Can I use X10 components outside? New question. Q117. What are the various combinations of X10 wireless receivers and transmitters that work together? New question. Q118. How do I make the motion detector floodlight unit work properly? New question. Q508. How do I repair a "blown" lamp module? Minor changes, alternate source for triac. Section 2: added some Radio Shack part numbers for existing descriptions OUTLINE SECTION 1: General Information Q101. What is X10? Q102. What sort of X10 transmitters exist? Q103. What sort of X10 receivers exist? Q104. How many different units can X10 handle? Q105. Who makes X10 components? Q106. Who sells X10 components? Q107. How do I solve common X10 problems? Q108. Will X10 work on 220/240V? Q109. How do I send and receive X10 signals with my computer? Q110. Where do I get X10 software for my computer? Q111. Where do I look for more information on X10? Q112. How should I design the wiring of my new home to accommodate X10? Q113. How do I control fluorescent and halogen lights with X10? Q114. Can I use X10 in a three-way light switching application? Q115. What is PLIX? Q116. Can I use X10 components outside? Q117. What are the various combinations of X10 wireless receivers and transmitters that work together? Q118. How do I make the motion detector floodlight unit work properly? SECTION 2: Information on X10 Components SECTION 3: Details on X10 Protocol SECTION 4: Programming details for CP290 Home Control Interface SECTION 5: Modifications to X10 hardware Q501. How do I modify appliance modules for momentary operation? Q502. How do I add local dimming capability to wall switch modules? Q503. How do I modify the maxi-controller to accommodate more than 16 units? Q504. How do I modify the mini-controller to control more units? Q505. How do I modify the mini-controller to control all units for a single housecode? Q506. How do I modify the mini-controller to control only units 9-12 or 13-16? Q507. How do I modify the mini-controller for momentary operation? Q508. How do I repair a "blown" lamp module? Q509. How do I defeat local control of lights and appliances? Q510. How do I add a relay output to the power horn? SECTION 1: GENERAL INFORMATION =============================== Q101. What is X10? A101. X10 is a communications protocol for remote control of electrical devices. It is designed for communications between X10 transmitters and X10 receivers which communicate on standard household wiring. Transmitters and receivers generally plug into standard electrical outlets although some must be hardwired into electrical boxes. Transmitters send commands such as "turn on", "turn off" or "dim" preceded by the identification of the receiver unit to be controlled. This broadcast goes out over the electrical wiring in a building. Each receiver is set to a certain unit ID, and reacts only to commands addressed to it. Receivers ignore commands not addressed to them. Note that "X-10" is a trademark of X-10 (USA) Incorporated an possibly of X-10 Home Controls Incorporated (in Canada) as well. This FAQ uses "X10" unless referring specifically to a product of the holder of the "X-10" trademark. Q102. What sort of X10 transmitters exist? A102. The simplest X10 transmitter is a small control box with buttons. The buttons select which unit is to be controlled, and which control function is to be sent to the selected units (e.g. "turn on", "all units off", etc). There are also clock timer transmitters which can be programmed to send X10 commands at certain times. Some of these can be programmed with buttons on the timer; some must be connected to a computer to select the times. There are other special purpose transmitters that send certain X10 commands at sunup or sundown, upon detecting movement, or as commanded by tones over a telephone. This is not an all inclusive list, and more detail on specific transmitters is given in Section 2. Q103. What sort of X10 receivers exist? A103. The simplest X10 receiver is a small module with an electrical plug (to connect to a standard wall outlet), an electrical outlet (to provide controlled power to the device it's controlling) and two dials (to set the unit ID code) on it. An appliance module has relay inside which switches power to its outlet on or off in response to X10 commands directed to it. A lamp module is similar, but has a triac instead of a relay and will respond to dimming commands as well as on or off commands. Other receivers can be wired into wall outlets or into lamp fixtures. Note that the standard wall switch (X10:WS467) is a receiver, not a transmitter; it does not transmit X10 commands, and only takes action when it receives the appropriate X10 command or local button-push. Q104. How many different units can X10 handle? A104. X10 specifies a total of 256 different addresses: 16 unit codes (1- 16) for each of 16 house codes (A-P). Normally a transmitter is set to a certain house code (generally selectable by means of a dial) and so can control at most 16 unit codes. There is no restriction on using multiple transmitters each set to a different house code on the same wiring. Also, several receivers could be set to the same house code and unit code so a single command issued by an X10 transmitter could control multiple receivers in parallel. Q105. Who makes X10 components? A105. Many different companies either make and/or distribute X10 components under different names. Some types are sold by more than one company (probably made by same OEM). Some are specific to only one company. Not all companies handle the complete range of components. Some companies selling X10 components and their associated product names are: - Radio Shack: Plug 'N Power - Leviton: Decora Electronic Controls Leviton Mfg. Co. Inc. Leviton Manufacturing of Canada 59-25 Little Neck Pkwy 165 Hymus Blvd Little Neck, NY 11362-2591 Point Claire, QC H9R 1G2 (718) 229-4040 (800) 824-3005 - Stanley: Light Minder - X-10: Powerhouse X-10 (USA) Inc. X-10 Home Controls Inc. 91 Ruckman Road, Box 420 1200 Aerowood Drive, Unit 20 Closter, NJ 07624-0420 Mississauga, Ont L4W 2S7 (201) 784-9700 (416) 624-4446 (800) 526-0027 (800) 387-3346 x10usa@aol.com Q106. Who sells X10 components? A106. The following companies are alleged to sell X10 components in North America. See Q108 for outside North America. Listing in this FAQ is not an endorsement or recommendation of any kind: Baran-Harper Group Inc. 77 Drakefield Road Markham, ON L3P 1G9 Help/Info: (905) 294-6473 Orders only: (800) 661-6508 Fax: (905) 471-3730 BBS1: (905) 471-9574 BBS2: (905) 471-6776 Canadian Control and Automation Ltd 7 Wincanton Rd. Markham, Ontario CANADA L3S-3H3 Phone: (905) 470-9121 FAX: (905) 568-3658 Complete Home Automation Phone: (800) 766-4226 (doesn't work in Canada) Home Automation, Inc. 2709 Ridgelake Dr. Metairie, LA 70002 Phone: (504) 833-7256 Fax: (504) 833-7258 Home Automation Laboratories 5500 Highlands Pkwy, Suite 450 Smyrna, GA 30082-5141 Orders: (800) 466-3522 Catalog: (800) 935-4425 Help: (404) 319-6000 Fax: (404) 438-2835 (is this the right number?) (404) 410-1122 (is this the right number?) BBS: (404) 319-6227 (300-14.4,8,N,1) Home Automation and Security 286 Ridgedale Ave. East Hanover, NJ 07936 Orders: (800) 254-5950 Help: (201) 887-1117 Fax: (201) 887-5170 Home Automation Systems, Inc. 151 Kalmus Drive, Suite M6 Costa Mesa, CA 92626 Orders: (800) 762-7846 (doesn't work in Canada) (800) 367-9836 (supposedly works in Canada, but doesn't really) Help: (714) 708-0610 (also for orders from outside US) Fax: (714) 708-0614 Home Control Concepts 9520 Padgett St. Suite 108 San Diego, CA 92126 Orders: (800) 266-8765 (doesn't work in Canada) Help: (619) 693-8887 Fax : (619) 693-8892 Hybrid Technical Systems, Inc. 4765 Franchise Street Charleston, SC 29418 Orders: (800) 289-2001 (doesn't work in Canada) America Online: HybridTech Compuserve: 71561,2604 JaMar Distributing 1292 Montclair Drive, Pasadena, MD 21222 Orders: (800) 477-8142 (doesn't work in Canada) Fax: (410) 437-3757 Help: (410) 437-4181 JDS Technologies 16750 W. Bernardo Drive San Diego, CA 92127 Orders: (800) 983-5537 Help: (619) 487-8787 Fax: (619) 451-2799 Marrick Limited P.O. Box 950940 Lake Mary, FL 32795 Phone: (407) 323-4467 Fax: (407) 324-1291 BBS: (407) 322-1429 MicroMint 4 Park St. Vernon, CT 06066 Orders: (800) 635-3355 (doesn't work in Canada) Phone: (203) 871-6170 Fax: (203) 872-2204 Q107. How do I solve the most common X10 problems? A107. There is a common problem that you may encounter in setting up your home with X10 modules. This happens mostly in larger homes, say larger than 2000 square feet (185 square metres). The symptoms are that some receiver modules may not work when commanded from some transmitters, or they may only work sporadically. This could be caused by too much isolation between the two sides of the power line (assuming North American wiring standards): a transmitter on one side will not transmit reliably to a receiver on the other side. Try your X10 system with and without your electric stove turned on; turning the stove on may bridge both sides of the power line, but is not the recommended permanent solution. A better way would be to install a signal bridge which is available as a commercial product. See section 2 below for details. An alternative solution is to install a 0.1 microfarad capcitor (240 VAC or 600 VDC) across the 220 volt line "hot-to-hot". A qualified electrician can do this across any 220 volt double pole breaker. This will bridge the signal from one side to the other. This could also be because the distance from the transmitter to the receiver is too great and the signals are two weak to activate the receiver. If moving the transmitter does not work or is not feasible, the solution may be to install a signal amplifier. This is available as a commercial product. See Section 2 below for details. Noise blocks or noise filters may solve other more obscure problems (false ON/OFF signals, for example), often caused by TVs or wireless intercomms. Locate interference sources by unplugging them one at a time. See details on commercially available nosie blocks and filters in Section 2 below if moving the transmitter away from interference sources does not work or is not feasible. If a WALL OUTLET 220V, 15A (X10:HD243) or WALL OUTLET 220V, 20A (X10:HD245) doesn't seem to work in an apartment or office building, that may be because the building has a three phase power system and the X10 outlets are designed to work on a single (split) phase system such as found in a home. There is no solution to this. Some power strips that have filters in them to protect electronic equipment effectively filter out X10 signals. Cheaper power strips that protect against voltage spikes only do not affect X10 signals. Try moving X10 transmitters or receivers from power strips to a standard outlet if they don't seem to be working. Another common problem with X10 devices is not reading the documentation that comes with them. People still insist on trying to use dimmer switches or lamp modules on electric fans or fluorescent lights (symptom can be fire), or trying to control low wattage lamps (symptom may be unreliable operation for less than 50W for some modules). Solution: RTFM. See also Q113. Q108. Will X10 work on 220/240V? A108. There are X10 receiver modules designed to control 240 volt loads, but only where these are part of a standard North American wiring system, e.g. for the electric stove or electric drier. See section 2 below. Knowledge of how X10 works on anything else than 60 Hz 110V is a bit hazy in North America. The following companies are reputed to sell X10 devices for European use: Busch-Jaeger Elektro GmbH P.O. box 1280 D-5880 Luedenscheid Germany Phone: +49 2351 956-0 Fax : +49 2351 956-694 Celtel (Celtec?) Ltd P.O. Box 135 Basingstoke RG25 2HZ U.K. Phone: 0256 474900 Fax: 0256 818064 WDC Home Automation Somewhere in the U.K. 0635 866707?? 0635 871141 ?? The following companies are reputed to sell X10 devices in Australia: CEBus Australia PO BOX 178 Greensborough VIC 3088 Australia Phone: 03 467 7194 Fax: 03 467 8422 Midac Technologies Upper Monkerai New South Wales 2415 Australia Phone: 049 94 7069 Fax: 049 94 7039 The Smart Company 5 Mouat Street PO Box 127 Fremantle, Western Australia 6160 Australia Phone: 09 430 8887 Fax: 09 430 8886 Q109. How do I send and receive X10 signals with my computer? A109. The easiest way of giving your computer some control over X10 modules is via the CP290 Home Control Interface. This is a small box that connects to a standard RS-232 serial port and has its own internal battery backed up seven day clock. It is sold with software to work with a PC, Mac, Apple ][, or Commodore 64/128, and comes with the appropriate serial cable (the CP290 box itself is the same for all). Once you set up to 128 events (on, off, dim) using your computer, you can turn off the computer and the box will transmit scheduled X10 commands on a daily or weekly schedule. The CP290 also has an "immediate" mode to send X10 commands from the computer to X10 receivers. Details on programming the CP290 are in Section 4. There are also other X10 modules to interface computers directly to the power line to send and/or receive X10 commands. These are the PL513 (send only) and the TW523 (send and receive). The TW523 is a low level two-way interface to the power line. It contains a PIC controller to decode incoming signals and store them for transmission to the host computer. It's essentially a 120KHz modulator and demodulator, with just enough smarts to recognize a valid X-10 command code. Due to the tight timing requirements and lack of drivers, applications are limited to systems developers and experienced hobbyists willing to code in assembly. The computer interfaces to the TW523 through an RJ-11 modular phone jack which has the following signals: signal (not AC) ground, receive output, zero-cross output and transmit input. All signals are optocoupled, and the outputs are open-collector. A logic high (greater than 4V) on the transmit input modulates the AC line with the 120KHz carrier wave. The zero-cross output is a square wave coincident with the 60Hz AC line. The receive output is an envelope of the X-10 signal, and is low when the 120KHz signal for `bit=1' is present during a valid code. The signal applied to the transmit input must encompass all of the bits for all 3 phases of the line (i.e. 3 bits per half AC cycle). The computer must follow the full transmission protocol detailed in Section 3 of the FAQ, but only needs to send the proper envelope for the transmission as the TW523 converts the digital envelope into bursts of 120KHz carrier. The receive output is buffered through the PIC in the TW523. The first valid X-10 code cycle on the AC line alerts the PIC (and is lost to the controlling computer). During the second code cycle (all codes in X-10 protocol are sent twice), the TW523 outputs a low when there is 120KHz carrier on the AC line, and only during the bit time for the local AC phase. The signals for the other two AC phases are not echoed to the controlling computer. The output is open-collector at all other times. The logic is reversed; when there's a valid `bit=1' (120KHz carrier), the output is low, and high otherwise. Since the TW523 responds to all signals on the AC line, it also echoes any sent by the controlling computer, allowing for collision detection similar to that used by the Ethernet protocol (CSMA/CD). [Question: does it output only the second transmission when echoing local transmissions?] These units may be supplied with parallel or serial port adaptors. These use handshaking bits in non-standard ways, so normal serial and parallel portdrivers are not of any use. See also Q115 for information on PLIX, which simplifies interface requirements considerably. Q110. Where do I get X10 software for my computer? A110. The CP290 Home Control Interface comes with software for either IBM PC, Mac, Apple ][, or Commodore 64/128. This is rudimentary, but functional. Baran-Harper Group Inc in Ontario runs a bulletin board that has a good selection of software for the CP290 and TW523. Their BBS numbers are (905) 471-9574 and (905) 471-6776. Also try BBS listed for other companies in A106 above. Other sources: FTP: ftp.digibd.com:/pub/rick/x10.shar oak.oakland.edu:/pub/msdos/x_10/ (CP290 software) mrcnext.cso.uiuc.edu:/asre/ cs.sunysb.edu:/pub/386BSD/xten.tgz id.wing.net:/pub/pgf/x10/x10.tar.gz (UNIX CP290 software) WWW: http://www.digibd.com/people/rick http://web.cs.ualberta.ca/~wade/HyperHome/ Q111. Where do I look for more information on X10? A111. Try the following: Magazines: Electronic House (is this the editorial address???) EH Publishing P.O. Box 339 Stillwater, OK 74076-9923 Phone: (405) 624-8015 (800) 375-8015 ??? FAX: (405) 743-3374 Electronic House (is this the address for subscriptions only???) P.O. Box 7972 Riverton NJ 08077-8672 Phone: (508) 358-3400 FAX: (508) 358-5195 Practical Home Automation magazine 3043 South Laredo Circle Aurora, CO USA 80013-1805 Phone: (303) 699-5541 FAX: (303) 766-2696 BBS: (303) 680-3864 (8N1, 2400-9600 V.32) Books: "How to automate your home", 2nd Edition byDavid Gladdis, published 1991 by David Gladdis, ISBN 0-9632170-0-3, available from Baran-Harper and possibly other X-10 mail-order companies WWW: http://web.cs.ualberta.ca/~wade/HyperHome/ X10 Expertise for hire: Canadian Control and Automation Ltd 7 Wincanton Rd. Markham, Ontario CANADA L3S 3H3 Phone: (905) 470-9121 FAX: (905) 568-3658 Custom engineered home automation systems, security,fully distributed A/V, home theater, energy management solutions, also SmartHouse(tm) certified T. Brusehaver Empowered Home 10608 Alabama Circle Bloomington, MN 55438 Phone: (612) 887-1342 X10 hardware and software, development in other areas of home automation, energy saving devices, smart occupancy sensors, infrared control Rick Sloan IntelliHome Controls 15 - 8 Deerfield Drive Nepean, ON, CANADA K2G 3R6 Phone: (613) 723-1427 FAX/BBS: (613) 723-2370 E-mail: al904@freenet.carleton.ca X10 hardware and software, development in other areas of home automation, energy saving devices,smart occupancy sensors, products for disabled persons, infrared control Q112. How should I design the wiring of my new home to accommodate X10? A112. Most X10 receivers and transmitters can be plugged or wired into conventional wiring in any home without any special preparation or design. However, if you have the luxury of designing the wiring in your home before it is built, there are a few things you may wish to consider. A conventional light switch is wired into the circuit between the power panel and the light it controls. Wiring conventional three-way (or more) switches for use at the top and bottom of the stairs for example, takes special wiring and foresight. There are X10 wall switches to replace conventional switches in conventional wiring, both for simple on/off and three-way control. See Q114. You may wish, however, to put dedicated control modules (see LEV:6375, LEV:6376 in Section 2) into built-in light fixtures and wire these fixtures directly to the power supply with no conventional switch. You could then turn the lights on or off from X10 transmitter anywhere in the house. Of course, you may wish to put in a conventional switch somewhere so you could manually enable/disable the light fixture independent of X10 on/off control. You would probably want to install wall mounted controllers (see LEV:6319 series) instead of light switches at convenient places like entrances or stairways. The wiring for these wall mounted controllers is just like the wiring for a power outlet: two wires direct to the power supply. This is NOT the same as wiring for a conventional light switch. By changing the settings on the control modules and the wall mounted controllers you can link any switch to any light. Any light can be controlled in a three-way (or four-way, or more) manner just by adding more wall mounted controllers wherever convenient. A motion/sunup/sundown detector (e.g. X10:PR511) is a good addition to any house. You will probably want to wire this in a conventional circuit controlled by a conventional light switch. This way you can disable it (stop it from sending X10 signals) if you have to. Other things you could consider are dedicated outlets in convenient locations for Christmas lights (few house builders ever think of this). This will avoid running extension cords out the garage or off the outdoor light fixtures. With these controlled by X10, you could then have your X10:CP290 turn them on or off as required. In Canada and other occasionally frigid climates you might consider controlling the outlet for your block heater by X10, but watch that the power drawn by the heater doesn't exceed the capacity of the X10 receiver. You may wish to document clearly how you have wired the house in case you ever sell it. It may not be obvious to the next occupant, or to any electrician he hires to "fix" things. Don't forget telephone wiring. For the ultimate house, you'll want at least one unlisted telephone line for remote control of your house from a DTMF phone anywhere in the world. This will take a telephone interface such as X10:TR551 or LEV:6325. While this might see like an expensive luxury, think of what you could do by calling to turn off your fax machine, and turn on your computer so that you could call it (on a separate line) to transfer data. When done, you turn it off (or better, have it turn itself off by sending the proper command to its X10 interface) and turn on the fax machine again. Q113. How do I control fluorescent and halogen lights with X10? A113. Lamp modules and standard X10 wall switch (e.g. X10:WS467) generally do not work well anything other than incandescent lights. There are several reasons why this is so. Both lamp modules and wall switches cut out part of the power sine wave to dim the lights that are connected to them; the waveform available at the load is no longer a simple sine wave, but a sharply-truncated version of a sine wave. Even at full brightness, there is some power cut [Can anyone confirm this?]. This is not too critical for a simple incandescent light. For a compact fluorescent lamp that has some electronic circuitry in the base to drive it, however, this is not a good idea since the circuitry is designed around the expectation of a stable waveform at standard voltage. Trying to dim a compact fluorescent by modifying the input power supply is like trying to turn down the volume on your radio by putting it on a dimmer circuit. It may sort of work with unpredictable results, but cause damage to the load being dimmed. Standard lamp modules and appliance modules have full access to house current since they are plugged directly into a power outlet. Standard X10 wall switch modules, however, rely on getting their power from current leaking through the filament of the incandescent bulb(s) in the circuit they control even when the bulb is off. If the load they control is not a standard incandescent bulb, there may be no (or not enough) current to the switch and it may not operate as designed. This may be especially true for fluorescent bulbs, or special power saving bulbs that have diodes built into the base. As noted above, the voltage output from lamp modules and standard X10 wall switches is not a pure sine wave. Tranformers are generally designed for a certain frequency or range of frequencies (e.g. 50-60 Hz). They may not be able to handle the higher frequency harmonics present in the sharply truncated sine wave output from a lamp module or wall switch. As a result, they may heat up and/or burn out. This is true of halogen or fluorescent lamps that have an integrated transformer. It's true of any device with a transformer (e.g. some radios and computers) or with a motor (e.g. garage door opener or electric fan). A standard APPLIANCE MODULE (X10:AM486) may work for loads that are other than incandescent lights. Note that when used with a compact fluorescent bulb, the local control mode in the appliance module often senses a small current flow and keeps turning on. See Section 5 on defeating local control. Using an appliance module on a halogen light should work in most applications, but will not permit remote dimming. If the light has a built-in dimming control, this can still be used. There are special modules designed for fluorescent lights and other loads. Some of these may be in wall switch form but require a neutral power connection (not all existing wiring designed for a manual on/off switch have the neutral connection). Others (e.g. LEV:6375) wire directly into the light fixture and rely on control from some X10 transmitter (e.g. LEV:6319-4 series). Halogen flood lights work fine in MOTION DETECTOR (X10:PR511, LEV:6417). There has been some success reported in using the standard X10 inacandescent wall switch for controlling halogen lights that do not have a transformer in the light fixture. There are many types of halogen bulbs; mileage may vary. Use at own risk. Despite the information above and warnings on X10 lamp modules and wall switches that they be used only for incandescent loads, people persist in trying to use them for other loads. There are unconfirmed reports that doing so will cause the module/switch to catch fire (luckily this rarely happens more than once for a single installation). One should be very sure that one understands the full implication of going against the manufacturers' recommendations when directly connecting a device to the main power supply which will be left unattended in a valuable home. Q114. Can I use X10 in a three-way light switching application? A114. The way lights are normally wired is with a single on/off SPST switch. When the contacts are closed, the light is on; when open, the light is off: *on-------------- / | -----* | *(off) LIGHT | ------------------------ In a three-way switching application, a pair of SPDT switches (often at the top and bottom of stairs) are wired so that the light can be turned on or off from either switch. (This is sometimes called two-way switching.) Note that for three-way switching, neither the switches nor the wiring are the same as for normal on/off switching: *----------------* / -----* *--------- / | *----------------* LIGHT | ------------------------------------- In a situation where a light is already wired for three-way switching, X10 can easily be used. Install the WALL SWITCH 3-WAY KIT (X10:WS4777) -- see section 2 below. This contains one WALL SWITCH 3-WAY (master) and one WALL SWITCH 3-WAY REMOTE. Put the master in place of one switch and the remote in place of the other, wiring carefully as shown in the instructions that accompany the kit. Note that this is for incandescent lights only and not for appliances, motors or fluorescent lights. In fact, this will work where lights are already wired for four- or more- way switching as well. All you need is one additional WALL SWITCH 3-WAY REMOTE (available separately) to replace each additional SPDT conventional switch. If you are wiring a circuit with the intent of using X10 in a three-way (or more) light switching application, don't wire it as shown above. A much simpler and more flexible method is described in Q112. Q115. What is PLIX? PLIX stands for Power Line Interface to X-10. It is an 18 pin DIP ASIC which performs all the timing and decoding necessary to interface a PL-513 transmitter or a TW-523 transmitter/receiver to a microprocessor's TTL I/O port. In a nutshell, it does all the bit twiddling necessary to send and receive X-10 commands using a TW-523, simplifying the interface for home automation software. This allows even interpreted BASIC to send and receive commands to X-10 devices. The PLIX chip can send and receive one command at a time. It can receive and buffer one X-10 command "in the background" (i.e. without any attention from the host processor) but if a second command comes in before the first is read the earlier data is overwritten. The PLIX Evaluation Board kit (PLIX-EKit) is a PLIX chip, printed circuit board, and all required components. You must assemble it. By hanging a PLIX-EKit off the parallel printer port on your IBM PC and running the appropriate software, you can send and receive X-10 commands from your IBM PC. The PLIX chip also includes an AC Power Failure detect line, which on the PLIX-EKit is wired to generate an interrupt request to the host PC in the event of a power failure. As a minimum setup you would probably need a TW-523 interface and a "straight through" modular telephone cord, plus some kind of power supply (either a 9V battery or a simple power pack) and a case if you need it. The PLIX chip comes with some simple software in BASIC, and there is sample C code available via anonymous ftp from mrcnext.cso.uiuc.edu:/asre/plix.c Knowledge of BASIC, Pascal, or C would be more than sufficient to do your own programming. The PLIX chip and data sheet is $20 + shipping, and the EKit is $39 + shipping, both available from the MicroMint. Q116. Can I use X10 components outside? A116. From time to time you may wish to control loads outside your home with X10. Generally this should be a WALL OUTLET (X10:SR227, LEV:6227) or an APPLIANCE MODULE (X10:AM466). There are two considerations you must bear in mind in installing these. First, the X10 device must be protected from moisture. An appliance module should not put put outside; you might want to put it in your garage or garden shed (assuming you have power in these locations) and run an extension cord to the load out under the door. A more flexible approach would be to put an X10 wall outlet in an existing outside electrical box. This must be a weather proof box with tight cover. If you intend to leave something plugged into it for long periods of time, you will have to find or make some kind of cover that protects the X10 wall outlet from moisture. Second, the X10 device should be on a circuit protected a ground fault circuit interrupter (GFCI, sometimes known as GFI). These are special outlets that shut down very quickly when they detect some leakage current. These can put in serial with an appliance module (appliance module plugged into GFCI outlet), or in parallel (X10 wall outlet wired on load side of GFCI outlet) as shown below (North American wiring assumed): GFCI outlet house current _____ _____ ________________|* *|---------|* *| X10 appliance module (plugged into ________________| * |---------| * | GFCI outlet, protected from ________________| |---------| | elements) (line)|* *| ----- | * | ||+------------- ----- |+-------------- load (plugged into +--------------- appliance module) house current _____ _____ ________________|* *|___________|* *| ________________| * |___________| * | ________________| |___________| |---------- load (plugged into (line)|* *|(load) |* *|---------- X10 wall outlet) | * | | * |---------- ----- ----- GFCI X10 wall outlet outlet (in weather proof box) One final warning is about installing the X10 wall switch in an area where it will get cold. Apparently the triac in it doesn't work at low temperatures. For this reason, you should avoid even putting it in an outside wall. Q117. What are the various combinations of X10 wireless receivers and transmitters that work together? A117. WIRELESS TRANSMITTER (X10:RT504, LEV:6313, RS:61-2560) will work with WIRELESS RECEIVER (X10:RR501, LEV:6314) or WIRELESS RECEIVER (X10:TM751). To control 16 units, use two X10:RR501 (one set to 1-8, the other set to 9-16) or one X10:TM751. The surface mount two, three and four button WIRELESS TRANSMITTERS (X10:684, X10:724, X10:694 respectively) will work for all codes with WIRELESS RECEIVER (X10:TM751). When used with WIRELESS RECEIVER (X10:RR501, LEV:6314), respectively they will only work for units 1-2, 1-3, or 1-4 if the receiver is set for 1-8; or 9-10, 9-11, or 9-12 if the receiver is set for 9-16. The WIRELESS TRANSMITTER (X10:KC674) works for all codes with WIRELESS RECEIVER (X10:TM751). With the WIRELESS RECEIVER (X10:RR501, LEV:6314), it will only work for units 1-2 with the reciever set on 1-8. All the transmitters work with X10 security systems to some degree. Check before investing. You should not use the WIRELESS RECEIVER (X10:TM751 or X10:RR501, LEV:6314) if you have an X10 security system (their timing is slightly different and the signals they put on the power line will interfere with each other). You should not have two wireless receivers of any type in close proximity (e.g. in same AC power bar) to each other (their local oscillators may interfere with each other). The bottom line is that the WIRELESS RECEIVER (X10:TM751) is much more flexible than the WIRELESS RECEIVER (X10:RR501, LEV:6314) strictly for control purposes. If you already have an X10 security system, you should not need a separate wireless receiver. Q118. How do I make the motion detector floodlight unit work properly? A118. MOTION DETECTOR (X10:PR511, LEV:6417) is a useful device that functions as both X10 receiver and transmitter. It contains a sensor head to detect motion, an X10 receiver to turn on the attached floodlights, and an X10 transmitter to turn on up to four X10 units when motion is detected or four other X10 units at dusk and off again at dawn. It also has a shutoff control with a variable timer to turn the lights (and remote units) off after motion has stopped. It has a photocell control with variable sensitivity to determine when dusk and dawn occur. The most common problems with the motion detector can be solved by reading the short owner's manual that comes with it. This may seem obvious, but the answers to the most frequently asked questions are in fact in the manual. If the detector does in fact detect motion during daylight hour and you want it to do so only at night, you need to adjust the DUSK control. Note that each time you change this, the new value will not become effective for ten minutes, or one minute if you turn the power off and then on again. The floodlights on the detector be triggered on either by motion (turns off after a set time), or by darkness (turns off in the morning). This mode is set on the THIS UNIT switch, either SENSOR (for motion) or DUSK (for darkness). Halogen floodlights work fine with this device. Independent of the setting of the THIS UNIT switch, the detector can turn on and off up to four remote X10 units when it detects motion. These units are the four units that follow in numerical sequence from the unit number of the detector. Thus if the detector is UNIT 1, when motion is detected (sensitivity controlled by RANGE control), the detector will send X10 signals to turn any or all of (individually selectable) UNITs 2, 3, 4, and 5 ON for the same house code, and turn them OFF again after the selected time (controlled by TIME DELAY control) has elapsed. As a second example of the unit codes, if the detector is UNIT 14, then any or all of UNITs 15, 16, 1 and 2 for the same house code can be triggered for motion detection. To reiterate, the detector can detect motion and trigger up to four external devices even if the floodlights themselves are set to come on at dusk and go off at dawn. Independent of the setting of the THIS UNIT switch, and independent of any signals sent to remote units upon detection of motion, the detector can trigger up to four remote units on at dusk and off again at dawn. These remote units are the four units that are +5, +6, +7 and +8 from the unit number of the detector. Thus if the detector is UNIT 1, at dusk it will send X10 signals to turn any or all of (individually selectable) UNITs 6, 7, 8 and 9 ON for the same house code at dusk and OFF again at dawn, according to the sensitivity set on the DUSK control. As a second example of the unit codes, if the detector is UNIT 14, then an or all of UNITS 3, 4, 5, and 6 for the same house code can be triggered to be on only during hours of darkness. To reiterate, the detector can turn on up to four remote units during darkness even if the floodlights themselves are set to come on only when the detector detects motion. The external units triggered by motion cannot be the same as those triggered by dusk/dawn. Also if the DUSK control is adjusted to the minimum to detect motion even during the day, the detector will not be useable for switching lights on and off at sundown and sunup. In this case, the attached floodlights will come on during the day, either continuously if THIS UNIT is set to DUSK, or whenever motion is detected if set to SENSOR. One typical application would be to have the detector overlooking a back door or patio. At dusk, the detector would turn on the front exterior lights and some interior ones to make the empty house look lived-in. When the detector detects motion in the back yard, it would turn on the attached floodlights, other interior lights and a recording of vicious dog. These would go off after the set time. Late in the evening, some sort of X10 timer would turn off the lights that came on at dusk, to simulate the occupants going to bed. SECTION 2: INFORMATION ON X10 COMPONENTS ========================================== Manufacturers' numbers shown below are coded as follows: X10: X-10 Powerhouse LEV: Leviton Decora Electronic Controls RS: Radio Shack Plug 'N Power MINI-CONTROLLER (X10:MC460). Controls either units 1-4 or 5-8 (selectable) for any single house code. Functions: on, off, dim, all lights on, all off. Connects to standard wall outlet. MAXI-CONTROLLER (X10:SC503, LEV:6320). Controls units 1-16 for any single house code. Functions: on, off, dim, all lights on, all off. Connects to standard wall outlet. SUNDOWNER (X10:SD533). Same as MINI-CONTROLLER. Also will turn four units on at sundown and off at sunup as determined by internal photocell. Connects to standard wall outlet. MINI-TIMER (X10:MT522, RS:61-2670). Battery backed up clock, controls units 1-8 for any house code. Functions (daily cycle): on or off at exact time or approximate time. Manual control: off on, all lights on TELEPHONE INTERFACE (X10:TR551, RS:61-2692). Answers phone, controls 10 modules from commands on remote DTMF phone TELEPHONE TRANSPONDER (LEV:6325). Answers phone, controls all 256 possible units for commands on remote DTMF phone, three digit access code, confirms all commands with synthesized voice HOME CONTROL INTERFACE (X10:CP290, RS:61-2617). Battery backed up clock, seven day cycle, 128 events set by computer connected to RS-232 interface, any house code, any unit codes. Manual control: units 1-8 for the base house code set on the unit, on or off. Comes with software for any one of (not all) PC, Mac, Apple ][ or Commodore 64/128 and appropriate serial cable. Computer can be turned off or disconnected once the interface has been programmed and it continues on by itself. COMPUTER INTERFACE (X10:PL513). Send only computer interface module. COMPUTER INTERFACE (X10:TW523). Semi-intelligent computer interface to the power line, recommended for developers only. It plugs into an outlet and allows a computer or microcontroller to talk and listen directly to the X10 command codes on the AC line. It's roughly the size of a lamp module. See details in Q109. THERMOSTAT CONTROLLER (X10:TH2807). Attaches to appliance module. Small heater underneath any thermostat fools it into thinking house is warm and furnace need not be turned on. Good for use with automatic timer (e.g. MINI-TIMER or HOME CONTROL INTERFACE). WIRELESS TRANSMITTER (X10:RT504, LEV:6313, RS:61-2560). Controls units 1-8 or 9-16 for any house code by sending radio signals to a WIRELESS RECEIVER (X10:RR501, LEV:6314). WIRELESS TRANSMITTER (X10:KC674, RS:61-2565). Turns any two units on or off by sending radio signals to WIRELESS RECEIVER (X10:TM571 or RR501), keychain size WIRELESS TRANSMITTER (X10:RW684, RS:61-2562). Turns any two units on or off by sending radio signals to WIRELESS RECEIVER (X10:TM571 or RR501), surface mount WIRELESS TRANSMITTER (X10:RW694, RS:61-2664). Turns any four units on or off by sending radio signals to WIRELESS RECEIVER (X10:TM571 or RR501), surface mount WIRELESS TRANSMITTER (X10:RW724, RS:61-2563). Turns any three units on, off or dim by sending radio signals to WIRELESS RECEIVER (X10:TM571 or RR501), surface mount WALL MOUNTED CONTROLLER (LEV:6319-4). Turns any four consecutive units on or off. Push button switches. Wired into rectangular wall box. WALL MOUNTED CONTROLLER (LEV:6319-4D). Turns any three consecutive units on, off or dim. Push button switches. Wired into rectangular wall box. WALL MOUNTED CONTROLLER (LEV:6319-4A). Turns any three consecutive units on or off. Also provides ALL ON and ALL OFF commands. Push button switches. Wired into rectangular wall box. WALL MOUNTED CONTROLLER (LEV:6319-2). Turns any two consecutive units on or off. Push button switches. Wired into rectangular wall box. WALL MOUNTED CONTROLLER (LEV:6319-2D). Turns any unit on, off or dim. Push button switches. Wired into rectangular wall box. WALL MOUNTED CONTROLLER (LEV:6319-2D). Turns any unit on or off. Push button switches. Wired into rectangular wall box. WALL MOUNTED CONTROLLER (LEV:6319-1A). Provides ALL ON and ALL OFF commands. Push button switches. Wired into rectangular wall box. DRY CONTACT TRANSMITTER (LEV:6315). Transmits X10 ON and OFF signals to four consecutive units in response to make or break connections of dry contact sensors (e.g. photocells, external alarm systems). Wired into rectangular wall box. MOMENTARY DRY CONTACT TRANSMITTER (LEV:6316). Similar to DRY CONTRACT TRANSMITTER (LEV:6315) but triggers on momentary changes in the external dry contact sensors. WIRELESS RECEIVER (X10:RR501, LEV:6314, RS:61-2608). Receives X10 commands by radio signals from WIRELESS TRANSMITTER (X10:RT504, LEV:6313) and retransmits them into house wiring for any eight units. Also has integrated appliance module. WIRELESS RECEIVER (X10:TM751). Receives X10 commands by radio signals from WIRELESS TRANSMITTER and retransmits them into house wiring for any two units. Also has integrated appliance module. APPLIANCE MODULE (X10:AM486). Responds to any house code, any single unit. Turns load (15A, motors up to 1/3 HP, 500W for lights) either on or off. Two conductor APPLIANCE MODULE (X10:AM466). Same as APPLIANCE MODULE (X10:AM486), but three conductor FIXTURE RELAY MODULE (LEV:6375). This module does not plug into an outlet, but must be wired into the circuit. It switches a relay that handles 5A for incandescent or fluorescent lights. Responds to ON, OFF, ALL LIGHTS ON, and ALL OFF commands. DIMMING FIXTURE MODULE (LEV:6376). Similar to FIXTURE RELAY MODULE (LEV:6375) but has no relay and will dim up to 300W incandescent lights. Responds to DIM and BRIGHTEN commands as well as ON, OFF, ALL LIGHTS ON, and ALL OFF commands. LAMP MODULE(X10:LM465). Responds to any house code, any single unit. Turns incandescent light (300W max) on, off, or dim. Reportedly melts if connected to anything else. MOTION DETECTOR (X10:PR511, LEV:6417, RS:61-2604). At sundown, sends ON command for any up to four consecutive units and sends OFF again at sunup. Also only when dark, sends ON command to up to four other consecutive units when motion detected. Two floodlight sockets turned on/off for either sundown/sunup or when motion detected (selectable). Adjustable sensitivity for sunup/sundown and on/off time delay for motion. For outside use. Must be wired into round electrical box. POWER HORN (X10:PH508, RS:61-2613). This is a very loud (100dB) piezo electric device used as the audible indicator to scare away or deafen intruders. It sounds in response to X10 signals, usually generated by other components in a complete X10 alarm system. WALL SWITCH (X10:WS467). Replaces standard wall switch, wired into rectangular wall box. Manual toggle of on or off. May be locked in off position. SCREW IN LAMP MODULE (X10:SL575). Same function as lamp module (X10:465) but screws in between existing light fixture and bulb. Controls up to 150 watts. WALL SWITCH 3-WAY (X10:WS477). Same as standard WALL SWITCH, but for use with three way switch (on/off at two or more locations). WALL SWITCH 3-WAY REMOTE (part no?). Used with WALL SWITCH 3-WAY. For on/off at two or more locations, one must be WALL SWITCH 3-WAY, others must be WALL SWITCH 3-WAY REMOTE. One of these is included with WS4777, but they are also available separately. WALL SWITCH 3-WAY KIT (X10:WS4777). Kit of WALL SWITCH 3-WAY (X10:WS477) and WALL SWICH 3-WAY REMOTE. WALL OUTLET (X10:SR227, LEV:6227). Similar to APPLIANCE MODULE 15 A, 800W) but replaces standard wall outlet, wired into rectangular wall box. One outlet is X10 controlled; other is always on. WALL OUTLET DUPLEX (LEV:6280). Similar to WALL OUTLET, but each outlet is considered separate X10 unit, controlled separately. WALL OUTLET 220V, 15A (X10:HD243, RS:61-2668). Controls 220V appliances (e.g. water heater) up to 15 A, monophase or split two phase, standard North American wiring. WALL OUTLET 220V, 20A (X10:HD245, RS:61-2669). Same as WALL OUTLET 220V 15A but for up to 20 A. REMOTE CHIME (X10:SC546). Chimes when turned on. Selectable for any house code, any unit code. Could be used with MOTION DETECTOR to warn when someone is approaching. UNIVERSAL LOW VOLTAGE MODULE (X10:UM506, LEV:6337, RS:61-2688). Selectable for any house code, any unit code. Closes external circuit (selectable continuous or momentary) in response to X10 command. Has integrated REMOTE CHIME function. Plugs into standard wall outlet. For controlling sprinklers, curtain closers whose control signals are not 120V but rely on simple switch closing. THERMOSTAT SET BACK (X10:TH2807). Supplies a small amount of heat under conventional thermostat to fool into turning heating off. Plugs into an appliance module (e.g. X10:AM486) or an X10 wall outlet (e.g. X10:SR227, LEV:6227) SYSTEM AMPLIFIER (LEV:6201). Boosts signals on one phase and retransmits them on the other in North American 120/240V wiring system. Installed on its own 15A breaker at main electrical panel. Often required for large buildings over 5000 square feet (465 square metres). SIGNAL BRIDGE (LEV:6299). Couples signals from one phase to other in North American 120/240V wiring system. Installed on its own 15A breaker in rectangular wall box. Often required in medium sized buildings over 2000 square feet (185 square metres), or smaller where commands do not pass reliably. NOISE BLOCK (LEV:6282). Installed between incoming power line and main panel to keep extraneous electronic noise and signals from entering or leaving X10 network. Useful in apartments or attached homes sharing same transformer with others. 100A per phase. NOISE FILTER (LEV:6288). Looks like appliance module. Installed between power outlet and power cord of particularly noisy appliance that is interfering with X10 signals. SECTION 3: DETAILS ON X10 PROTOCOL ==================================== Note: This section applies to 60 Hz North American wiring. Relevance of this to European wiring is not known. Each ONE bit in a legitimate X10 transmission is a 1 millisecond (mS) pulse code modulated burst of 120KHz on the AC line, and each ZERO is the absence of that burst. The exact length of the burst may not be too critical in most applications. The burst is sent three times for each bit, once at each AC zero-crossing (accounting for zero-crossing in 3-phase). That means once each 2.778 mS. The next bit is sent on the following zero- crossing. This is done to get the quietest time on the AC line for the receiver, whatever phase of the AC it's on. The zero crossing gives the best signal-to-noise ratio for data transmission because everything should be shut down then (i.e. the voltage is low). . . . . . . . . . . . . . ._____________________________._____________________________.___________ ^ ^ ^ ^ . ^ ^ . ^ ^ 1 1 1 2 . 2 2 . 3 etc. . . . . . In addition, each bit is sent both true and complemented, and each code sequence is sent twice. That's a lot of bit redundancy, and just barely enough to make it past the noise on the line, depending on actual conditions. A single normal command takes eleven cycles of the AC line to finish. All legal commands must first start with the header 1110, a unique code as described below. The header bits take two cycles at one bit per half cycle. The next four cycles are the four-bit House Code, but it takes eight bits total because each bit is sent true then complemented. This is similar to biphase encoding, as the bit value changes state half-way through the transmission, and improves transmission reliability. The last five AC cycles are the Unit / Function Code, a five bit code that takes ten bits (again, true then complemented). For any codes except the DIM, BRIGHT and the data following the EXTENDED DATA function, there's a mandatory three cycle pause before sending another command DIM and BRIGHT don't necessarily need a pause, and the data after the EXTENDED DATA command absolutely MUST follow immediately until all bytes have been sent. The EXTENDED DATA code is handy, as any number of eight-bit bytes may follow. The data bytes must follow the true/complement rule, so will take eight cycles per byte, with no pause between bytes until complete. The only legal sequence that doesn't conform to the true/complement rule are the start bits 1110 that lead the whole thing off, likely because the modules need some way to tell when it's OK to start listening again. A full transmission containing everything looks like this (see the end of this section for the actual command codes): 1 1 1 0 H8 /H8 H4 /H4 H2 /H2 H1 /H1 D8 /D8 D4 /D4 D2 /D2 D1 /D1 F /F (start) (House code) (Unit/Function code) So, to turn on Unit 12 of House code A, send the following: 1 1 1 0 0 1 1 0 1 0 0 1 1 0 0 1 1 0 1 0 0 1 (House A, Unit 12) then wait at least three full AC cycles and send it again, then wait three and send: 1 1 1 0 0 1 1 0 1 0 0 1 0 1 0 1 1 0 0 1 1 0 (House A, Function ON) again wait three cycles and send it the last time. Total transmission would have been 264 discrete bits (don't forget the 3-phase) and would take 53 cycles of the AC line, or about .883 seconds. It's perfectly allowable to stack the Unit or Function codes together, so sending Unit 2 Unit 3 Unit 12 ON (separated by 3 cycles minimum) will turn on all 3 units. Stacking ON and OFF codes is annoying and flashes the lights quickly (roughly 4 Hz). X10 COMMAND CODES House Codes Unit/Function Codes H8 H4 H2 H1 D8 D4 D2 D1 F A 0 1 1 0 1 0 1 1 0 0 B 1 1 1 0 2 1 1 1 0 0 C 0 0 1 0 3 0 0 1 0 0 D 1 0 1 0 4 1 0 1 0 0 E 0 0 0 1 5 0 0 0 1 0 F 1 0 0 1 6 1 0 0 1 0 G 0 1 0 1 7 0 1 0 1 0 H 1 1 0 1 8 1 1 0 1 0 I 0 1 1 1 9 0 1 1 1 0 J 1 1 1 1 10 1 1 1 1 0 K 0 0 1 1 11 0 0 1 1 0 L 1 0 1 1 12 1 0 1 1 0 M 0 0 0 0 13 0 0 0 0 0 N 1 0 0 0 14 1 0 0 0 0 O 0 1 0 0 15 0 1 0 0 0 P 1 1 0 0 16 1 1 0 0 0 All Units Off 0 0 0 0 1 All Units On 0 0 0 1 1 On 0 0 1 0 1 Off 0 0 1 1 1 Dim 0 1 0 0 1 Bright 0 1 0 1 1 All Lights Off 0 1 1 0 1 Extended Code 0 1 1 1 1 Hail Request 1 0 0 0 1 Note 1 Hail Acknowledge 1 0 0 1 1 Pre-Set Dim 1 0 1 X 1 Note 2 Extended Data 1 1 0 0 1 Note 3 Status is On 1 1 0 1 1 Status is Off 1 1 1 0 1 Status request 1 1 1 1 1 Note 4 Note 1: Hail Request is transmitted to see if there are any other X10 compatible transmitters within listening range. Note 2: In a Pre-Set Dim function, the D1 bit represents the MSB of the level and the 4 House code bits represent the 4 least significant bits. No known X10 device responds to the Pre-Set Dim function. Note 3: The Extended Data code is followed by eight-bit bytes which can be any data you might want to send (like temperature). There must be no delay between the Extended Data code and the actual data bytes, and no delay between data bytes. Note 4: The X10 RF to AC Gateway model RR501 is a two-way module. If the RR501 is addressed by transmitting its House Code and Unit Code and then the STATUS REQUEST is transmitted, the RR501 will respond by transmitting Status ON if it's turned on, or Status OFF if it's off. RECOMMENDED SPECS TO ENSURE RELIABLE COMMUNICATION TO ALL X10 DEVICES: Carrier Oscillation Frequency 120KHz +/- 5% (s/b 2%, but 5% OK) Zero Crossing Detection 100uS +/- 100uS Width of Transmitted Carrier 1mS +/- 50uS Transmitter output power 60 mW average (5V pk-pk into 5 ohms) Isolation Voltage 2500V RMS. 60Hz for 1 min. Path: orca.sim.es.com!uunet!cs.utexas.edu!swrinde!ihnp4.ucsd.edu!library.ucla.edu! new ws.mic.ucla.edu!unixg.ubc.ca!quartz.ucs.ualberta.ca!news.sas.ab.ca!freenet.e dmo onton.ab.ca!tgreen From: tgreen@freenet.edmonton.ab.ca () Newsgroups: comp.home.automation Subject: X10 FAQ 2/2 Date: 8 Jan 1995 13:06:48 GMT Organization: Edmonton Freenet, Edmonton, Alberta, Canada Lines: 984 Message-ID: <3eoo18$mnr@news.sas.ab.ca> NNTP-Posting-Host: freenet.edmonton.ab.ca X-Newsreader: TIN [version 1.2 PL2E] SECTION 4: PROGRAMMING DETAILS FOR CP290 HOME CONTROL INTERFACE ================================================================ Reference: X10 CP290 Home Control Interface Programming Guide for Advanced Programmers The CP290 Home Control Interface communicates with the host computer via a simplified RS-232 interface. Serial communication takes place at 600 baud, eight data bits, no parity, and one stop bit. The reference recommends a pause of one millisecond between transmitted bytes, although in many applications this seems not to be required. This probably depends on the efficiency of the serial communications software used to send data to the interface. The serial connector on the CP290 is a five pin DIN connector. As seen from the back of the interface, the pinouts are as follows: 5 - no connection * * 1 - no connection 4 - data to computer * * 2 - data from computer * 3 - signal ground There are eight possible commands that the computer can send to the CP290. Each command starts with 16 hex FF bytes (each 0xff, or eight ones) for synchronization purposes. These are followed by the command code 0-7 and then a variable number of bytes as required by the syntax of each command. The interface requires a checksum of data bytes that follow the command code (see details for each command for exceptions) as the last byte in a command. The interface responds to each command with 6 hex FF bytes (each 0xFF, or eight ones) for synchronization purposes. This is followed by a status byte, and depending on the command, other information. The interface generates a checksum for all bytes following the status byte and sends it as the last byte in a reply to a command. COMMAND 0 - SET INTERFACE BASE HOUSE CODE The CP290 maintains a value called the base house code, which defaults to house code A on power up. This is equivalent to setting the house code on other X10 controllers; the eight buttons on the CP290 control units 1-8 on or off for the base house code. Note that setting the base house code with this command will clear all data in the interface. Command syntax (computer to interface): bytes 0-15: 1111 1111 - synchronization 16: 0000 0000 - command 0 17: HHHH 0000 - base house code to set where HHHH = 0000 - house code M 0001 E 0010 C 0011 K 0100 O 0101 G 0110 A 0111 I 1000 N 1001 F 1010 D 1011 L 1100 P 1101 H 1110 B 1111 J Return (interface to computer): bytes 0-5: 1111 1111- synchronization 6: 0000 000X - interface status where X = 0 - interface has lost all memory 1 - interface is OK COMMAND 1 - SEND DIRECT COMMAND It is possible to send X10 commands from the computer onto the power line via the CP290. This is not particularly fast. Command Syntax (computer to interface): bytes 0-15: 1111 1111 - synchronization 16: 0000 0001 - command 1 17: LLLL FFFF - dimming level and function 18: HHHH 0000 - house code for this command 19: UUUU UUUU - unit codes bitmapped 9-16 20: VVVV VVVV - unit codes bitmapped 1-8 21: CCCC CCCC - checksum where LLLL = 1111 - dimmest (not quite full off) ... - intermediate brightness values 0000 - brightest (not quite full on) FFFF = 0000 - units off (*) 0001 - lights on, not appliances (*) 0010 - turn on 0011 - turn off 0100 - if light off, turn on full; in any case, dim to full off. Responds as 0011 (*) 0101 - if light off, turn on full; else brighten to full; then dim LLLL (LLLL+1?) steps. Responds as 0100. 0110 - if light off, turn on full; else brighten by LLLL+1 steps. Responds as 0101. (*) 0111 - no obvious effect. Responds as 0110. 1000 - no obvious effect. 1001 - no obvious effect. 1010 - no obvious effect. 1011 - no obvious effect. 1100 - no obvious effect. Responds as 1011. 1101 - no obvious effect. Responds as 1100. 1110 - no obvious effect. Responds as 1101. 1111 - no obvious effect. Responds as 1110. where (*) indicates behavior undocumented in the reference HHHH - as for Command 0 UUUU UUUU - units bitmapped as 9 10 11 12 13 14 15 16 VVVV VVVV - units bitmapped as 1 2 3 4 5 6 7 8 CCCC CCCC - sum of bytes 17-20 Return (interface to computer): bytes 0-5: 1111 1111 - synchronization 6: 0000 000X - interface status (pause while X10 command is sent onto power line) 7-12: 1111 1111 - synchronization 13: 0000 000X - interface status 14: HHHH FFFF - house code and function 15: UUUU UUUU - unit codes bitmapped 9-16 16: VVVV VVVV - unit codes bitmapped 1-8 17: HHHH 0000 - base house code 18: CCCC CCCC - sum of bytes 14-17 where all values are as explained above; response function codes are same as command function codes except as noted COMMAND 2: SET INTERFACE CLOCK This command sets the internal clock in the CP290. Command syntax (computer to interface): bytes 0-15: 1111 1111 - synchronization 16: 0000 0010 - command 2 17: 00mm mmmm - minutes 0-59 18: 000h hhhh - hours 0-23 19: 0ddd dddd - bitmapped day of week Sun - Mon 20: CCCC CCCC - sum of bytes 17-19 where ddd dddd is day of week bitmapped as Sun Sat Fri Thu Wed Tue Mon Return (interface to computer): bytes 0-5: 1111 1111 - synchronization 6: 0000 000X - interface status COMMAND 3a: SEND TIMER EVENT TO INTERFACE This command sends a timer event to the interface. The computer can then be disconnected and the event will be sent over the power line as X10 commands at the appropriate time. Events are stored eight bytes per event in locations 0-1023 in the 2K RAM inside the interface. Command syntax (computer to interface): bytes 0-15: 1111 1111 - synchronization 16: 0000 0011 - command 3 17: AAAA AAAA - LSB of event address 18: 0000 00AA - MSB of event address 19: NNNN MMMM - mode 20: 0ddd dddd - bitmapped days Sun - Mon 21: 000h hhhh - hour 0-23 22: 00mm mmmm - minute 0-59 23: VVVV VVVV - bitmapped unit codes 1-8 24: UUUU UUUU - bitmapped unit codes 9-16 25: HHHH 0000 - house code for this event 26: LLLL FFFF - level and function 27: CCCC CCCC - sum of bytes 19-26 where 0000 00AA AAAA AAAA (bytes 18 and 17) = 0000 0000 0000 0000 for event 0 0000 0000 0000 0100 for event 1 0000 0000 0000 1000 for event 2 .... (increases by 8 for each event) 0011 1111 1111 1100 for event 127 MMMM = 0000 - clear 0001 - ? 0010 - tomorrow only then clear 0011 - ? 0100 - today only then clear 0101 - ? 0110 - ? 0111 - ? 1000 - at exact time 1001 - at approximate time 1010 - ? 1011 - ? 1100 - ? 1101 - ? 1110 - ? 1111 - ? NNNN = MMMM - program event NNNN = MMMM = 0000 - clear event NNNN not = 0000; MMMM = 0000 - store event but put it on hold (will not take place) Actually, setting for NNNN and MMMM is a bit vague. The reference indicates that NNNN = 0 and MMMM is function code as shown above. The software provided with the CP290 uses NNNN = MMMM except when "freezing" an event (deactiving it, but not erasing it). Frozen events also have UUUU UUUU = VVVV VVVV = 0. It's not clear how a frozen event knows what units it is to control. Not clearing the unit mask confuses the standard CP290 software... Return (interface to computer): bytes 0-5: 1111 1111 - synchronization 6: 0000 000X - interface status COMMAND 3b: SEND "GRAPHICS DATA" TO INTERFACE In the 2K RAM of the interface, locations 1024 through 1535 are accessible from the external computer, but are not used for events or any other purpose by the interface. In the CP290 these are referred to as the locations for graphics data. For each of 256 possible units, the memory locations could be used to indicate (under control of an external program) the on/off condition of a unit, or the type of unit it is (possibly an index to a graphics icon). This command writes data from the computer two bytes at a time to these memory locations in the interface. Command syntax (computer to interface): bytes 0-15: 1111 1111 - synchronization 16: 0000 0011 - command 3 17: AAAA AAA0 - LSB of data address 18: 0000 0AAA - MSB of data address 19: GGGG GGGG - data byte 0 20: GGGG GGGG - data byte 1 21: CCCC CCCC - sum of bytes 19 and 20 where 0000 0AAA AAAA AAAA(bytes 18 and 17) = 0000 0100 0000 0000 for data pair 0 0000 0100 0000 0010 for data pair 1 ... (increases by 2 for each subsequent data pair) GGGG GGGG - can be anything relevant to the external program, since this data is not used by the interface Return (interface to computer): bytes 0-5: 1111 1111 - synchronization 6: 0000 000X - interface status COMMAND 4: GET CLOCK TIME AND BASE HOUSE CODE FROM INTERFACE This command reads the time from the internal interface clock and also gets the current base house code. It is an innocuous way of testing for the presence of the interface, and to see if it has lost its memory since the last time events were downloaded to it. If there is no reply to this command after several seconds, the computer could assume that the interface was not (properly) connected. Command syntax (computer to interface): bytes 0-15: 1111 1111 - synchronization 16: 0000 0100 - command 4 Return (interface to computer): bytes 0-5: 1111 1111 6: 0000 000X - interface status 7: 00mm mmmm - minute (0-59) 8: 000h hhhh - hour (0-23) 9: 0ddd dddd - bitmapped days Sun - Mon 10: HHHH 0000 - base house code 11: CCCC CCCC - sum of bytes 7-10 COMMAND 5: GET TIMER EVENTS FROM INTERFACE This command requests the interface to send to the computer the events that it has stored in its memory. Command syntax (computer to interface): bytes 0-15: 1111 1111 - synchronization 16: 0000 0101 - command 5 Return (interface to computer): bytes 0-5: 1111 1111 6: 0000 000X - interface status for( event = 0 ; event < 128 ; event = event+1 ) { if( event is not erased ) { 7: NNNN MMMM - mode 8: 0ddd dddd - bitmapped days Sun - Mon 9: 000h hhhh - hour 0-23 10: 00mm mmmm - minute 0-59 11: VVVV VVVV - bitmapped unit codes 1-8 12: UUUU UUUU - bitmapped unit codes 9-16 13: HHHH 0000 - house code for this event 14: LLLL FFFF - level and function } else 7: 1111 1111 - indicates event in that location is erased } last byte: CCCC CCCC - sum of all bytes for valid events starting with byte 7; does not include the 1111 1111 for locations where event has been erased COMMAND 6: GET "GRAPHICS DATA" FROM INTERFACE This command requests the interface to send the "graphics data" that it has stored in its memory. See COMMAND 3b above. Graphics data is not used in any way by the interface. Command syntax (computer to interface): bytes 0-15: 1111 1111 - synchronization 16: 0000 0110 - command 6 Return (interface to computer): bytes 0-5: 1111 1111 6: 0000 000X- status for( unit = 0 ; unit < 256 ; unit = unit+1 ) { if( graphics data for unit has been stored ) { 7: GGGG GGGG 8: GGGG GGGG } else 7: 1111 1111 } last byte: CCCC CCCC - sum of all data pairs for all units starting with byte 7; excludes the single 1111 1111s in cases where data for that unit has not been stored COMMAND 7: DIAGNOSTIC This command tells the interface to run a self-check on its hardware and firmware. Pin 4 on the interface goes low for 10 seconds; this may generate extraneous characters that are detected by the attached computer. At the end of this time, the interface sends its status if it can. Note that this command will scramble or clear any data stored in the interface. Command syntax (computer to interface): bytes 0-15: 1111 1111 16: 0000 0111 - command 7 Return (interface to computer): bytes ?: extraneous characters for 10 seconds 0-5: 1111 1111 - synchronization 6: 0000 000T - test status where 0000 000T = 0 - interface is OK 1 - interface has a fault KEYBOARD COMMANDS If X10 commands are sent using the keys on the top of the CP290, the interface will send a report to the computer so it can keep track of the status of units. Report (interface to computer): 0-5: 1111 1111 - synchronization 6: 0000 000X - interface status 7: HHHH FFFF - house code and function 8: UUUU UUUU - unit codes bitmapped 9-16 9: VVVV VVVV - unit codes bitmapped 1-8 10: HHHH 0000 - base house code 11: CCCC CCCC - sum of bytes 14-17 where FFFF is the function return code described for Command 1 (SEND COMMAND DIRECT) TIMED EVENTS When the CP-290 sends X10 commands in accordance with an event programmed into it, it will send a report to the computer so the computer can keep track of the status of units. This report is in the same format as the report for keyboard commands described above. SECTION 5: MODIFICATIONS TO X10 HARDWARE ========================================= WARNING: Modifying X10 hardware as described in this section will void the warranty of the hardware. Any modifications you do are at your own risk and the results are entirely your own responsibility. You may end up damaging the hardware beyond use. Remember, X10 devices are connected directly to the power line, and can kill you. If you feel uncomfortable about any of this, don't do it. The modifications in this section have been tried by one or more people. They may not work for you, due to variation in technical skill, or variation in X10 equipment lots. Again, you are on your own; use at your own risk! Q501. How do I modify appliance modules for momentary operation? A501. Normally appliance modules turn on and stay on in response to an ON command, and off in response to an OFF command. In response to an ON command appliance modules modified as described in this section will pulse on then off twice, returning to the off position. Procedure: 1. Make sure module is off, unplug it and then take cover off. 2. Locate 330K resistor below the IC chip. Remove it. 3. Reassemble and test the module. The module clicks twice because each X10 command is issued twice. Thus the two commands causes two on/off cycles. If you would like the module to be normally on, make sure that the module was left on before you start the mod. Q502. How do I add local dimming capability to wall switch modules? A502. There are X10 wall switches with local dimming capability, but these are not as widely available and reasonably priced as the X-10 WS467. This switch has a local on/off toggle and a slide button to lock it off. The light it controls can be dimmed only from a remote X10 transmitter. The difference in circuitry between the switches with and without local dimming capability is minor. Those with local dimming capability have a jumper wire where those without local dimming have a resistor and capacitor. To convert a switch without local dimming to one with local dimming, you will need to remove the resistor and capacitor and replace them with a wire. You will need a jeweler's flat-blade screwdriver, a soldering iron, and a desoldering bulb or solder-up wick. You may find needle nose pliers to be helpful as well. Procedure: 1. Make sure the switch is functioning properly before starting. 2. Take the module apart all the way. Using the screwdriver, press down on the tabs at the four corners of the back cover, and pop the cover off. Be careful not to break the tabs. Remove the circuit board from the case by prying the side of the case away from the side of the board with the screwdriver far enough so that the PCB can clear the tabs which hold it in place. As the PCB comes out, be careful not to lose the small metal tab or the tiny spring-loaded rod which form part of the cutoff switch. Also remove the plastic piece which holds the cutoff switch assembly in place; removing the switch assembly now will make it easier to reassemble the switch properly later. The following is a crude ASCII diagram of the component side of the WS467 PC board, showing relative locations of various components. |---------------------------------| | | TRIAC | | / | | / | | / Notes: The WS467 has a small | | / 1/4 watt resistor soldered | | / between holes 1 and 2, as | |---------------| | / well as an electrolytic | | I C | |-| |/ capacitor soldered between | |---------------| o 1 | |/| holes 3 and 4. Remove these | 2 o |-| | components and solder a | o | jumper wire between holes | 3 o | 1 and 3 to restore local | 4 | dimming. | | | | | | | | | (Other circuitry omitted | | for clarity.) | | | |---------------------------------| WS467 PC Board Component Side 3. Once the switch has been disassembled and the PCB removed from the case, examine the component side of the board closely while referring to figure 1. Locate the small electrolytic capacitor and 1/4 watt resistor located just below and to the right of the IC on the board. They share a common connection. Note that there is probably a larger 1/2 watt resistor in close proximity to the correct one - make sure you pick the right resistor. Now flip the board over and locate the 4 pads to which these two components are soldered. After warming up your soldering iron, use the solder wick or desoldering bulb to remove the solder from those pads, and remove the components from the board. NOTE: you could also simply cut the components off the board, leaving the lead stubs soldered in place, but desoldering the components will result in a much neater job. 4. Again referring to the diagram in figure 1, install a small jumper wire between holes 1 and 3. Solder the wire to the pads on the foil side of the PCB. 5. Reassemble the case, pop the circuit board back in, and pop the back cover on. Turn the switch over and look closely into the hole where the cutoff switch assembly fits. There you will see a pair of small metal protrusions as well as a shorter metal contact area. Replace the small metal tab into its position between the two taller metal protrusions, positioned so that the other end of the metal tab can contact the shorter metal contact area. Pop the cutoff switch assembly back into place, making sure that neither the tiny spring-loaded rod nor the metal tab fall out while you do so. 6. Install the switch in the wall, and test normal operations (local on/off control, remote on/off/dim control, and the function of the cutoff switch). 7. Finally, test the local dimming function: Press and hold the button on the switch. The light will come on, and then slowly cycle through a bright-to-dim-to-bright sequence. Release the button when the desired level of lighting is achieved. A quick tap on the button will turn the light on and off. Q503. How do I modify the maxi-controller to accommodate more than 16 units? A503. The maxi-controller controls 16 units on a single house code. For those of applications with more than 16 units (and the thoughts of grouping units together or glueing a dime to the house code select slot aren't that appealing), a maxi controller can be made to control an alternate house code with the addition of a momentary contact pushbutton. The following procedure modifies the maxi-controller to use house code I normally and control house code K with the push of a button. Procedure: 1. Open the maxi-controller. There is no need to remove the circuit board. 2. Install a miniature normally open momentary contact push button switch (e.g. RS 275-1571A) in a hole *carefully* drilled in the back of the top piece of the case so the switch will stick out the back when all is done). Avoid the components and the mounting post. Position it roughly behind the red LED on the Powerhouse brand of the maxi. Another way to describe its location: If you have the standard label 1-16 in position, the button goes behind approximately 12 (maybe a bit towards 11). 3. Using a short jumper wire, solder one post of the switch to pin 7 of the IC (GI 8417) and the other lead to pin 10. Use as little heat on the IC pins as possible to get a good solder without destroying it. 4. Reassemble making sure nothing is shorting (jumper leads, etc.). 5. Set house code rotary to position I and test units on house code I. To operate house code K, push in pushbutton and hold it while selecting the unit(s) and the operation (on,off,dim,bright,all lights on, or all units off). Note that the pins 7 to 10 mod will also allow you to control house codes J/L, H/F, G/E, B/D, A/C, P/N, or O/M by changing the rotary switch. Untried variations: Using the chart below, you could connect via pushbutton pins 7 and either 8, 9, 10, or 11 alternatively or more than one if necessary to produce a desired combination. If you absolutely had to produce a house code alternative where you need to turn a 1 into 0 instead, you could use a normally closed pushbutton and cut a trace. Maxi controller with GI 8417 IC (can jumper a "1" from pin 7) PIN 8 9 10 11 --- -- -- -- -- J 0 0 0 0 I 0 0 0 1 L 0 0 1 0 K 0 0 1 1 H 0 1 0 0 G 0 1 0 1 F 0 1 1 0 E 0 1 1 1 B 1 0 0 0 A 1 0 0 1 D 1 0 1 0 C 1 0 1 1 P 1 1 0 0 O 1 1 0 1 N 1 1 1 0 M 1 1 1 1 Q504. How do I modify the mini-controller to control more units? A504. This answer should be read in conjunction with the instructions for modifying the maxi-controller in Q503. Unfortunately, the truth table for the mini-controller appears to be all different for that for the maxi-controller, and there isn't a real good place to mount the pushbutton. Besides, if you really need to control a bunch of units, you wouldn't have the mini-controller in the first place. However, the following seems to apply: Mini controller with 8925 IC (can jumper a "1" from pin 3) PIN 5 6 7 8 --- -- -- -- -- M 0 0 0 0 O 0 0 0 1 E 0 0 1 0 G 0 0 1 1 C 0 1 0 0 A 0 1 0 1 K 0 1 1 0 I 0 1 1 1 N 1 0 0 0 P 1 0 0 1 F 1 0 1 0 H 1 0 1 1 D 1 1 0 0 B 1 1 0 1 L 1 1 1 0 J 1 1 1 1 Q505. How do I modify the mini-controller to control all units for a single housecode (i.e. all "bands")? A505. The X10 mini controller is capable of addressing four of the sixteen X10 unit codes. A slide switch on the controller allows the user to select the "band" of units 1-4 or 5-8. A simple modification allows the selection of two additional bands, 9-12 and 13-16. This covers the entire spectrum of X10 units accessible from a single house-code. This modification applies to the "Radio Shack" branded mini controller, number 61-2677B. By visual inspection of the circuit board and internal components, it appears that this modification also applies to "Stanley" branded mini controller number 360-3090. It appears that both of these units were manufactured for X10 for sale under the distributers' own brand name, and are essentially identical inside. There was an earlier model of the mini controller that was available from Radio Shack, and possibly other sources. Legend has it that the old unit was even easier to modify for access to all four bands. In fact, one legend says that the unit was equipped with a four-band switch, two positions of which were simply blocked off by the plastic bezel sticker applied over the plastic cabinet. I don't know what the truth is, not having one of the old mini controllers to study. What I do know is that this modification was not developed for the old controller. The old mini controller had four switches for the unit codes, plus individual switches for ON, OFF, DIM, BRIGHT, ALL LIGHTS ON, and ALL UNITS OFF. To turn on unit three, one would depress two switches: 3 and ON. The new mini controller does not have ON and OFF switches apart from the unit codes. Instead it has an ON and OFF switch for each of the four unit codes. (In the case of the Radio Shack unit, there are four rocker switches, up for ON and down for OFF. The Stanley unit has individual switches for 1 ON, 1 OFF, 2 ON, 2 OFF, etc.) Pressing one of these switches sends both the unit code and the ON or OFF command. The user can then follow up by using the DIM or BRIGHT switches, or the ALL LIGHTS ON or ALL UNITS OFF switches. Procedure: 1. Unplug the unit and open the case by removing the four phillips-head screws. Put both halves of the case in a safe place. When handling the printed circuit board, orbserve the usual precautions for static-sensitive devices. 2. Locate the place where the existing "band" switch is located. This is nothing more than a plastic handle on a metal slider that runs in a trough molded into the top part of the case. The slider makes contact with three large pads on the printed circuit board. 3.The hardest part of the modification is finding a new switch to use for the four-position band selector! It is possible to use a two-pole four-throw rotary switch. I'll let you figure out how to do the encoding if you decide on that. I found a suitable switch in my junk-box and mounted it in a position that replaces the old band switch. This entailed some amount of cutting and gluing on the plastic case. I will assume that you are doing the same. Find a small slide switch that has four positions. It should have two rows of five contacts. As the switch is moved, it should short two adjacent contacts at a time. Looking into the pins in the back of the switch, one should see the following connection pattern for each switch position: position 1 position 2 position 3 position 4 +-------------+ +-------------+ +-------------+ +-------------+ |1--2 3 4 5| |1 2--3 4 5| |1 2 3--4 5| |1 2 3 4--5| | | | | | | | | |A--B C D E| |A B--C D E| |A B C--D E| |A B C D--E| +-------------+ +-------------+ +-------------+ +-------------+ Physically, the switch should fit in pleasingly with the rest of the panel. This usually means that it should be rather small. This is a good time to decide exactly where to put it. The most logical place is directly in place of the existing band switch. This may require hacking away part of the printed circuit board. 5. Orient the printed circuit board in front of you, such that the foil side is down, and the power cord attaches to the board on your left. The big chip should be slightly right of center, and most of the components will be near your belly. Make sure that the chip has 24 pins, and is marked 78567. To your right of the chip is a small metal-can transformer. Further right and up, should be an electrolytic capacitor, around 1000 mFd at 25 V. The capacitor's negative lead is well marked. Locate the positive lead. 6. If the new switch does not physically replace the old one, disable the old switch by removing the slider from it. 7. Looking into the back of the switch, wire pin A to 4 to IC pin 11. Wire switch pin B to 3 to D to the + lead of the capacitor. Wire switch pin C to IC pin 12. The result should look something like this: .------------. | | | +---------|---+ | |1 2 _3_ 4 5| | | / \ | |---A B C D E| | +------|--|---+ | | | | | `-----> to capacitor + | `--------> to IC, pin 12 `------------------> to IC, pin 11 The intent of this circuit is to impress one of four binary codes on the IC's pins 11 and 12. This tells the controller chip which band of X10 units to address. The logic levels to be presented to the chip are provided by dead air and the + lead of the electrolytic capacitor. The truth table is: unit switch switch | pin 11 pin 12 band position shorting | sees sees ----- -------- -------- -+- ------ ----- 1-4 1 1&2, A&B | cap air 5-8 2 2&3, B&C | air cap 9-12 3 3&4, C&D | cap cap 13-15 4 4&5, D&E | air air 7a. Rotary switch option. This version is untested, but should work. It is for rotary switch lovers out there. Get a 2-pole 4-throw rotary switch and wire it as follows: .------------------------------> to capacitor + | | | | 1_ 2 3 4 1_ 2 3 4 |\ |\ \- - - - - - - - -\ \ \ O O | | | `--------> to IC, pin 12 `--------------------------> to IC, pin 11 You probably want to avoid binary or BCD-encoded thumbwheel switches because the base station coding scheme is offset slightly from normal binary coding (and the switch output). You would have to relabel the switch positions, not to mention blocking off the unused positions. 8. Put the box back together. Screw it shut again before applying power. Try it out. (dennisg@filenet.com) Q506. How do I modify the mini-controller to control only units 9-12 or 13-16? A506. Read in conjunction with Q505. Proecedure: 1. Open mini-controller and pull back the circuit board. Be careful not to let all the switch tops fall out. 2. Locate the three pads underneath the slide switch. Notice that the unmodified mini selects 1-4 or 5-8 depending on whether the center position makes connection with one side or the other. 3. To modify the mini to control only units 9-12, solder a jumper such that all three pads connect together. 4. To modify the mini to control units 13-16, simply remove the slide switch. Untried variation #1: If you solder the jumper as to not interfere with the slide switch, then you could jumper just one side and then use the slide to select 1-4 or 9-12 or .. jumpering the other side, 5-8 or 9-12. Untried variation #2: If you mangle the slide switch so that it only has the contacts on one side or the other, you could use the slide switch to select 1-4 or 13-16, or .. removing the other side 5-8 or 13-16. A possible problem here is that the half-mangled slide switch may not "sit right". Q507. How do I modify the mini-controller for momentary operation? A507. The following answer comes from oadebc@robots.gsfc.nasa.gov: Description: When a Mini-Controller is modified as below, your key presses are undone as soon as you release the key. Thus pressing 'on' and then releasing, sends an 'ON' and then a 'OFF' command. This is also true for 'All Unit' commands. This mod only works on model 'MC460' Mini-Controllers, and not the 'MC260' (If anyone knows how to identify the two, please post). Procedure: Inside the mini controller, connect pin 3 and 14 of the black IC marked 78567. You may want to make the connection with a little switch to return the controller to normal mode. Q508. How do I repair a "blown" X10 lamp module? A508. X10 lamp modules have a bad habit of dying premature deaths. Most of the time, the problem can be traced back to a bad triac. Why the triac is the weak link has been debated hotly. It is possible to "resurrect" the module by simply replacing the triac. Caution must be stressed here; there are a lot of triacs available, but whichever one you use must have an isolated tab. The most universally available replacement is from Radio Shack, part number 276-1000 [Does this part actually have an isolated tab?], or Digi-Key part number L4008L6-ND. In addition to having an isolated tab, it also has a higher rating than the original one, so will be less likely to fail. If you don't know a triac from a mouse trap, you'd better not try to replace it. Q509. How do I defeat local control of lights and appliances? A509. A standard appliance or lamp module will turn itself on if the power switch on the device it is connected to is switched on. This provides local control. This is not always desirable, however. Local control depends on the current draw through the module; if it exceeds a certain value, the device turns on. Some devices (compact fluorescent lamps, for example) seem to have low impedance and keep switching themselves on even when explicitly turned off. This local control can be disabled for appliance modules. Procedure: Inside each module, there is an integrated circuit labeled "PICO- 570" or "PICO-536C" Cut the lead that goes from pin 7 of this integrated circuit to the hot AC connection. Q510. How do I add a relay output to the power horn? A510. The following answer comes from oadebc@robots.gsfc.nasa.gov: Description: I have always wanted to add a relay output to the power horn. With this feature, I can switch on a more powerful outside bell, an autodialer, or any other load upon detection of a violation. When I opened the case, I was surprised to learn that unit was already designed to do just that, except the necessary components have been left out. There even are two holes in the back of the unit for screw terminals that are covered by a small sticker. After tracing the circuit, I selected some replacements listed below. Procedure: The procedure requires the installation of eight components that should be commonly available. Open the case by removing the four screws in the back. On the PC board you will see near the bottom (side away from the AC plug) the silk screening for the relay output portion. Install the following components (all resistors 1/4 watt with exceptions): R30 - 1Kohm (1/2Watt) R32 - 12Kohm R33 - 12Kohm R34 - 200Kohm R35 - 200Kohm D16 - Any Silicon Diode (not Zener) RL1 - Your relay (see note below) TR8 - 2N2222 Switching Transistor For the screw terminals, you can use a set taken from an unused (X-10) alarm sender, or you can decide on your own interface. The relay could be tricky. I was lucky and was able to find a relay that fit after some modifications. It does appear to me however that Radio Shack sells micro relays that would fit. Operation: The relay will close as soon as the horn starts blaring (and vise versa). Your current rating will certainly depend on the relay you choose. If you are so inclined, you could even disconnect the piezo horns, and have a unit that silently turns on a load upon an alarm violation. Changing the reaction time of the Horn: After some poking around I found out specifically how the Horn is triggered. A capacitor is charged a small amount every time an ALL UNITS OFF command is received after an ALL UNITS ON command. When this voltage reaches 7.0 Volts, the Horn starts a-blarin'. This usually takes 20 seconds after the alarm system is triggered, an amount that I think is just too long. The capacitor that determines the reaction time is C13, located near pin 18 of the 78566 chip. The 'stock' value of this capacitor is 22uF, and it takes five transitions of the command to trigger the horn. By using a 10uF capacitor this amount is reduced to only two needed transitions. Summary: Standard Horn (22uF) trigger time is 20 seconds. Modified Horn (10uF) 8 seconds. The quick reaction time will hopefully cause the intruder to stop his break in attempt sooner. Effects of Combining the two Mods: If you want the load that is switched by the relay be flashed on and off, you can combine the two modifications. The on to off duty cycle can be changed by changing C13. Actually what I have done is to socket C13, so that I can open the case and easily change the reaction time of the horn. Conclusion: I (oadebc@robots.gsfc.nasa.gov) am curious to know if anyone finds this mod useful. Please let me know any questions or comments. Have fun, and I will trust that you will not hold me responsible for your failures (only for your successes 8-). Harrison Cooper Sr. Hardware Engineer Evans & Sutherland Computer Corp www.es.com