please dont rip this site

io serial x10 x10

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<return>, where NN is the X10

             ;command.  Example 'Et' is Housecode E and Keycode ON.

             ;Response is CX_NN<return>, 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<ret>

  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
 
</FAQ CHANGES>
 
<FAQ OUTLINE>
 
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? 
 
</FAQ OUTLINE>
 
<FAQ BODY>
 
<FAQ SECTION 1>
 
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)
 Hel