본문 바로가기

아두이노우노 R4

아두이노를 이용한 원격 제어 조명 제어 Dimming Light

반응형

 

아두이노를 이용한 원격 제어 조명 조광기 Dimming Light 

 

지난 프로젝트에서는 전위차계로 빛의 세기(램프 밝기)를 제어하는 아두이노를 이용한 간단한 조광기를 만들었는데, 이번 프로젝트에서는 전위차계 대신 IR 리모컨으로 램프 밝기를 제어하도록 회로에 리모컨을 추가하는 방법을 보여드리겠습니다.

 

이 프로젝트에 사용된 IR 리모컨은 RC-5 통신 프로토콜을 사용합니다. 아래 관련 프로젝트는 RC-5 리모컨을 디코딩하는 방법을 보여줍니다. 아두이노 코드에서 사용할 버튼의 IR 코드를 알기 위해 IR 리모컨을 디코딩해야 한다는 점에 유의하세요. 

 

Related Projects:
220V Light dimmer with Arduino – Lamp brightness control
Arduino RC5 IR remote control decoder

 

 

아두이노 원격 제어 조명 디머 회로: 

 

 

 

모든 접지된 단자는 함께 연결됩니다.

 

일반적으로 IR 수신기에는 3개의 핀이 있습니다: 이 예제에서는 출력 핀이 외부 인터럽트 핀(INT0)인 Arduino 핀 2에 연결됩니다. IR 센서와 LM393 비교기 IC에는 5V가 공급됩니다(아두이노 보드에서 제공됨).

 

LM393 비교기는 제로 크로싱 감지에 사용됩니다. 

 

아두이노 원격 제어 조명 디머 코드:

 

회로도에 표시된 것처럼 IR 수신기 출력 핀은 아두이노 외부 인터럽트 핀(핀 번호 2)에 연결되어 있으므로 리모컨에서 버튼을 누르면 아두이노가 즉시 IR 신호를 읽기 시작합니다.

 

이 예제에 사용된 리모컨은 RC-5 프로토콜을 사용하며 RC-5 코드 메시지는 시작 비트 2개, 토글 비트 1개, 주소 비트 5개 및 명령 비트 6개 등 14비트 길이로 구성됩니다. 2개의 비트(시작 비트)는 항상 1이고 토글 비트는 1 또는 0일 수 있습니다.

 

이 프로젝트에서는 2개의 시작 비트와 토글 비트는 아무런 효과가 없기 때문에(또한 코드를 단순화하기 위해) 전혀 사용하지 않았습니다. 모든 주소 비트가 0(주소 = 0)인 TV 리모컨을 사용했습니다.

 

남은 것은 RC-5 코드 메시지에서 명령 번호인 중요한 부분으로, 두 개의 버튼을 사용했습니다. 첫 번째 버튼은 코드 = 0x10으로 빛의 강도를 높이고, 두 번째 버튼은 코드 = 0x11로 빛의 강도를 낮춥니다. 리모컨의 다른 버튼은 회로에 아무런 영향을 미치지 않습니다. 

 

내 AC 소스의 주파수는 50Hz이므로 주기는 20밀리초이므로 반파 주기는 10밀리초 = 10000µs입니다.

 

전체 아두이노 코드: 

 

// Arduino light dimmer with IR remote control
// This is a free software with NO WARRANTY - Use it at your own risk!
// http://simple-circuit.com/

// Define number of Timer1 ticks (with a prescaler of 1/8)
#define short_time     1400                      // Used as a minimum time for short pulse or short space ( ==>  700 us)
#define   med_time     2400                      // Used as a maximum time for short pulse or short space ( ==> 1200 us)
#define  long_time     4000                      // Used as a maximum time for long pulse or long space   ( ==> 2000 us)

// define remote control button codes
#define Button_up   0x10
#define Button_dn   0x11

#define ZC_input     3
#define triac_gate   8

bool ZC_previous = 0;
byte rc5_state = 0, j, alpha = 100;
unsigned int rc5_code;

void setup(void) {
  pinMode(triac_gate, OUTPUT);
  digitalWrite(triac_gate, LOW);

  // Timer1 module configuration
  TCCR1A = 0;
  TCCR1B = 0;                                    // Disable Timer1 module
  TCNT1  = 0;                                    // Set Timer1 preload value to 0 (reset)
  TIMSK1 = 1;                                    // enable Timer1 overflow interrupt

  attachInterrupt(0, RC5_Read, CHANGE);          // Enable external interrupt (INT0)
}

void RC5_Read() {
unsigned int timer_value;
  if(rc5_state != 0){
    timer_value = TCNT1;                         // Store Timer1 value
    TCNT1 = 0;                                   // Reset Timer1
  }

  switch(rc5_state){
    case 0 :                                      // Start receiving IR data (initially we're at the beginning of mid1)
      TCNT1  = 0;                                  // Reset Timer1
      TCCR1B = 2;                                  // Enable Timer1 module with 1/8 prescaler ( 2 ticks every 1 us)
      rc5_state = 1;                               // Next state: end of mid1
      j = 0;
      return;

    case 1 :                                      // End of mid1 ==> check if we're at the beginning of start1 or mid0
      if((timer_value > long_time) || (timer_value < short_time)){         // Invalid interval ==> stop decoding and reset
        rc5_state = 0;                             // Reset decoding process
        TCCR1B = 0;                                // Disable Timer1 module
        return;
      }
      bitSet(rc5_code, 13 - j);
      j++;
      if(j > 13){                                  // If all bits are received
        rc5_state = 0;
        rc5_code &= 0x07FF;                        // Remove the two start bits and the toggle bit from the code message
        if( (rc5_code == Button_dn) && (alpha < 100) )
          alpha++;
        if( (rc5_code == Button_up) && (alpha > 0) )
          alpha--;
        return;
      }
      if(timer_value > med_time){                // We're at the beginning of mid0
        rc5_state = 2;                           // Next state: end of mid0
        if(j == 13){                             // If we're at the LSB bit
          rc5_state = 0;
          bitClear(rc5_code, 0);                 // Clear the LSB bit
          rc5_code &= 0x07FF;
          if( (rc5_code == Button_dn) && (alpha < 100) )
            alpha++;
          if( (rc5_code == Button_up) && (alpha > 0) )
            alpha--;
          return;
        }
      }
      else                                       // We're at the beginning of start1
        rc5_state = 3;                           // Next state: end of start1
      return;

    case 2 :                                      // End of mid0 ==> check if we're at the beginning of start0 or mid1
      if((timer_value > long_time) || (timer_value < short_time)){
        rc5_state = 0;                             // Reset decoding process
        TCCR1B = 0;                                // Disable Timer1 module
        return;
      }
      bitClear(rc5_code, 13 - j);
      j++;
      if(timer_value > med_time)                   // We're at the beginning of mid1
        rc5_state = 1;                             // Next state: end of mid1
      else                                         // We're at the beginning of start0
        rc5_state = 4;                             // Next state: end of start0
      return;

    case 3 :                                      // End of start1 ==> check if we're at the beginning of mid1
      if((timer_value > med_time) || (timer_value < short_time)){           // Time interval invalid ==> stop decoding
        TCCR1B = 0;                                // Disable Timer1 module
        rc5_state = 0;                             // Reset decoding process
        return;
      }
      else                                         // We're at the beginning of mid1
        rc5_state = 1;                             // Next state: end of mid1
      return;
    case 4 :                                      // End of start0 ==> check if we're at the beginning of mid0
      if((timer_value > med_time) || (timer_value < short_time)){           // Time interval invalid ==> stop decoding
        TCCR1B = 0;                                // Disable Timer1 module
        rc5_state = 0;                             // Reset decoding process
        return;
      }
      else                                         // We're at the beginning of mid0
        rc5_state = 2;                             // Next state: end of mid0
      if(j == 13){                                 // If we're at the LSB bit
        rc5_state = 0;
        bitClear(rc5_code, 0);                     // Clear the LSB bit
        rc5_code &= 0x07FF;
        if( (rc5_code == Button_dn) && (alpha < 100) )
          alpha++;
        if( (rc5_code == Button_up) && (alpha > 0) )
          alpha--;
      }
  }
}

ISR(TIMER1_OVF_vect) {                           // Timer1 interrupt service routine (ISR)
  rc5_state = 0;                                 // Reset decoding process
  TCCR1B = 0;                                    // Disable Timer1 module
}

void loop() {

  while(digitalRead(ZC_input) == ZC_previous) ;  // Wait for zero crossing event

  ZC_previous = digitalRead(ZC_input);

  delayMicroseconds(alpha * 95);                 // Why 95? for max alpha=100 we get 9500µs (half wave period=10000µs)
  digitalWrite(triac_gate, HIGH);
  delayMicroseconds(200);
  digitalWrite(triac_gate, LOW);

}

 

 

언제나 그렇듯이 이 링크를 따라가시면 참고 원문을 확인하실 수 있습니다.

 

 

 

 

반응형

더욱 좋은 정보를 제공하겠습니다.~ ^^