|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
X-10 Household Automation on AVRProject
In the early 1980s, I started dabbling with household automation. I purchased Plug-n-Power Controllers and consoles from Radio Shack. They also offered an interface that connected to the TRS-80 Model 1 Cassette Interface. This allowed me to delve into the Machine Language aspect of this technology (Z-80 machine language, though). The interface was primitive, but the code only needed written once. I had the Model 1 on a timer, it woke up in the morning. It loaded the time and date, looked up my schedule to see if it was a weekend, holiday, or day off (entered in a file). It either shut itself off, or woke me up using a variety of methods like flashing the lights and swearing at me through the voice synthesizer. That was 1984. I had a lot of time on my hands back then. I'm amazed the technology didn't die. I'm sure some school with dozen young kids would've burnt down, get blamed on an X-10 malfunction, and spell liability doom for this technology forever more. It didn't happen. Radio Shack still sells the modules after 23 years. They're also available from many other sources. X-10 communicates with RF pulses through the power line. These pulses occur on the trailing edges of the AC sine wave peaks within a small timing window (lowest power consumption on linear supplies). The code is not 'bullet proof' as appliances such as drills, circular saws, and washing machines can send errant codes through the line when mechanical switches bounce and arc. Early unfiltered switching power supplies were also a serious signal problem back in the early 90s. Furthermore, I have a whole pile of blown modules and control consoles evident from 23 years of constant use. Recently I encountered an X-10 Powerhouse two way Power Line Interface (Model TW523) on Ebay. I purchased 2 (just in case my messing around fries one) . To my dismay, I found the technology almost unimproved. With only ancient knowledge and no documentation, I examined and reverse engineered, finding the pinout below. 1 - Yellow - pulled up with 10K ohm is 60 HZ 2 - Green is Common GND 3 - Red - pulled up with 10K ohm is Signal In 4 - Black - Jams controller when pulled up with 1K ohm à Signal Output These signal-input pulses are 1.1mS to 1.2mS in width (1.146 to be exact). The pulses are roughly synchronized to the moment of change of the 60hz output signal. This TW523 module conveniently does the RF part and Opto-Isolates the inputs and outputs for us. Our AVRProject will be safe. We need 10K pull-ups to 5V on pins 1 and 3 to look at the data. I didn't believe the internal AVR pull-ups are strong enough to pull up the opto-isolators (50K ohm) so I didn't try it. Common GND is on pin 2. A look at the logic analyzer of the 60hz clock and the Signal In lines shows the 60hz square wave. Hitting a button on a separate X-10 controller pad shows the pulses being pulled low for the 1.146mS length of time. I'm calling this pulse a '1'. Absence of a pulse would be called a '0'.
-The data pulse train, synchronized at 60hz (rising or falling) always starts with '1 1 1 0' pulse pattern. This is true for all commands, selects, and house codes. -After this 'Start' signal, 8 bits of data is shifted out, MSB first, synchronized data bits are '1 0' pulse pattern for a logic 1, and '0 1' pulse pattern for a logic 0. The 8 bits is actually a 4 bit house encode (MSD), followed by 4 bits of either the unit select encode or command code (LSD). -Finally, we get to the stop bit. If the last digit of the data was a unit select, it ends with a '0 1' pulse pattern. If it was a command, it ends with a '1 0' pulse pattern (OK, just a '1' will do). -Above example shows 1110 01 01 01 01 01 10 10 01 01. It was captured when the '1' select button was pressed under house code 'M'. House Codes and Unit Select codes are a mystery as to why they devised such an encrypted numbering system. I tried for weeks of idle time to figure a logical pattern -- failed. Here they are:
I'll show a few pulse patterns to illustrate. These pulses are synchronized with either a rising or falling edge of the 60 hz signal (pulse output at 120hz rate), and are 1.146mS long for a '1' and absent for a '0': 1110101010101010101001 House Code J, Unit Select 10 1110010101010101010101 House Code M, Unit Select 13 1110101010100101010101 House Code J, Unit Select 13 1110011010010110100101 House Code A, Unit Select 1 1110010101010101010110 House Code M, Command All Units Off 1110010101010101011010 House Code M, Command All Lights On Format: 1110 hh hh hh hh cc cc cc cc 10 or 1110 hh hh hh hh ss ss ss ss 01 Since these can be generated in an automated fashion, I found 236mS between the trailing bit of the first transmission and the leading bit of the following transmission (inter transmission spacing). That's about 420mS from start to start. For my first project, I needed a display device to work on the many busted X-10 console controllers I had stashed in the garage. I had no way of knowing what they were transmitting or even IF they were transmitting. The hardware is simple.
Programming took the better part of a day - includes writing this web page. It works very reliably although it does miss codes when the 'Bright' or 'Dim' buttons are pressed. It serves my purpose of troubleshooting keyboard controllers since my majority of failures turned out to be the cheap 'House Code' thumb wheel selectors on the bottom. They were putting out the right unit codes, but to the wrong house codes. A couple had no output at all, even though the light flashed.
The transmit side will wait for another day. There's enough code space left inside the AT90S2313 for some output command functions, but this project is a good start on understanding the technology. Robert J Reeder
'X-10 Code Display for Powerhouse two-way Power Line Interface TW523 'by Robert J Reeder, AVRProject 03/13/04 'This program only displays codes. Dim H As Byte , S As Byte , C As Byte , X As Byte Dim Shift1 As Byte , Shift2 As Byte , Shift3 As Byte Dim Tbl(16) As Byte , Func As String * 7 Tbl(1) = 13 Tbl(2) = 5 Tbl(3) = 3 Tbl(4) = 11 Tbl(5) = 15 Tbl(6) = 7 Tbl(7) = 1 Tbl(8) = 9 Tbl(9) = 14 Tbl(10) = 6 Tbl(11) = 4 Tbl(12) = 12 Tbl(13) = 16 Tbl(14) = 8 Tbl(15) = 2 Tbl(16) = 10 'shift 1, 2, and 3 are the main in shift register. ' Config Pind.2 = Input Config Pind.3 = Input Config Pinb.1 = Input Config Pinb.0 = Output Config Pind.5 = Output Portb.0 = 0 C = 0 Shift1 = 0 Shift2 = 0 Shift3 = 0 'We will interrupt every rise or fall of pin 1 (actually 120hz) Config Int0 = Falling Config Int1 = Rising On Int0 Sixtyhertz Nosave On Int1 Sixtyhertz Nosave Enable Int0 Enable Int1 Enable Interrupts Home Home Cls Cursor Off 'Display the codes: 'Upper line = "House x Sel nn" (Select) 'Lower Line = "House x ccccccc" (Command) 'Output to 9600 baud RS232 for permanent log of activity 'Main Program Loop (hard work done in machine code) Loop1: If C = 0 Then Goto Loop1 X = Tbl(h) + 64 Print "House " ; Chr(x) ; " "; If C = 64 Then Upperline Lcd "House " ; Chr(x) ; " Sel " ; Tbl(s) ; " "; Print "Sel " ; Tbl(s) End If If C = 128 Then Lowerline Lcd "House " ; Chr(x) ; " " ; If S = 1 Then Func = "All Off" If S = 2 Then Func = "All On " If S = 3 Then Func = "On " If S = 4 Then Func = "Off " If S = 5 Then Func = "Dim " If S = 6 Then Func = "Brightn" Lcd Func; Print Func End If C = 0 Goto Loop1
'Interrupt routine - most work is done here 'Sets C=128 or C=64 if an input is received Sixtyhertz: $asm push r31 push r30 push r29 push r28 in r31,sreg push r31 'give some delay time 400uS (10Mhz dependant, but forgiving) ldi r30,6 clr r31 Sh1: dec r31 brne sh1 ;3 cycles dec r30 brne sh1 ;(3 * 256 + 3)=771 *6=463uS 'Now we shift the <shift> bytes through carry 'leaving R31=MsB, R30=CsB, R29=LsB lds r29,{Shift3} 'Set the carry flag if the input line is pulled low clc sbis pinb,1 sec rol r29 sts {Shift3},r29 lds r30,{Shift2} rol r30 sts {Shift2},r30 lds r31,{Shift1} rol r31 sts {Shift1},r31 'now we check for the 3 high bits of [shift1] for set with a 4th clear andi r31,240 ;F0 cpi r31,224 ;E0 brne Sh2 'goes to Sh2 if pattern not found 'shift r31-r29 4 more times lds r31,{Shift1} ldi r28,4 ;loop counter Sh3: lsl r29 rol r30 rol r31 dec r28 brne Sh3 'store results sts {h},r31 ;house code sts {s},r30 ;select or command sts {c},r29 ;top two bits = 01 for sel, = 10 for cmd
'compress bits ldi r28,4 clr r29 clr r30 Sh4: lsl r31 rol r29 lsl r31 rol r30 dec r28 brne Sh4 inc r29 sts {h},r29 ;house code 1-16 dec r29 'At this point, R29 and R30 should be opposites 'xor one with the other should yeild all 1's eor r30,r29 cpi r30,15 brne BitError 'now lets do the same for the select or cmd lds r31,{s} ldi r28,4 clr r29 clr r30 Sh5: lsl r31 rol r29 lsl r31 rol r30 dec r28 brne Sh5 inc r29 sts {s},r29 ;unit code 1-16 dec r29 eor r30,r29 cpi r30,15 breq Sh2 Biterror: clr r31 sts {c},r31 ;clears C to void corrupt data Sh2: pop r31 Out Sreg , R31 pop r28 pop r29 pop r30 pop r31 $end Asm Return End |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||