아두이노를 이용한 원격 제어 조명 조광기 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);
}
언제나 그렇듯이 이 링크를 따라가시면 참고 원문을 확인하실 수 있습니다.
'아두이노우노 R4' 카테고리의 다른 글
우노 R4로 키보드로 업무를 자동화 버튼 (1) | 2024.12.15 |
---|---|
DS18B20 온도센서 식별 번호 관리 방법 (1) | 2024.12.14 |
Adafruit CH552 QT Py (2) | 2024.12.08 |
Adafruit CH552 QT Py 아두이노 환경 설정 (1) | 2024.12.08 |
키보드 자동화 샘플 코드 2 (2) | 2024.12.04 |
DF Player Mini를 사용한 Arduino와 함께 오디오 플레이어 프로젝트 (0) | 2024.11.20 |
Bluetooth HM-10 BLE module 서로 통신하는 방법 (0) | 2024.11.12 |
DIY 홈보안 시스템 Arduino Uno R4 Wi-Fi키패드 LCD 디스플레이 (2) | 2024.11.02 |
더욱 좋은 정보를 제공하겠습니다.~ ^^