Network Light Dimmer with Slider Control

 

History

   This project is one of many I have undertaken to control my house using a set of rules, a web interface, a logger and many more components. This project is a light dimmer which has multiple control interfaces such an RS485 network, an infrared remote control, a proximity touch slider or touch sensor.

    It is based on a ATMega8 and the well known Qprox QT401/QT110proximity sensor. The Mega8 had lots of things to do: detect zero crossing of phase, calculate the firing angle for the triac, manage the network communications, check for a finger presence and position on the proximity touch slider and detect and decode infrared coming from a remote control. The device is powered from the RS485 network connection which has +12, data+, data- and GND.  On the schematic you will see that there are two detectors, one is the slider, and the other is a simple touch detector.  It was done like this so that non-dimmable loads can be driven by using the touch detector as the control. That is why there are circuit pads on the board for two sensors.
 

 

Features

puce Slider QProx sensor
puce IR receiver
puce RS485 interface
puce Opto isolated
puce Up to 500watts
puce Network firmware upgradeable

 

Pictures

Click to enlarge

Top side of the PCB Dimmer

Original dimmer box cut to give more space in

the wall box

Mounting all together

 

Down side of the PCB Dimmer

Modification of the front plate

All done

 

Slider PCB

Slider PCB with is cover

All done with the IR receiver too!

 

Sources codes & Schematics

-Schematic NetDimmer  in PDF format

-Schematic of the Slider in PDF format

 

//*****************************************************************************
// NetDimmer
// Version 10.0 Nov 2005
//
// 10.0 -> New code for 9bit protocol
//
// Sylvain Bissonnette
//*****************************************************************************
// Editor : UltraEdit32
//*****************************************************************************
//
//                         R E T U R N   S T A C K   3 2
//                                  X T A L  16 MHZ
//                            BootLoader of 512 word
//
//*****************************************************************************
//
//                F U S E   B I T
//
//( )7      ( )6     (X)BL12 (X)BL11  ( )BL02   ( )BL01    ( )Lock2   ( )Lock1
//( )RSTDIS ( )WDON  (X)SPIEN(X)CKOPT (X)EESAVE (X)BOOTSZ1 ( )BOOTSZ0 (X)BOOTRST
//(X)BODLEV (X)BODEN ( )SUT1 ( )SUT0  ( )CKSEL3 ( )CKSEL2  ( )CKSEL1  ( )CKSEL0
//
//*****************************************************************************
//                P I N   U S A G E
//
// PB0 -> IR input
// PB1 -> n/c VCC
// PB2 -> SPI SS / LED
// PB3 -> SPI MOSI
// PB4 -> SPI MISO
// PB5 -> SPI SCK
// PB6 -> Xtal
// PB7 -> Xtal
//
// PC0 -> Dip Switch Bit-0
// PC1 -> Dip Switch Bit-1
// PC2 -> Dip Switch Bit-2
// PC3 -> Dip Switch Bit-3
// PC4 -> Dip Switch Bit-4
// PC5 -> Dip Switch Bit-5
// PC6 -> RESET
//
// PD0 -> RS485 RX
// PD1 -> RS485 TX
// PD2 -> Triac Zero Crossing interrupt input
// PD3 -> Option Jumper (Dimmer/Switch)Proximity Detector
// PD4 -> RS485 TXE
// PD5 -> n/c vcc
// PD6 -> Triac Drive
// PD7 -> Proximity Detector
//
// ADC6-> n/c
// ADC7-> n/c
//
//*****************************************************************************
//                T I M E R   U S A G E
//
// Timer 0 is use by TaskManager
// Timer 1 is use by triac and (IR remote controle or Slider)
//
//*****************************************************************************
// NetWork Function
//-----------------------------------------------------------------------------
// Command
// 0xff           -> Get 16 bit software version
// 0xf5,0x55,0xaa -> Reset MCU
// 0xf0,0x55,L,V  -> Write eeprom at L value V
// 0xf1,0x55,L    -> Read eeprom at L
// 0x10           -> Set Light from 0 to 10 Byte[1]
// 0x20           -> Get Light from 0 to 10
// 0x21           -> Get Switch stat 0/1
// 0x22           -> Get IR Command
//-----------------------------------------------------------------------------
// EEprom
// 00@xx -> Not used
//*****************************************************************************

//*****************************************************************************
//                      I N C L U D E
//*****************************************************************************
#include <iom8v.h>
#include <macros.h>
#include <stdlib.h>
#include <eeprom.h>
#include <shortnametype.h>
#include "TaskManager.h"

//*****************************************************************************
//                      D E F I N E
//*****************************************************************************
#define VERSION               100
#define DEVICE                80
#define TRUE                  1
#define FALSE                 0
#define XTAL                  16000000

#define LED                   0x04
#define LED_DDR               DDRB
#define LED_PIN               PINB
#define LED_PORT              PORTB

#define PROX_DDR              DDRD
#define PROX_PIN              PIND
#define PROX_PORT             PORTD
#define PROX_DET              0x80

#define TRIAC_DDR             DDRD
#define TRIAC_PIN             PIND
#define TRIAC_PORT            PORTD
#define TRIAC_DRIVE           0x40
#define TRIAC_ZERO_CROSSING   0x04
#define TRIAC_OPTION          0x08

#define DIMMER_PROX           0
#define DIMMER_SLIDER         1
#define SWITCH                2

#define SPI_DDR               DDRB
#define SPI_PIN               PINB
#define SPI_PORT              PORTB
#define SPI_DOUT              0x08
#define SPI_DIN               0x10
#define SPI_SCLK              0x20
#define SPI_SS                0x04
#define SPI_DET               0x01

#define NET_ADDRESS_DDR       DDRC
#define NET_ADDRESS_PIN       PINC
#define NET_ADDRESS_PORT      PORTC

#define NET_DDR               DDRD
#define NET_PIN               PIND
#define NET_PORT          &nbs¥þˆúbsp;  PORTD
#define NET_RX                0x01
#define NET_TX                0x02
#define NET_TXE               0x10

#define NET_UBRRH             UBRRH
#define NET_UBRRL             UBRRL
#define NET_UCSRA             UCSRA
#define NET_UCSRB             UCSRB
#define NET_UCSRC             UCSRC
#define NET_UDR               UDR

#define NET_RXBUFFER          10
#define NET_TXBUFFER          10

#define NET_GET_ADDRESS       NET_ADDRESS_PIN & 0x3f;

#define NET_SPEED             19200

#define BROADCASTDEVTYPE      0xf2
#define BROADCAST             0xff

#define IR_DDR                DDRB
#define IR_PIN                PINB
#define IR_PORT               PORTB
#define IR_INPUT              0x01

#define REMOTE_UP             20
#define REMOTE_DOWN           21
#define REMOTE_RIGHT          22
#define REMOTE_LEFT           23
#define REMOTE_MENU           24
#define REMOTE_STOP           30
#define REMOTE_PLAY           31
#define REMOTE_MUTE           32
#define REMOTE_REW            33
#define REMOTE_FFWD           34
#define REMOTE_PAUSE          35
#define REMOTE_POWER          40

//*****************************************************************************
//                  P R O T O T Y P E
//*****************************************************************************
void main(void);
void _StackOverflowed(char c);
int GetSwitchMode(void);

void LEDInit(void);
void LEDFlash(void);
void LightFlash(void);

void ProxInit(void);
void ProxCheckDimmer(void);
void ProxCheckSwitch(void);
void ProxSliderCheckDimmer(void);

void SPIInit(void);
ushort SPI(uint Write);
void SPISetSCLK(ushort state);
void SPISetDOUT(ushort state);
ushort SPIGetDIN(void);
void SPIWaitOnePulse(void);

void IRInit(void);
void IRLightChange(void);
void IRDecode(void);

void TriacInit(void);
void TriacFire(void);
void TriacZeroCrossing(void);

void NetInit(void);
void NetRxChar(void);
void NetAnalyseData(void);
void NetWrite(int Value);
void NetTxByte(void);
void NetTxFinish(void);
void NetGetAddress(void);

//*****************************************************************************
//                    G L O B A L   V A R I A B L E
//*****************************************************************************
ushort NetAddress;
ushort NetRxData[NET_RXBUFFER];
ushort NetTxData[NET_TXBUFFER];
ushort *NetTxPtr;
short NetTxQte;
short NetBroadCast = FALSE;

uint LatchedIrData = 0;
uint RemoteKey = -1;

ushort Light= 0;
ushort NetLight = 0;
ushort NetChange = 0;
ushort ChangeStat = FALSE;
ushort SwitchMode;

//*****************************************************************************
//                            M A I N
//*****************************************************************************
void main()
{
  int i;
  WDR();
  WDTCR = 0x0f;     // Enable WatchDog at 2.2 sec

  TaskInit();
  NetInit();
  TriacInit();
  IRInit();
  LEDInit();
  SPIInit();
  ProxInit();

  SEI();

  TaskRegister(NetGetAddress,T1S,TRUE);
  TaskRegister(IRLightChange,T100MS,TRUE);

  switch (GetSwitchMode())
  {
    case SWITCH :
      TaskRegister(ProxCheckSwitch,T80MS,TRUE);
      TaskRegister(LEDFlash,T100MS,TRUE);
      break;
    case DIMMER_PROX :
      TaskRegister(ProxCheckDimmer,T80MS,TRUE);
      TaskRegister(LEDFlash,T500MS,TRUE);
      break;
    case DIMMER_SLIDER :
      TaskRegister(ProxSliderCheckDimmer,T10MS,TRUE);
      break;
  }

  while (1)
  {
    WDR();
    _StackCheck();
  }
}

/******************************************************************************

Name:         void _StackOverflowed(char c)

Description:  This function is automaticaly called if
              the stack crash.


Input:        none

Output:       PB2

Misc:
******************************************************************************/
void _StackOverflowed(char c)
{
  CLI();
  while(1);
}

/******************************************************************************

Name:         void LightFlash(void)

Description:  This function make the Light Flashing

Input:        none

Output:       none

Misc:
******************************************************************************/
void LightFlash(void)
{
  if (Light == 0) Light = 100;
  else Light = 0;
}

/******************************************************************************

Name:         void GetSwitchMode(void)

Description:  This function is to get the switch mode


Input:        none

Output:       none

Misc:
******************************************************************************/
int GetSwitchMode(void)
{
  int i;

  for (i=0;i<500;i++) SPIWaitOnePulse();
  if ((TRIAC_PIN & TRIAC_OPTION) == TRIAC_OPTION) SwitchMode = SWITCH;
  else
  {
    SwitchMode = DIMMER_PROX;
    for (i=0;i<500;i++) // Check 500ms for QT401
    {
      if ((PROX_PIN & PROX_DET) != PROX_DET)  SwitchMode = DIMMER_SLIDER;
      SPIWaitOnePulse();
    }
  }
  return SwitchMode;
}

/******************************************************************************

Name:         void LEDInit(void)

Description:  Init device for LED

Input:        none

Output:       none

Misc:

******************************************************************************/
void LEDInit(void)
{
  LED_DDR |= LED;     // Pin as output
}

/******************************************************************************

Name:         void LEDFlash(void)

Description:  This function make the LED Flashing

Input:        none

Output:       none

Misc:
******************************************************************************/
void LEDFlash(void)
{
  LED_PORT ^= LED;
}

/******************************************************************************

Name:         void ProxInit(void)

Description:  Init device for proximity functions

Input:        none

Output:       none

Misc:

******************************************************************************/
void ProxInit(void)
{
  int i;

  PROX_DDR &= ~PROX_DET;      // Pin as input
  PROX_PORT |= PROX_DET;      // Pin as pullup
  SPI(0x01);
  while(!(PROX_PIN & PROX_DET)) WDR();
  SPI(0x02);
  while(!(PROX_PIN & PROX_DET)) WDR();
}

/******************************************************************************

Name:         void ProxCheckDimmer(void)

Description:  This function is call each 66ms to check
              the key and set the light

Input:        none

Output:       none

Misc:

******************************************************************************/
void ProxCheckDimmer(void)
{
  static ushort StillON = FALSE;
  static ushort OneShot = FALSE;
  static ushort DimUp = 0x00;
  static ushort Key = 0;
  static ushort Last = 0x0a;
  static ushort Debounce;

  if (!(PROX_PIN & PROX_DET)) Key++;
  if (Key > 25) Key = 25;

  if ((PROX_PIN & PROX_DET) && (Key > 0) && (Key < 5)) OneShot = TRUE;
  else OneShot = FALSE;

  if (!(PROX_PIN & PROX_DET) && (Key > 4)) StillON = TRUE;

  if ((PROX_PIN & PROX_DET) && (StillON == TRUE))
  {
    if (DimUp == TRUE) DimUp = FALSE;
    else DimUp = TRUE;
    StillON = FALSE;
  }

  if (OneShot == TRUE)
  {
    OneShot = FALSE;
    Key = 0;
    if (Light == 0)
    {
      Light = Last;
      DimUp = FALSE;
    }
    else
    {
      Light = 0;
      DimUp = TRUE;
    }
  }

  if (StillON == TRUE)
  {
    OneShot = FALSE;
    Key = 0;
    if ((DimUp == FALSE) && (Light > 0)) Light-=5;
    if ((DimUp == TRUE) && (Light < 100)) Light+=5;
    if (Light == 0) DimUp = TRUE;
    if (Light == 100) DimUp = FALSE;
    Last = Light;
  }
}

/******************************************************************************

Name:         void ProxCheckSwitch(void)

Description:  This function is call each 66ms to check
              the key and set the light

Input:        none

Output:       none

Misc:

******************************************************************************/
void ProxCheckSwitch(void)
{
  static ushort Debounce;

  if ((!(PROX_PIN & PROX_DET)) && (Debounce == FALSE))
  {
    Debounce = TRUE;
    ChangeStat = TRUE;
    if (Light == 0)
    {
      Light = 100;
    }
    else
    {
      Light = 0;
    }
  }
  if (PROX_PIN & PROX_DET) Debounce = FALSE;
}

/******************************************************************************

Name:         void ProxSliderCheckDimmer(void)

Description:  This function is call each time the QT401 have
              a valid value to give

Input:        none

Output:       none

Misc:

******************************************************************************/
void ProxSliderCheckDimmer(void)
{
  static ushort DriftComp = 0;
  static ushort LastLightValue = 10;
  static int Count = 0;
  static int Error = 0;
  ushort byte;
  int i;

  if (DriftComp++ > 3) // One drift compensation each 3 burst
  {
    SPI(0x03);
    DriftComp = 0;
    return;
  }
  else byte = SPI(0x00);

  // Check for sensor Error
  if ((byte & 0x82) == 0x02)
    {
      Error++;
      if (Error > 3)
      {
        ProxInit();
        Error = 0;
        return;
      }
    }
  if ((byte & 0x82) == 0x00) Error = 0;

  // if sensor is not touch exit
  if ((PROX_PIN & PROX_DET) != PROX_DET) return;

  // Check is the sensor is touch if yes increment Count
  if ((byte & 0x80) == 0x80) Count++;
  else Count = 0;

  // If touch for the frist time toggle light to is last value
  if (((byte & 0x80) == 0x80)  && (Count == 2))
  {
    if (Light == 0) Light = LastLightValue;
    else Light = 0;
  }

  // If continously touch set the light value to
  // the new value
  if (Count > 25)
  {
    Count = 26;
    if ((byte & 0x80) == 0x80)
    {
      i = (byte & 0x7f) * 100;
      i = i / 127;
      Light = i;
      LastLightValue = Light;
    }
  }
}

/******************************************************************************

Name:         void SPIInit(void)

Description:  Init device for SPI functions

Input:        none

Output:       none

Misc:
******************************************************************************/
void SPIInit(void)
{
  int i;

  SPI_DDR |= SPI_SCLK + SPI_DOUT + SPI_SS;      // All those as output
  SPI_DDR &= ~SPI_DIN;                             // As input
  SPI_PORT |= SPI_SCLK + SPI_SS;                // Clock at 1
}

/******************************************************************************

Name:         void SPI(void)

Description:  Write and read a byte from the QT401

Input:        uint8 -> value to write to SPI

Output:       uint8 -> value read from SPI

Misc:
******************************************************************************/
ushort SPI(uint Write)
{
  signed char i;
  ushort Read = 0x00;

  SPI_PORT &= ~SPI_SS;
  SPIWaitOnePulse();
  for (i=7;i!=-1;i--)
  {
    SPISetDOUT(Write&(1<<i));
    SPISetSCLK(FALSE);
    SPIWaitOnePulse();
    SPISetSCLK(TRUE);
    SPIWaitOnePulse();
    Read = Read << 1;
    if (SPIGetDIN()) Read |= 0x01;
  }
  SPIWaitOnePulse();
  SPI_PORT |= SPI_SS;
  return Read;
}

/******************************************************************************

Name:         void SPISetSCLK(ushort state)

Description:  Set the SPI clock line

Input:        ’ö!ˆr state -> 0 or 1

Output:       none

Misc:
******************************************************************************/
void SPISetSCLK(ushort state)
{
  if (state) SPI_PORT |= SPI_SCLK;
  else SPI_PORT &= ~SPI_SCLK;
}

/******************************************************************************

Name:         void SPISetDOUT(ushort state)

Description:  Set the SPI data in line

Input:        uchar state -> 0 or 1

Output:       none

Misc:
******************************************************************************/
void SPISetDOUT(ushort state)
{
  if (state) SPI_PORT |= SPI_DOUT;
  else SPI_PORT &= ~SPI_DOUT;
}

/******************************************************************************

Name:         ushort SPIGetDIN(void)

Description:  Get the SPI data in line

Input:        none

Output:       uchar state -> 0 or 1

Misc:
******************************************************************************/
ushort SPIGetDIN(void)
{
  if ((SPI_PIN & SPI_DIN)) return 1;
  else return 0;
}

/******************************************************************************

Name:         void   SPIWaitOnePulse(void)

Description:  Clock & Data line delay for 23khz

Input:        none

Output:       none

Misc:
******************************************************************************/
void SPIWaitOnePulse(void)
{
  int i;

  for (i=0;i<(XTAL/400000);i++) WDR();
}

/******************************************************************************

Name:         void IRInit(void)

Description:  Init device for IR functions

Input:        none

Output:       none

Misc:         Share Timer 1 with Triac functions

******************************************************************************/
void IRInit(void)
{
  IR_DDR &= ~IR_INPUT;          // ICP as input on PB0
  IR_PORT |= IR_INPUT;          // Pull up on ICP pin
  TCCR1B |= (1<<CS11);          // Timer1 / 8
  TCCR1B |= (1<<ICES1);         // Rising edge on ICP
  TIMSK |= (1<<TICIE1);         // Int on ICP
}

/******************************************************************************

Name:         void IRLightChange(void);

Description:  Check the IR command Change Light

Input:        none

Output:       none

Misc:

******************************************************************************/
void IRLightChange(void)
{
  if ((SwitchMode != SWITCH) && (RemoteKey == REMOTE_UP) && (Light < 96))
  {
    Light+=5;
    if (Light > 95) Light = 100;
    RemoteKey = -1;
  }

  else if ((SwitchMode != SWITCH) && (RemoteKey == REMOTE_DOWN) && (Light > 4))
  {
    Light-=5;
    if (Light < 5) Light = 0;
    RemoteKey = -1;
  }

  else if ((SwitchMode == SWITCH) && (RemoteKey == REMOTE_UP))
  {
    Light = 100;
    RemoteKey = -1;
  }
  else if ((SwitchMode == SWITCH) && (RemoteKey == REMOTE_DOWN))
  {
    Light = 0;
    RemoteKey = -1;
  }
}

/******************************************************************************

Name:         void IRDecode(void);

Description:  This routine is called whenever a rising edge (beginning
              of valid IR signal) is received.

Input:        none

Output:       Global variable LatchedIrData

Misc:         Sony VCR protocol

******************************************************************************/
#pragma interrupt_handler IRDecode:6
void IRDecode(void)
{
  static uint LastCapture;
  uint PulseWidth;
  static ushort IrPulseCount;
  static uint IrData;

  PulseWidth = ICR1 - LastCapture;
  LastCapture = ICR1;

  if (PulseWidth > (XTAL/4000))
  {
    IrPulseCount = 0;
    IrData = 0;
  }
  else
  {
    IrData = IrData >> 1;
    if (PulseWidth > (XTAL/5714)) IrData = IrData | 0x8000;
    IrPulseCount++;
    if (IrPulseCount == 12)
    {
      LatchedIrData = IrData >> 4;
      switch(LatchedIrData)
      {
        case 2176 : RemoteKey = 1;
        break;
        case 2177 : RemoteKey = 2;
        break;
        case 2178 : RemoteKey = 3;
        break;
        case 2179 : RemoteKey = 4;
        break;
        case 2180 : RemoteKey = 5;
        break;
        case 2181 : RemoteKey = 6;
        break;
        case 2182 : RemoteKey = 7;
        break;
        case 2183 : RemoteKey = 8;
        break;
        case 2184 : RemoteKey = 9;
        break;
        case 2208 : RemoteKey = 0;
        break;
        case 2224 : RemoteKey = REMOTE_REW;
        break;
        case 2227 : RemoteKey = REMOTE_REW;
        break;
        case 2225 : RemoteKey = REMOTE_FFWD;
        break;
        case 2228 : RemoteKey = REMOTE_FFWD;
        break;
        case 2231 : RemoteKey = REMOTE_UP;
        break;
        case 2238 : RemoteKey = REMOTE_UP;
        break;
        case 2230 : RemoteKey = REMOTE_DOWN;
        break;
        case 2237 : RemoteKey = REMOTE_DOWN;
        break;
        case 2235 : RemoteKey = REMOTE_RIGHT;
        break;
        case 2194 : RemoteKey = REMOTE_RIGHT;
        break;
        case 2234 : RemoteKey = REMOTE_LEFT;
        break;
        case 2195 : RemoteKey = REMOTE_LEFT;
        break;
        case 2233 : RemoteKey = REMOTE_PAUSE;
        break;
        case 2232 : RemoteKey = REMOTE_STOP;
        break;
        case 2226 : RemoteKey = REMOTE_PLAY;
        break;
        case 2271 : RemoteKey = REMOTE_MUTE;
        break;
        case 2262 : RemoteKey = REMOTE_MENU;
        break;
        case 2197 : RemoteKey = REMOTE_POWER;
        break;
        default   : RemoteKey = -1;
        break;
      }
    }
  }
}

/******************************************************************************

Name:         void TriacInit(void)

Description:  Init device for Triac functions

Input:        none

Output:       none

Misc:       Timer 1

******************************************************************************/
void TriacInit(void)
{
  TRIAC_DDR |= TRIAC_DRIVE;           // PD6 as output
  TRIAC_DDR &= ~TRIAC_ZERO_CROSSING;   // PD2 as input for Int 0
  TRIAC_DDR &= ~TRIAC_OPTION;          // PD3 as input
  TRIAC_PORT |= TRIAC_OPTION;          // PD3 as pullup
  // Int 0 on Low level
  GICR |= (1<<INT0);                   // Int 0 enable
  TCCR1B |= (1<<CS11);                 // Timer1 / 8
  TIMSK |= (1<<OCIE1A);                // Int on compare match A

  Light= 0;
}

/******************************************************************************

Name:         void TriacFire(void)

Description:  This function is automaticaly called
              when the delay is expired and fire the
triac

Input:        none

Output:       none

Misc:         Timer 1 is also share with IR remote controle

******************************************************************************/
#pragma interrupt_handler TriacFire:7
void TriacFire(void)
{
  int i;

  if (SwitchMode != SWITCH)
  {
    if ((Light > 0) && (Light < 100))
    {
      CLI();
      TRIAC_PORT |= TRIAC_DRIVE;
      for (i=0;i<10;i++);   // 15us
      TRIAC_PORT &= ~TRIAC_DRIVE;
      SEI();
    }
    CLI();
    if (Light == 0)  TRIAC_PORT &= ~TRIAC_DRIVE;
    if (Light == 100) TRIAC_PORT |= TRIAC_DRIVE;
    SEI();
  }
  GICR |= (1<<INT0); // Int 0 enable
}

/******************************************************************************

Name:         void TriacZeroCrossing(void)

Description:  This function is automaticaly called
              each time the 110Vac cross 0 volt and
              set up the delay to fire the triac later
              delay from light 9 -> 0x05fa to
              light 1 -> 0x0d6a
             
Input:        none

Output:       none

Misc:

******************************************************************************/
#pragma interrupt_handler TriacZeroCrossing:2
void TriacZeroCrossing(void)
{
  static ushort Delay = 0;

  OCR1A = TCNT1 + ((100 - Light) * 120) + 3200;
  GICR &= ~(1<<INT0); // Int0 Disable

  if (SwitchMode != SWITCH)
  {
    Delay++;
    if (Delay > 2)
    {
      Delay = 0;
      if (NetChange == TRUE)
      {
        if (NetLight > Light) Light++;
        if (NetLight < Light) Light--;
        if (NetLight == Light) NetChange = FALSE;
      }
    }
  }
  else
  {
    if (NetChange == TRUE)
    {
      if (NetLight == 0) Light = 0;
      else Light = 10;
      NetChange = FALSE;
    }
    CLI();
    if (Light == 0)  TRIAC_PORT &= ~TRIAC_DRIVE;
    else TRIAC_PORT |= TRIAC_DRIVE;
    SEI();
  }
}

//*****************************************************************************
//        N E T W O R K     F U N C T I O N
//*****************************************************************************
/******************************************************************************

Name:         void NetInit(void)

Description:  This function initialize for NET network

Input:        None

Output:       None

Misc:
******************************************************************************/
void NetInit(void)
{
  NET_UBRRH = ((XTAL / (16 * NET_SPEED)) - 1)>>8;  //set baud rate Ÿ™'úi>
  NET_UBRRL = (XTAL / (16 * NET_SPEED)) - 1;      //set baud rate
  NET_UCSRA = (1<<MPCM);
  NET_UCSRB = (1<<UCSZ2) + (1<<RXCIE)+(1<<RXEN)+(1<<TXEN)+(1<<TXCIE);
  NET_UCSRC = (1<<URSEL)+(1<<UCSZ1) + (1<<UCSZ0);  // 8 bit
  NET_PORT &= ~NET_TXE;                               // Switch NET in Rx mode
  NET_PORT |= NET_RX;                               // Pull up on RX
  NET_DDR |= NET_TXE + NET_TX;
  NET_ADDRESS_DDR = 0x00;                                // All port as input
  NET_ADDRESS_PORT = 0xff;                               // All port as pullup
  NetGetAddress();
}

/******************************************************************************

Name:         void NetRxChar(void)

Description:  This function is automaticaly called each
              time a char is received on the NET bus.


Input:        none

Output:       Data in NetRxData[]

Misc:
******************************************************************************/
#define RESET     0
#define QTE       1
#define DATA      2
#define CHECKSUM  3

#pragma interrupt_handler NetRxChar:12
void NetRxChar(void)
{
  static ushort InByte;
  static ushort Qte;
  static ushort CheckSum;
  static ushort *Ptr;
  static ushort State;

  if (NET_UCSRA & ((1<<FE)+(1<<DOR)))
  {
    InByte = NET_UDR;
    return;
  }

  if (NET_UCSRB & (1<<RXB8))
  {
    InByte = NET_UDR;
    if (InByte == NetAddress)
    {
      NET_UCSRA &= ~(1<<MPCM);
      State = QTE;
      NetBroadCast = FALSE;
      return;
    }
    else if ((InByte == BROADCASTDEVTYPE) || (InByte == BROADCAST))
    {
      NET_UCSRA &= ~(1<<MPCM);
      State = QTE;
      NetBroadCast = TRUE;
      return;
    }
    else
    {
      NET_UCSRA |= (1<<MPCM);
      State = RESET;
      NetBroadCast = FALSE;
      return;
    }
  }

  InByte = NET_UDR;

  switch (State)
  {
    case QTE :
    CheckSum = 0;
    Ptr = &NetRxData[0];
    Qte = InByte;
    State = DATA;
    break;

    <