/*****************************************************
This program was produced by the
CodeWizardAVR V2.03.4 Standard
Automatic Program Generator
© Copyright 1998-2008 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com

Project : 
Version : 
Date    : 10.10.2010
Author  : 
Company : 
Comments: 


Chip type           : ATmega8
Program type        : Application
Clock frequency     : 16,000000 MHz
Memory model        : Small
External RAM size   : 0
Data Stack size     : 256
*****************************************************/

#include <mega8.h>
#include <delay.h>

#define delay_   30    // плавность включения
#define yes   1
#define no    0

int status = 0;  // текущее значение яркости

unsigned int tick = 0;          //счетчик тиков таймера
unsigned char b_cnt = 0;        //счетчик принятых бит
bit start_cond = 0;             //флаг стартового условия
//bit repeat_cond = 0;            //флаг повтора

unsigned char addr_1 = 0;       //прямой байт адреса
unsigned char addr_0 = 0;       //инверсный байт адреса
unsigned char cmd_1 = 0;        //прямой байт команды
unsigned char cmd_0 = 0;        //инверсный байт команды
unsigned char cmd = 0;          //байт команды

// External Interrupt 0 service routine
interrupt [EXT_INT0] void ext_int0_isr(void)
  {
  TCNT1 = 0; // сбросили таймер
  }
  
// External Interrupt 1 service routine
interrupt [EXT_INT1] void ext_int1_isr(void)
{
        TCNT0=0xFA;                                                             // запускаем таймер на 96 мкс
        TCCR0=0x04;                                                             // частота таймера 62.500 кГц
        
        /*if (tick >= 92 && tick < 96 && start_cond)                              //если прошло от 8,832 мс до 9,216 мс и есть стартовое условие
                {
                repeat_cond = 1;                                                //фиксируем флаг повтора
                //start_cond = 0;                                                 //обнуляем флаг стартового условия
                TCNT0=0x00;
                }*/
        if (tick >= 92 && tick < 96)                                            //если прошло от 8,832 мс до 9,216 мс
                {
                start_cond = 1;                                                 //фиксируем стартовое условие
                addr_1 = addr_0 = cmd_1 = cmd_0 = 0;                            //обнуляем ранее полученную команду и адрес
                }
        if (tick >= 21 && tick < 25 && start_cond)                              //если прошло от 2,016 мс до 2,4 мс
                {
                b_cnt++;                                                        //приняли "1" и увеличили счетчик битов
                if (b_cnt < 9) addr_1 = (addr_1 << 1) + 1;                      //первый байт - прямой адрес
                if (b_cnt >= 9 && b_cnt < 17) addr_0 = (addr_0 << 1) + 1;       //второй байт - инверсный адрес
                if (b_cnt >= 16 && b_cnt < 25) cmd_1 = (cmd_1 << 1) + 1;        //третий байт - прямая команда
                if (b_cnt >= 24) cmd_0 = (cmd_0 << 1) + 1;                      //четвертый байт - инверсная команда
                }
        if (tick >= 10 && tick < 22 && start_cond)                              //если прошло от 0,96 мс до 2,112 мс
                {
                b_cnt++;                                                        //приняли "0" и увеличили счетчик битов
                if (b_cnt < 9) addr_1 = (addr_1 << 1);                          //далее - аналогично по байтам
                if (b_cnt >= 9 && b_cnt < 17) addr_0 = (addr_0 << 1);
                if (b_cnt >= 16 && b_cnt < 25) cmd_1 = (cmd_1 << 1);
                if (b_cnt >= 24) cmd_0 = (cmd_0 << 1);
                }
        tick = 0;                                                               //обнулили тики
        if (b_cnt == 32)                                                        //если приняли уже 4 байта
                {
//                 if ((addr_1+addr_0) == 0xFF) addr = addr_0;                  //закомментировано, потому как в пульте First
//                         else addr = 0;                                       //16-bit адрес 0x6120, т.о. проверка адреса не проходит
                if ((cmd_1 + cmd_0) == 0xFF) {                                  //проверили правильность приема команды
                  cmd = cmd_1;
                  }                       
                else {
                  cmd = 0;        
                  b_cnt = 0;                                                    //обнулили счетчик битов
                  start_cond = 0;                                               //сбросили стартовое условие
                  //repeat_cond = 0;
                  TCCR0=0x00;                                                   //остановили таймер
                  TCNT0=0x00;
                  }
                }
}

// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
        TCNT0=0xFA;                                                    //переинициировали таймер - отсчитывает 96 мкс
        tick++;                                                        //увеличили число тиков
        if (tick > 500) {                                              //если прошло более 48 мс
          TCCR0=0x00;                                                  //сбросили все к исходному состоянию
          TCNT0=0x00;
          tick = 0;                                                       
          start_cond = 0;
          //repeat_cond = 0;
          cmd = 0;
        }

}

// Timer 1 output compare A interrupt service routine
interrupt [TIM1_COMPA] void timer1_compa_isr(void)
  { 
  PORTC.5 = 1;    // открыли симистор
  delay_us(200);  // импульс 200 мкс
  PORTC.5 = 0;    // вернулись в режим ожидания
  }

// Таблица задержек для 16-тибитного таймера
flash const unsigned int nagruzka[99] = {
20324,  // 1% нагрузки
19794,  // 2% нагрузки
19384,  // 3% нагрузки
19036,
18728,
18450,
18190,
17948,
17720,
17504,
17296,
17096,
16904,
16718,
16536,
16360,
16188,
16022,
15858,
15696,
15538,
15384,
15232,
15082,
14934,
14788,
14644,
14500,
14360,
14220,
14082,
13944,
13808,
13674,
13540,
13406,
13274,
13142,
13012,
12882,
12752,
12622,
12494,
12366,
12238,
12110,
11982,
11854,
11728,
11600,
11472,
11346,
11218,
11090,
10962,
10834,
10706,
10578,
10448,
10318,
10188,
10058,
9926,
9794,
9660,
9526,
9392,
9256,
9118,
8980,
8840,
8700,
8556,
8412,
8266,
8118,
7968,
7816,
7662,
7504,
7342,
7178,
7012,
6840,
6664,
6482,
6296,
6104,
5904,
5696,
5480,
5252,
5010,
4750,
4472,
4164,
3816, // 97% нагрузки
3406, // 98% нагрузки
2876, // 99% нагрузки
};

/*========================================= ФУНКЦИЯ ПЛАВНОГО ВКЛЮЧЕНИЯ ===========================================*/

void soft_on (unsigned int phaze) {  // функция регулирует мощность от 1% до 99% ( phaze от 0 до 98 )
 int on;                             // крайние положения надо выставлять вручную: PORTC.5 = 1 или PORTC.5 = 0
 for (on=0;on<=phaze;on++) {           
  OCR1A = nagruzka[on];
  delay_ms(delay_);
 };
}

/*============================== ФУНКЦИЯ ПЛАВНОГО ВЫКЛЮЧЕНИЯ С ТЕКУЩЕЙ ЯРКОСТИ ===================================*/

void soft_off (unsigned int phaze) {  
 int off;                             
 for (off=phaze;off>=0;off--) {           
  OCR1A = nagruzka[off];
  delay_ms(delay_);
 };
}

void main(void)
{
// Declare your local variables here

// Input/Output Ports initialization
// Port B initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In 
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T 
PORTB=0xFF;
DDRB=0xFF;

// Port C initialization
// Func6=Out Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out 
// State6=0 State5=0 State4=0 State3=0 State2=0 State1=0 State0=0 
PORTC=0x00;
DDRC=0x7F;

// Port D initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In 
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T 
PORTD=0x08;
DDRD=0x00;

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
TCCR0=0x00;
TCNT0=0x00;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 2000,000 kHz
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: On
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x46;
OCR1AL=0x50;
OCR1BH=0x00;
OCR1BL=0x00;

// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer 2 Stopped
// Mode: Normal top=FFh
// OC2 output: Disconnected
ASSR=0x00;
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;

// External Interrupt(s) initialization
// INT0: On
// INT0 Mode: Falling Edge
// INT1: On
// INT1 Mode: Falling Edge
GICR|=0xC0;
MCUCR=0x0A;
GIFR=0xC0;

// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x11;

// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
SFIOR=0x00;

// Global enable interrupts
#asm("sei")

while (1)
      {
/*====================================== РЕАКЦИЯ НА НАЖАТИЕ КЛАВИШ ВЫКЛЮЧАТЕЛЯ ==================================*/

      if (PINB.0==0) {         // ждем нажатие клавиши выключателя
       delay_ms(50);           // антидребезг
       if (status==0) {
        TCCR1B=0x02;           // запуск таймера на 2000 кГц
        soft_on (98);          // плавно от 1% до 99% мощности
        TCCR1B=0x00;           // остановка таймера ( чтобы не молотил в пустую 200 мкс импульсы на PORTC.5 )
        PORTC.5 = 1;           // 100%
		status = 98;
        }
       else {
        TCCR1B=0x02;
        soft_off(status);      // плавно выключаем с текущей мощности
        TCCR1B=0x00;
        PORTC.5 = 0; // 0%
        status=0;
       };
       }
       
       /*if (PINB.5==0) {      // вкл/выкл основного света
       // реле вкл/выкл
       }*/
       
/*========================================= УВЕЛИЧЕНИЕ/УМЕНЬШЕНИЕ ЯРКОСТИ =======================================*/

	   if (cmd == 0b11111000) {       // кнопка "Display" - увеличение яркости
          TCCR1B=0x02;
		  status++;
		  if (status >= 98) {
            TCCR1B=0x00;
		    status = 98;   
            PORTC.5 = 1;                // полностью включили
			}
          else {
		    OCR1A = nagruzka[status];   // увеличиваем яркость
		    delay_ms(delay_);
            }
		 }
         
       if (cmd == 0b11000000) {      // кнопка "Sleep" - уменьшение яркости
          TCCR1B=0x02;
		  status--;
		  if (status < 1) {
		    status = 0;                 // чтобы не уйти в минус
            PORTC.5 = 0;                // полностью выключили
            TCCR1B=0x00;
			}
          else {
		    OCR1A = nagruzka[status];   // уменьшаем яркость
		    delay_ms(delay_);
            }
		 }
         
/*===================================== ВКЛЮЧЕНИЕ/ВЫКЛЮЧЕНИЕ С ПУЛЬТА ========================================*/

      if (cmd == 0b11011000) {          // кнопка "TV" - вкл/выкл диммера
       if (status==0) {
        TCCR1B=0x02;                    // запуск таймера на 2000 кГц
        soft_on (98);                   // плавно от 1% до 99% мощности
        TCCR1B=0x00;                    // остановка таймера ( чтобы не молотил в пустую 200 мкс импульсы на PORTC.5 )
        PORTC.5 = 1;                    // 100%
		status = 98;
        }
       else {
        TCCR1B=0x02;
        soft_off(status);               // плавно выключаем с текущей мощности
        TCCR1B=0x00;
        PORTC.5 = 0; // 0%
        status=0;
       };
      }
      
      if (cmd == 0b10000000) {          // кнопка "VIDEO" - вкл/выкл основного света
      // реле вкл/выкл
      }
      };
}
