아이가 유치원에서 너무나 예쁜 스탠드를 만들어 왔습니다.. AAA 건전지가 들어가는 예쁜 스탠드.
스텐드 옆면에 예쁘게 그림을 그려서 본인이 자는 방에 가져다 두고는
"오늘부터 얘가 나를 지켜줄꺼야~"
ㅎㅎ
너무나 귀엽지 않습니까?
저녁이 되어 불을 켜보니
헐랭
정말 오던 잠도 달아날 것 같은 푸르스름한 조명이더군요.
그래서 바꿔주기로 하였습니다.
일단 조명 색상은 따뜻한 색상으로
밤새 켜져 있지 않도록 자동으로 소등될 것
요렇게 간단한 요구사항을 작성한뒤에 바로 실행에 들어갑니다.
필요한 재료는 간단합니다.
Attiny85 (아두이노를 사용하기는 아깝잖아요?)
1W LED (5000K 미만)
50uf 전해 콘덴서 (작은걸로)
전선 조금.
간단하죠?
우선 자동으로 소등이 되어야 하고 소등이 될때는 서서히 어두워 지는 것이 좋을 것 같아 먼저 테스트를 해보기로 하였습니다.
우선 Attiny 에 대하여 간단히 알아 보아야 하는데요. attiny 는 아주 작은 마이크로프로세서로 칩안에 부트로더, 디지털핀, 아날로그핀, PWM 핀을 모두 갖춘 환상적인 부품입니다. 전압만 적당히 주면 칩하나로도 왠만한 동작이 가능한 녀석입니다. 나중에 이녀석을 이용한 작품들을 좀 소개해 드리겠습니다.
소스코드를 업로드 하기 위하여 별도의 프로그래머가 필요하긴 하지만 아두이노를 이용하여 간단하게 프로그래머로 사용할 수 있는 방법이 있으니 걱정마시고 진행하시면 됩니다.
저는PWM 핀에 일정 시간이 지나면 서서히 전압을 감소 시킨뒤 0V 까지 떨어지면 Attiny85를 sleep 모드로 진입시켜 초절전상태가 되도록 할 계획입니다.
아두이노 ISP 만들기
아두이노를 ISP 와 같이 사용하여 Attiny85 를 프로그래밍 할 건데요. 간단합니다.
아두이노 예제에 있는 ArduinoISP 를 열어 주세요.
해당 소스를 본인의 아두이노 설정에 맞게 세팅한 뒤 업로드를 합니다.
그런 다음 10uf 전해 콘덴서를 하나 준비해주시고
Arduinoreset -- 콘덴서의 + , ArduinoGND -- 콘덴서의 - 를
연결한 뒤 Arduino 와 Attiny85의 각 핀을 아래와 같이 연결합니다.
Arduino 5V -- ATTiny85 Pin 8 (Vcc)
Arduino GND -- ATTiny85 Pin 4 (GND)
Arduino Pin 13 -- ATTiny85 Pin 8 (SCK)
Arduino Pin 12 -- ATTiny85 Pin 7 (MISO)
Arduino Pin 11 -- ATTiny85 Pin 6 (MOSI)
Arduino Pin 10 -- ATTiny85 Pin 1 (Slave Reset)
전 브래드 보드에 매번 연결하는 것이 귀찮아서 간단한 보드를 하나 만들었습니다.
위 사진과 같이 만들어서 소켓에 아두이노 나노와 attiny85 를 끼웠다 뺐다 할 수 있게 했습니다.
참고로 사진에 보이는 attiny85 는 smd 타입으로 dip 타입보다 작고 가격도 조금 저렴합니다. 저는 smd 타입에 8핀 보드를 붙여서 사용하고는 합니다.
일단 이러면 코드 테스트를 위한 준비가 완료 되었습니다.
코딩을 해보자!
// this code for enter sleep mode
#include <avr/sleep.h>
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
//setting variables
int ledPin = 0; // LED connected to digital pin 9
float timer = 2400;
float maxBrightness = 255.0;
float a = 0;
float curX = 0;
float curY = 0;
void setup() {
// 그래프의 기울기 값 계산
a = maxBrightness / (timer*timer);
}
void loop() {
curX++;
curY = a * (curX*curX);
analogWrite(ledPin, maxBrightness - curY);
if (maxBrightness - curY < 1 )
{
analogWrite(ledPin, 0);
system_sleep(); // sleep 모드 진입
}
delay(1000);
}
void system_sleep()
{
cbi(ADCSRA, ADEN); // switch Analog to Digitalconverter OFF
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here
sleep_enable();
sleep_mode(); // System sleeps here
sleep_disable(); // System continues execution here when watchdog timed out
sbi(ADCSRA, ADEN); // switch Analog to Digitalconverter ON
}
코드 위아래에 좀 눈에 익지 않은 코드가 있죠? 그 부분이 바로 sleep 모드 진입을 시키기 위한 코드입니다. attiny85 는 슬립 모드에 진입하면 놀라울 만큼 전기를 먹지 않기 때문에 아주 유용한 기능이 아닐 수 없습니다. sleep 모드에서 깨우기 위하여는 reset pin 에 GND 를 스위치 등으로 순간 연결해 주거나 전원을 껏다가 켜면 다시 최초 상태로 실행이 됩니다.
위에 타이머 부분이 전체 조명이 켜져있는 시간이되겠습니다. 다만 정확한 시간 조정은 안되고 대충 감으로 잡아야 하더군요. 현재 설정은 2400 초 인데요. 대략 40분 내외의 시간이 흐르면 소등됩니다. (한 30분 지나면 점점 어두워집니다)
loop 의 아래쪽에 현재 아날로그 출력값이 1보다 작아지면 sleep 모드로 진입하는 코드가 있고요.
그게 전부입니다. ㅋ
이제 attiny85 에 업로드를 해야하는데요.
먼저 라이브러리가 없다면 추가를 해주어야 겠죠?
구버전용 라이브러리는 직접 받으셔야 하고요. 신버전은 json 을 추가해주고 설치를 하면 됩니다.
이제 조명을 뜯어서 기존의 LED 를 떼어내고 Attiny 와 LED 를 부착해줄 차례 입니다.
당연한 이야기지만 먼저 배터리를 제거해 줍니다.
상단의 흰색 갓은 위로 잡아 당기면 그냥 빠집니다. 꽉 끼워져 있기는 한데 본드로 붙어있는 것은 아니더군요.
아래쪽 나사를 모두 풀어주고 분리하면 위와 같은 상태입니다. 심플하네요.
스프링이 도망가지 않게 살살 열어 줍니다.
어쨌든 문제의 LED는 제거합니다.
크기도 엄청 크네요.
스위치에 붙어 있는 저항도 필요 없으니 떼어낼겁니다.
Attiny 에 배터리 (약 4.5v) 를 연결하니 전압이 불안정한지 동작이 원하는데로 되지 않아 굴러다니는 전해 콘덴서를 하나 붙여 주었습니다. 저는 50uf 를 달아 주었는데요. 적당히 아무거나 달아도 될 듯 합니다. 크기가 작아 소켓보드 아래에 쏙 들어가네요. ㅎㅎ
예전에 사두었던 LED 가 적당해 보여 달아주었습니다. 불빛도 너무 노랗지도 않고 방열판도 있으니 적당하다 생각되었습니다.
본딩을 해서 붙인뒤 고정을 위해 일단 테이프로 붙여 둡니다.
자 이제 거의 다 되었습니다.
스위치에 있는 저항을 테어내고 전선을 연결할 겁니다. 스위치로 - 가 연결되고 스위치의 다른 한쪽이 attiny 의 GND 에 연결되면 됩니다.
빨간선은 + 이므로 attiny 의 5V 에 연결합니다.
쨔잔~ 네 예쁘게 잘 들어옵니다.
Attiny 는 3M 양면 테이프로 붙여주면 완성입니다.
참고로 위와 같이 배선하시면 안됩니다. 잘못 배선한 사진인데요. LED 로 가는 굵은 빨간선이 사진상 오른쪽 맨 아래 핀에 연결이 되어야 합니다. ㅜㅜ
아래 사진에는 다시 제자리에 납땜을 했습니다.
자 이제 완성입니다.
배선에 약간 오류가 있기는 했지만 간단한 문제로 바로 해결하였습니다.
최종 결과물은?
ㅋㅋ 처음과 똑같네요. 다시봐도 그림이 너무 예쁩니다.
어쨌든 이제 아이방에 놔주기만 하면 됩니다.
음~ 마음에 드는군요.
아이도 좋다며 매일 켜고 자고 있습니다. ㅎㅎ
자동으로 소등이 되니 배터리도 많이 먹지 않고요.
만약 사용해보고 배터리를 많이 먹는다 싶으면 저항을 하나 달아줄 계획입니다. 저항은 아주 작은 용량의 저항이면 됩니다.
자 간단한 작업으로 싸구려 같은 장난감에서 고급스러운 조명 색상에 타이머 기능까지 있는 멋진 조명으로 탈바꿈 하였습니다. 여러분도 한번 도전해 보시면 어떨까요?
이런 생각들로 인해 DIY 를 하더라도 목공이나 수예와 같이 분야를 한정하는 경우가 있는데요. 오늘은 간단한 전기 전자 부분에 대하여 소개를 해드릴까 합니다.
저는 관련 전공자도 아니고 (예체능 출신) 대학은 미대를 나왔으며 직장에서는 디자이너로 일하고 있으니 실제 전기랑은 전혀 관련이 없는 사람이지만 제가 하는 대부분의 DIY 는 전기를 통하지 않는 것이 없답니다.
그래서 오늘은 간단한 DIY 를 할 수 있는 수준의 전기 상식을 소개해 드리겠습니다. 그 이상은 저도 무리데스.
DC 와 AC
우선 DC 와 AC 라는 말이 많이 나옵니다.
DC 는 직류, +- 극이 존재합니다. 보통 배터리나 아답터에서 나오는 전기의 형태죠. 그리고 대부분의 전자 부품은 DC 에서 동작합니다. 그래서 우리는 DC 에 대하여 잘 알아야 합니다.
AC 는 교류, +- 극이 없습니다. 흔히 알고 있는 가정의 콘센트가 대표적인 교류 전기이죠. 가정용 교류 전기는 우리나라는 220V, 일본이나 미국은 110V 를 사용합니다. 해외에서 전자제품을 구입할 때는 전압을 바꿀 수있는 제품인지, 두가지 전압을 모두 사용할 수 있는지를 잘 확인해야 합니다. 어쨌든 교류는 DIY 에서는 그냥 뭐 거의 안쓴다고 보시면 됩니다. 위험하기도 하고 교류를 사용하는 부품도 없기 때문입니다. DIY 생활을 하며 교류 전기와 관련 있는 작업을 한다면 형광등 안정기 교체나 끊어진 전선 복구 정도가 되겠네요. 전구 가는 것 정도는 DIY 라고 하기에는 조금~ 그렇죠?
어쨌든 우리는 AC(교류)는 집어 치우고 DC(직류)만이라도 잘 알면 되겠습니다.
DC 의 특성
DC 전기는 전압, 전류, 저항 요 세녀석이 중요합니다. DIY 초보라면 무엇보다 전압이 가장 중요하죠. 제품마다 사용하는 전압이 다르므로 제품이 허용하는 전압을 정확히 아는 것이 중요합니다. 거의 대부분의 전자 부품은 허용 전압보다 높은 전압이 인가 되면 망가지게 되어있습니다. 심한경우 터질 수 있지만 그런 부품은 배터리 말고의 거의 없긴 하죠. 반대로 허용전압 보다 낮은 전압이 인가 되었을경우 고장나는 경우는 없으니 안심하셔도 됩니다.
집에 전자제품이 있는데 몇 V 용 인지 모르겠고 아답터가 3V 5V 6V 9V 12V 요렇게 있다면 3V 부터 순서대로 꼽아 보시면 됩니다.
허용 되는 전압은 제품마다 다 적혀 있습니다. 뒷면 라벨에 적혀있는 것이 대부분이지만 처음 제품과 함께 오는 DC 아답터를 보면 해당 제품이 사용하는 전압을 알 수 있으니 레벨에 적혀있지 않은 경우 안보이는 곳에 작게 메모해 놓으면 나중에 아답터를 잃어 버렸을 때 도움이 됩니다.
일반 적인 집안의 DC 전기는 대부분의 경우에 인체에 해롭지 않습니다. 만져도 느낌도 없죠. 하지만 자동차 배터리처럼 대전류를 흘려줄 수 있는 전원 공급 장치 (배터리)는 이야기가 다릅니다. 우리 몸은 전기를 아주 좋아하는(?) 성질이어서 전기를 끌어 당깁니다. 자동차 배터리의 전류는 치명적일 수 있습니다.
그럼 모든 DC 전선 또는 배터리의 +- 극을 손으로 만질 경우 과연 큰일이 날까요?
컴퓨터 파워 서플라이의 5V, 12V : 큰 문제 없음. (접제가 안되면 찌릿 할 수 있음)
일반적인 아답터 : 문제 없음 (경험상).
전동 킥보드 배터리 : 문제 있음
자동차 배터리 : 큰 문제 있음
1.5V 건전지 : 먹지만 않으면 됨
회색 케이스 또는 봉지 같은 것에 들어있는 핸드폰, 드론 배터리 : 칼로 찌르지만 않으면 됨 --> 배가 불룩한 경우 얼릉 1층 배터리 수거함으로 ㄱㄱ
동그란 18650 배터리 : 만져도 됨, 단 전선으로 +- 를 바로 연결하면 안됨
수은전지 (수은은 없지만) : 먹지만 않으면 됨
DC 전기는 +-가 존재하는데 이게 바뀌어 연결되면 역시 대부분의 전자 부품에 치명적인 피해를 입힙니다. 그래서 아래와 같이 여러가지 방법으로 +- 를 구분하여 표시하고 있습니다.
[배터리]
1.5v 건전지라면 볼록한 부분이 +, 단추형 전지 (일명 수은전지) 라면 평평하고 글씨가 써있는 부분이 +, 선이 있는 배터리라면 빨간 선이 +,
다리가 긴쪽이 +, 안이 보이는 LED 라면 내부에 면적이 넓적한 쪽이 -, 위에서 봤을때 한쪽면이 살짝 깍여서 납작하다면 납작한 쪽이 - 입니다.
참고로 LED 는 그 자체로 다이오드인데요. 다이오드는 전기가 역으로 흐를 수 없도록 만든 장치이므로 +- 를 반대로 연결해도 고장나지 않습니다.
DC 라면 언제나 강렬한 색상이 +, 검정, 회색과 같이 탁한 색이 - 입니다. 물론 제조 업체에서 맘대로 조립하는 경우도 있으므로 테스터기를 통해 확인 한번 쯤 해보시는 것을 추천 드립니다.
안쪽이 거의 대부분의 경우에 + 입니다. 바깥쪽 감싸고 있는 부분이 - , 반대의 암놈 짹도 마찬가지, 가운데 튀어나와 있는 심이 + 입니다. 연결 하실때는 뒷부분으로 나온 단자가 + , 아래로 내려온 단자가 - 인데요, - 의 경우 두개가 나와있는 경우가 있습니다. 보통 아래쪽 단자를 이용하시면 됩니다.
극성이 없는 부품이 있다?
네 그렇습니다. 회로에 사용하는 부품이 모두 극성이 있는 것은 아닙니다. 대표적으로 저항이 그러한데요. 저항은 극성이 없기 때문에 어떻게 연결해도 상관이 없으며 LED 같은 경우 + 쪽에 연결하거나 - 쪽 어느곳에 연결해도 문제가 되지 않습니다.
요즘은 구하기 힘든 꼬마전구나 할로겐 램프도 극성이 없습니다. 그냥 아무렇게나 연결해도 됩니다.
캐패시터라 불리우는 부품도 전해 캐패시터를 제외하면 극성이 없습니다. 캐패시터는 다음 포스트에서 조금더 써 볼께요.
전압, 전류, 저항에 대하여
자 그럼 전압, 전류, 저항 은 무었이냐.
비유하여 설명해 보자면 호스를 통해 공급되는 물과 비교해서 설명을 드려보겠습니다. (실제 전문적인 전기 지식은 아닙니다. 경험에 따른 비유이므로 딴지 노노)
먼저 호스를 통과하는 물의 속도를 전압이라고 생각하면 되고요, 호스의 굵기를 전류라고 생각하시고, 호스의 중간에 있는 밸브를 저항이라고 보면 되겠습니다.
전압이 높고 전류도 높다 : 소방호스 처럼 엄청난 속도에 굵은 물줄기 입니다. 위험하겠죠?
전압이 낮고 전류도 낮다 : 링거 줄 처럼 얇은 관을 물이 아주 천천히 졸졸졸 흐르는 상태입니다. 안전하겠죠?
전압이 높고 전류는 낮다 : 링거 줄 처럼 얇은 관이지만 물의 속도가 아주 빠르다면? 큰 부상은 없겠지만 따끔하겠죠?
전압이 낮고 전류는 높다 : 물이 천천히 나오기는 하지만 그 호스 굵기가 굵다면 감당하기 힘들겠죠?
뭐 이런식입니다. 중간에 밸브가 달려 있다면 물의 압력이 줄어들게 될 건데요. 결과적으로는 호스 전체에 흐르는 물이 줄어 들게 됩니다.
그런데 물에 비유했을 때 한가지 차이점은요. 보통 물은 물의 압력이 밀어 낸다고 생각되는데요, 전기는 끌어 쓴다고 보시면 됩니다. 전기를 사용하는 쪽이 전원부에서 제공 가능한 최대한의 양을 끌어 당기는 것이지요. 전기를 공급해주는 쪽에서 아무리 많은 전류를 흘려 줄 수 있다고 해도 사용하는 쪽으로 전류가 조금만 흐르도록 조절하면 전류는 조금밖에 흐르지 않습니다.
마치 필요한 만큼의 물을 퍼올릴 수 있는 고급 양수기로 물을 퍼올리는 것과 비슷한데요, 파워 서플라이가 양수기라면 용량이 큰 양수기로 화단에 물을 주는것은 쉬운 일이지만 용량이 작은 양수기로 수영장에 물을 받는 것이 어려운 것과 같다고 볼 수 있겠습니다. 말그대로 파워 서플라이(공급자) 아닙니까? 자 이제 우리가 여기서 알아야 할게 바로 이 양수기에서 퍼올리는 물중에 실제 필요한 만큼만 화단에 뿌려지도록 회로에서 전류가 조금만 흐르게 하는 방법 입니다.
어쨌든 위의 내용을 보면 전원 공급 장치를 고를때는 일반 적인 경우에 공급 전류가 큰 것을 구입하는 것이 좋습니다. 만약 공급은 조금밖에 못하는데 끌어 쓰는 녀석이 전기를 많이 사용하면(최대한으로 장시간 사용하면) 열이 심하게 나거나 아답터가 고장이 나게 됩니다. 보통 큰 전류를 전달하는 파워서플라이는 가격이 비싸기 때문에 일반적으로는 제품에 딱 맞는 수준의 전류를 보낼 수 있는 전원 공급 장치를 제품에 포함하여 제공하게 됩니다.
DIY 용으로 사용할때 모터나 전열기를 사용한다면 2A 이상, LED나 간단한 센서를 이용한다면 아주 작은 500mA 도 충분 합니다.
참고로 전력량을 표시하는 단위는 W(와트) 입니다. W 는 전압과 전류를 곱한 값 입니다.
20W 를 사용하는 전자제품에 5V 가 적용되면 해당 제품에 흐르는 전류량은 20W / 5V = 4A 인 것이죠. 반대로 5V 에 0.2A 를 사용하는 전자제품의 전력량은 5V x 0.2A = 1W 가 되는 겁니다.
통상 사용되는 0.25W LED 의 허용 전압이 3V 라고 하면 해당 LED 의 허용 전류는 0.25W / 3V = 0.083A = 83mA 가 됩니다. 다시 말하자면 정확한 허용 전류를 알기 위하여는 LED 구입시 반드시 사용 전력량과 허용 전압을 확인하셔야 합니다. 물론 모르면 적당히 붙여도 되긴 합니다. ㅋ
전류를 제어하는 가장 쉬운 방법 : 저항! 그리고 옴의 법칙!
중학교때 아마 옴의 법칙을 배우셨을 건데요. 식은 아래와 같습니다.
위의 세가지 식은 모두 다 똑같은 식입니다. 어떤 값을 구하느냐에 따라 편의상 치환하여 사용하는 것이죠.
계산 같은건 집어 치우고 개념만 알고 있으면 됩니다. 전류는 저항에 반비례하고 전압에는 비례한다. 즉 전압이 커지면 사용되는 전류도 많아집니다. 저항이 커지면 사용되는 전류도 작아지죠.
보통 LED 를 자동차에 연결할 때 저항을 달게 되는데 여기서 저항이 하는 역할이 바로 흐르는 전류를 줄여주는 역할을 하게 됩니다. 저항이 없다면 LED 는 자신이 끌어쓸 수 있는 최대 전류 이상을 땡겨 쓰고 장렬히 전사하는거죠. 다시 말하지만 12V 의 높은 전압이 인가되었기 때문에 LED 가 터지는게 아닙니다. 일반적인 LED 의 허용 전압인 3V 보다 4배나 전압이 높아졌기 때문에 흐르는 전류가 많아져서 LED 가 터지게 되는거에요. 전원 공급 장치에서 공급할 수 있는 최대 허용 전류가 모기눈꼽 만큼이라면 전압이 12V 가 아니라 24V 여도 LED 는 터지지 않습니다. 다만 그렇게나 미약한 전류만 흘려 줄 수 있는 전원 공급 장치라면 아마 손바닥보다 작은 태양광 패널 정도 일까요? 어쨌든 거의 없다고 보시면 됩니다. 즉 전압이 안맞다면 무조건 저항은 필수!
그럼 한번 예를 들어 볼까요?
흔히 자동차에 LED 를 이용하여 튜닝을 하시는 분들 많으시죠? 그런데 늘 걱정인게 바로 저항 구하는 방법일 거에요. 간단하게 자동차에 1W 를 사용하는 LED (3.3V용) 를 붙이려면 얼마의 저항이 필요할까요? 일단 허용 전류를 알아야 겠죠? 1W / 3.3V = 0.303A 가 되겠습니다. 그럼 필요한 저항 값은 옴의 법칙에 의해 저항(R) = 12V / 0.303A = 39.6옴 이 됩니다. 40옴 정도가 적당하나 LED 의 수명 연장을 위하여 흔히 구입할 수 있는 1W급 47옴을 부착해 주시면 되겠습니다. 물론 흔히 사용하는 0.25W LED 를 실내등 용으로 사용할 경우 위의 계산 식을 적용했을 때 144옴 이지만 구하기 쉬운 220 옴 정도의 저항을 붙여주시면 안전하게 무리없이 사용이 가능하게 됩니다. 실제 사용하시게 될 LED 의 스펙에 따라 계산 값이 달라질 수 있으니 참고만 해주세요~
딱 맞는 저항이 없다면 저항을 직렬로 연결하여 사용하는 방법도 있습니다. 47옴 짜리 저항을 나란히 3개 연결하면 이론적으로 141 옴이 됩니다. ^^ (물론 오차 때문에 딱 저 값이 나오지는 않겠지만요)
일반적인 회로부품은 자신에게 허용된 전류 이상을 소모하지 않도록 이미 안전장치가 칩안에 들어있습니다. 예를 들면 아두이노 우노가 12V 전압을 사용할수 있는데요. 위에서 언급했던 대전류 파워인 자동차 배터리 12V 를 연결한다고 해서 터지거나 하지 않습니다. 이미 아두이노 나노 안에 자신이 사용하는 전류 이상이 흐르지 않도록 보호회로가 구성되어있기 때문이죠. 그러니 걱정 마시고 사용하셔도 됩니다. (아두이노의 허용 전압은 6~20V, 그렇다고 20V 에서 버티는지 실험은 하지 말자)
오늘 포스팅은 여기까지 마치기로 하고요.
다음 포스트에서 각종 부품을 연결하는 방법과 테스터기를 이용하여 여러가지 테스트를 하는 방법을 소개해 드리겠습니다.
궁금한 것은 뎃글로 질문해주시고요, 전문적 내용에 문제가 있는 부분은 지적 부탁드리겠습니다~
본격적으로 캠핑의 계절이 왔습니다. 야외에서 침낭이 없어도 춥지 않은 환상적인 날씨죠. 이제 가을까지 계속 캠핑하기 좋은 날이 이어질거라 믿습니다. 그래서 이것저것 캠핑용품을 구입하였는데요.
문제는
차에 안들어 간다는 것입니다. i30cw 의 트렁크가 작지 않다고 믿었지만 ... 무리데스. -_-;;
위의 사진에추가로 구입한 물품이
야전텐트 2개, 캠핑의자 2개, 자충식 에어 매트리스 가 되겠으며 이제 여름이니까 여름 물놀이 용품과 보트, ....
... (-_-)>"
그래서 차량용 루프박스를 구입하기로 마음 먹었습니다.
우선 여러가지 제품을 살펴보았는데요. 단연 THULE 제품이 눈에 들어오더군요. 많은 사람들에게 인기가 있는건 다 이유가 있는 것이지요. 유럽에서 안전 인증도 받았을 뿐더러 디자인이 정말 너무나 예쁩니다. 하지만 문제는 가격이죠. 마음에 든다 싶으면 100만원이 훌쩍 넘어가더군요. 결재 버튼에 손이 몇번이나 갔는지 모르겠습니다.
어쨌든 구입을 망설이며 며칠을 루프박스를 검색하며 알아본 결과 중요한 포인트를 몇가지 알게 되었습니다.
차량용 루프박스 선택 시 체크해야 할 사항 (중요)
내 차량에 루프레일 / 루프랙이 달려있는가?
기본 장착 구조가 아니라면 별도로 장착하기 위한 구조로 설계가 되어있는가?
루프박스의 높이가 생각보다 높다. 가로바와 루프박스 설치를 완료한 높이가 2.1 m 를 넘는가? (건물 지하주차장 최소 진입 높이가 대부분 2.1m라고 합니다.)
루프 박스의 잠금 방식은 안전한가?
과연 내차에 올라가는 사이즈(길이, 폭) 인가? (생각보다 루프박스가 큽니다. 길이가 2m 가 훌쩍 넘는 제품도 있지요)
열리는 방향은 양쪽으로 다 열리는가?
뚜껑이 견고한 플라스틱으로 이루어져 있는가? (재질, 두께)
적어도 이 정도의 검토를 하고 구입을 하는 것이 후회를 하지 않습니다. 인터넷에 찾아보면 주차장 진입시 루프박스가 부딪혀 박살난 이야기들을 종종 찾아볼 수 있는데요. i30cw 의 경우 워낙 오래된 차여서인지 생각보다 정보가 없더군요. 어떤 제품을 사야할지 많이 고민이 되었습니다.
i30cw의 경우 일단 SUV 보다는 차고가 낮으니 선택의 폭은 좀 넓어 지겠으나 루프랙 자체의 높이도 있고 하니 최소한의 높이가 되는 조합을 찾기로 하였습니다.
그런데 루프박스의 높이가 낮아지면 가격은 올라가는 것을 아시나요? 얇은 루프박스들은 정말 많이 비쌉니다.
일단 제차는 높이가 낮으니 조금은 선택의 폭이 넓어진 셈 입니다. 중대형 SUV 였다면 아마 눈물을 머금고 비싸고 얇은 루프박스를 구입했어야 하겠죠.
제 차량에 과연 루프박스가 문제 없이 올라갈까 싶어 포토샵으로 시뮬레이션도 해보았습니다.
가로바의 선택
높이를 낮추기 위해서는 가로바를 휘습바 라는 제품을 설치하는 것이 좋습니다. 물론 루프랙이 있는 차량의 이야기 입니다. 휘습바는 루프랙 안쪽으로 설치가 가능한데 좌우로 가로바가 튀어 나오지 않아 깔끔한 외관을 보이고 높이도 장착할 수 있는 최저 높이가 되므로 아주 적당한 솔루션이 되겠습니다. 툴레와 야키마의 제품이 유명한데 가격이 만만치 않습니다. 국산 유일 캐리어에서는 휘습바는 나오지 않지만 루프랙에 장착할 수 있는 고급형 가로바의 거의 두배에 가까운 금액이 필요합니다. 이것도 고민이 되는 부분입니다.
하지만 결국 저는 유일 캐리어의 가로바를 최종 선택하였는데요. 아무래도 국산 제품이며 제품에 대한 신뢰도가 생각보다 높았습니다. 만약 루프박스도 생산하였다면 유일 캐리어 제품을 고민 했을 지도 모릅니다.
어쨌든 제가 구입한 가로바는 유일 캐리어의 YI-127WB 제품을 구입하였습니다. 참고로 YI-127 은 가로바 아래쪽에 루프랙과 고정되는 부품(풋) 의 제품명이며 WB 는 윈드 블레이드?? 정도로 구분되는 제품명으로 보여집니다. 어쨌든 제품이 튼튼해 보이고 디자인도 유려하였으며 (툴레 못지 않게) 가로바의 단면 형상이 공기 저항에 최적화된 '에어로 바' 를 제공하므로 툴레와 비교하여도 부족할 것이 없었습니다. 다만 휘습바에 비하여 높이가 높아지기 때문에 루프박스 선택에 야간의 고민이 늘게 되었습니다.
설치는 직접 하는 것으로 하고 인터넷으로 구입하니 툴레 제품의 반값 밖에 안되더군요.
또 나중에 차량을 바꿔 루프랙이 없는 차량이라도 풋만 따로 구입이 가능하므로 풋만 구입하면 바로 재사용 할 수 있겠다 싶었습니다.
유일 캐리어 가로바는 이틀만애 배송 완료.
루프박스 선택
어쨌든 가로바를 먼저 구입하고 나서 루프박스를 살펴보았습니다.
처음엔 THULE 에서만 고르다가 인터넷에 찾아보니 가성비 루프박스들이 많이 소개되어 있었습니다. 하지만 국내 루프박스의 3대장 하면 결국 THULE, Hapro, Yakima 요렇게 3가지로 압축 되더군요. 중국산 제품은 일단 믿음이 잘 안가고 심지어 많이 알려진 제품의 경우 가격도 그다지 저렴하지도 않았습니다.
결국 안전성, 디자인, 가격 모두 합리적이다 판단된 Hapro 브랜드로 선택의 폭이 좁혀졌고 그 중에 제니스, 트랙서로 압축이 되었습니다.
제니스는 높이가 비교적 낮고(37cm) 디자인이 훌륭합니다. 하지만 가격이 비싼게 걸렸습니다. 가장 큰 사이즈인 8.6 의 경우 100만원이 훌쩍 넘는 가격이어서 포기, 6.6 역시 가격에 있어서는 큰 차이가 없었습니다.
트랙서 제품은 70만원대에 가격이 형성되어 있고 6.6 으로 사게 되면 크기도 적당해 보여 해당 제품으로 구입해야 겠다 마음을 먹었습니다. 높이가 제니스에 비하여 약간 높지만(43cm) 설마 2.1m 가 넘겠나 싶었습니다. 결국 인터넷에서 검색되는 최저가로 구입을 하였습니다. 물론 최저가는 60만원대 초반에 올라와 있더군요.
그런데 이게 왠일 인가요.. 판매자가 갑자기 물건이 없다며 환불을 해버린 것 입니다. 어의가 없었지만 재고가 없다니 어쩌겠습니까... 그렇게 구매에 실패하고 나니 좀 현실감이 생겼습니다. 중고도 한번 알아볼까?
결국 중고나라를 며칠 뒤적거린 후 아주 마음에 드는 녀석을 발견!! 판매자 분과 바로 약속을 잡고 두근거리는 마음을 안고 퇴근길에 올랐습니다.
바로 제니스 8.6 을 구입할 설렘을 안고 말이지요. ㅋㅋ
유일캐리어 가로바 직접 설치하기!
집에오자 마자 저녁을 입으로 먹었는지 코로 먹었는지 모릅니다. 숟가락을 놓자마자 중고거래를 위하여 미리 사놓은 가로바를 부랴부랴 설치합니다.
가로바 설치는 처음해보았는데요. 유일 캐리어에서 설치하는 메뉴얼을 영상으로 제작해 주어 아주 쉽게 따라할 수 있었습니다. 손재주 좋으신 분은 혼자서도 20분이면 충분히 설치할 수 있을 것 같습니다.
순서는 다음과 같습니다.
가로바 상단에 고무 마개 씌우기 끝까지 딱 맞게 끼우시면 됩니다. 고무 길이가 가로바 길이의 1/2 보다 조금 짧으므로 두개 끼우고 나서 하나는 끼우고 끝을 커터칼로 잘라주시면 됩니다.
하단 양쪽에 풋이 들어갈 부분에 밀어주는 마개가 있는데요. 안쪽으로 밀어줍니다.
풋을 박스에서 꺼내서 나사를 풀어 아래쪽을 좀 벌려준 후 양쪽에 하나씩 끼워줍니다. 안쪽으로 여유있게 넣어 둡니다.
반듯하게 들고 이동하여 루프랙 위에 얹어봅니다.
한쪽씩 풋의 위치를 조정하여 루프랙에 고정 부분이 끼워지도록 위치합니다. (양쪽 모두)
줄자를 가져와서 좌우 길이가 동일해 지도록 맞춥니다.
다른 한세트를 동일하게 조립해서 역시 루프랙에 위치하고 길이를 맞춥니다.
가로바와 가로바 사이의 길이를 최소한 550mm 이상으로 벌려서 조임 나사를 돌려 본격적으로 고정을 합니다. 이때 루프랙의 끝부분으로 부터 거리를 잘 확인하셔서 양쪽이 동일한 위치에 자리잡도록 확인해 주셔야 합니다. 그리고 약간 앞 쪽으로 위치시켜야 나중에 루프박스를 올렸을때 트렁크와의 간섭이 안생깁니다.
네군데 나사를 모두 조여줍니다. YI-127 제품은 별도의 공구 없이도 손으로 나사를 조일 수 있게 되어 있으니 설지 작업이 매우 편리한 편 입니다.
아까 안쪽으로 밀어 두었던 하단부 마개를 풋에 딱 맞도록 다시 당겨서 맞춥니다.
가로바 양쪽에 플라스틱 마개를 덮고 동전 등을 이용하여 잠금장치를 잠그어 줍니다. 4군데 모두
풋의 덮개를 덮어주기 전에 네군데 모두 확실하게 조여질 수 있도록 한번더 확인합니다.
풋의 덮개를 덮고 열쇠로 잠그면 설치 완료!
글로 설명하려니 장황하지만 직접 해보시면 간단한 작업이고요. 옆에서 누가 도와주면 정말 쉬운 작업입니다.
디자인도 굳!
자 이제 머리 올리러 출발!
i30cw 에 215cm 의 제니스 8.6 루프박스가 거뜬히 올라가다.
직접 만나서 거래를 하고 판매자 분과 함께 제차에 올려보며 크지는 않은지 확인까지 하며 중고 거래를 마쳤습니다. 생각보다 크지 않더군요. 사이즈가 아주 마음에 듭니다. 판매자 분도 6.6으로 구입했으면 후회했을거라 하시더라구요. 짐 들어가는게 많이 차이가 난다고 합니다.
색상도 제 차량과 잘 어울립니다. 진회색인 제 차량과 카본 실버 색상이 톤이 비슷하여 깔끔하고 예뻐 보입니다.
가로바도 마칭 600mm 정도로 간격을 벌려놨기 때문에 루프박스가 바로 올라갑니다. 전 주인분께서 친절히 설치를 도와 주셨고요, 고정장치를 손으로 돌려 고정하기 때문에 별도의 장비도 필요가 없었습니다.
라고 생각하시겠지만 아이들을 키우다 보면 생각보다 음악 CD 를 재생할 일이 많이 있습니다. 동화책 같은 곳에 딸려오는 CD 도 있고요, 영어 교재나 음악 교재 등에도 여전히 CD 로 음악을 담아 배포하는 경우가 흔하답니다. 저역시 지금 사용하는 노트북은 CD 롬 드라이브가 장착이 안되어 있을 정도로 중요하다고 생각하지 않았습니다.
어쨌든 당장 CD 음악을 들어야 하는 상황이 되니 당황스럽더군요. 그래서 온라인으로 USB 타입 외장형 CD-ROM 을 하나 구입하였습니다.
그런데 구형 미디어의 불편함이랄까요? 요즘은 음악을 듣고 싶으면 유튜브나 멜론 같은 스트리밍으로 언제 어디서든 음악을 들을 수 있지만 제가 구입한 외장형 CD 만 하더라도 장착하고 CD 를 넣고 재생될때 까지 기다리고 하는 과정이 생각보다 귀찮아서 CD 안의 음악을 꺼내야겠다 생각이 들었습니다.
그래서 적어도 노트북에 꺼내 놔야 겠다 생각을 하게 되었던 것이죠.
CD-ROM 드라이브를 윈도우 탐색기를 통해 열어보면 아래와 같은 모습입니다.
이것 때문에 아내가 저에게 복사가 안된다며 이야기를 건냈습니다.
저역시 열어보고 살짝 당황했는데요.
사실 윈도우 미디어 플레이어에 기본으로 지원하는 기능 중에 음악 파일을 라이브러리로 꺼내는 기능이 있습니다.
먼저 CD를 재생할 플래이어를 윈도우 미디어 플레이어로 지정해 주어야 합니다.
미디어 플레이어가 실행되면 아래와 같은 모습이 되겠죠.
그럼 우측 상단에 보이는 네모네모 아이콘을 클릭해 줍니다.
그럼 아래와 같이 미디어 라이브러리가 보이게 됩니다.
아래 그림의 빨간 네모 박스를 선택하셔서 내 컴퓨터로 가져올 음악을 모두 선택해 줍니다. 물론 개별로 선택하셔도 됩니다.
아래 사진의 CD 복사를 눌러줍니다.
그럼 아래 그림처럼 선택된 음악 파일이 하나씩 하나씩 컴퓨터로 복사되기 시작합니다.
그럼 복사된 파일은 어디에 저장이 될까요?
바로 라이브러리 - 음악 폴더에 저장이 된답니다.
간단하죠?
참고로 복사설정을 누르시면 복사할 파일의 음질이나 포멧 등에 대하여 선택이 가능하므로 원하는 설정을 먼저 골라준 뒤 복사를 진행해도 되지만 이것저것 잘 모르겠으면 그냥 CD 복사 를 하셔도 무방합니다.
어렸을적 위대한 발명가, 과학자 하면 단연 손꼽는 일인자가 있었는데 누군가 물어본다면 100 이면 100 다 토마스 에디슨을 떠올릴 것입니다.. 그런데 커보니 에디슨은 발명가나 과학자라기보다는 사업가에 가까운 사람이었고 정반대 편에 니콜라 테슬라라는 진정 위대한 과학자가 존재함을 알게되었습니다.
테슬라의 위대한 발명품중에 단연 인지도 최강 아이템.
바로 테슬라 코일 되시겠습니다.
제가 과학도도 아니고 테슬라코일의 원리나 구조에 대해 이야기할건 아니고요. 알리익스프레스에서 2000원 정도의 저렴한 가격에 구입할 수 있는 킷이 있어 구입을 해 보았습니다.
일단 배송비가 있어 2세트를 주문 했는데 배송비까지 모두 해서 5000원 정도에 구입을 하였습니다.
약 1달여가 지나 도착했고.... 아래와 같이 포장이 되어 있었습니다.
그냥 비닐백에 싸여 왔습니다. 물론 알리 특유의 회색 비닐백안에 들어있었습니다.
음.. 좀 조잡한데?
부품은 별거 없습니다만.... 별도의 조립 설명서 같은건 없군요...
음... 조립 설명서가 없다라...
보드에 뭔가 적혀있는 것을 자세히 봤습니다.
음.. 대략적으로 감은 오는데...
네 어려울 건 없네요.
그냥 생긴데로 끼우면 되는거였습니다.
딱히 잘못 조립할 수있는 유일한 부품은 LED 군요.
다행인건 보드에 표시가 되어 있고 LED 의 극성을 구분하는 것은 쉬운 일이니까요. LED 안쪽을 자세히 보면 핀과 연결된 부분이 보이는데 넓은 면이 - 입니다. 다리 길이로 보면 긴쪽이 + 가 되지요.
그레서 바로 조립해 보았습니다.
조립하는데에는 15분도 걸리지 않습니다. 제가 어렸을 적 라디오 키트 조립 같은게 유행했었는데 말이죠. 그 시절의 저였다면 초등학생이지만 가능한 간단한 조립입니다.
참고로 코일 원통에 선이 위로 한가닥 아래로 한가닥이 나오는데요. 보드에는 T 라고 써있는 부분에 한가닥만 연결하시면 됩니다.
다른 한가닥은 바로 스파크를 내뿜는 곳이죠.
그리고 코일통과 보드는 따로 고정해줄 수 있는 구조가 없기 때문에 실리콘이나 본드로 붙이셔야 합니다.
저는 E7000 본드로 고정을 해주었습니다.
어쨌든 2개를 샀으니 하나는 아들내미에게 기회를 한번 줘 볼까 합니다.
드디어 조립완료
굴러다니는 12V 아답터를 연결해주니 안쪽의 LED가 켜지면서 동작이 되네요. 가운데 보이는 스위치로 껏다 켰다 할수도 있습니다.
자 이제 테슬라코일임을 즐겨야겠지요?
동봉되어 있는 부품중에 할로겐 전구 같은 전구가 하나 있습니다.
그 전구가 바로 테스트용 전구인데요. 테슬라 코일을 동작시키로 가까이 가져가면 불이 켜지는것을 테스트 해보기 위한 재료입니다.
두구두구
드디어 사진이나 영상으로만 보던걸 제 손으로 해보는 군요.
두구두구두구..
쨔쨘~ ㅋㅋ
올~~
진짜 되는군요.
그럼 진짜배기 테스트를 해봐야 겠지요?
형광등을 하나 준비합니다. 굴러다니는 삼파장 등이면 됩니다.
두구두구
올~~~~
ㅋㅋㅋ
정말 재미있네요.
내일은 아이들에게 신기한 장면을 좀 보여주어야 겠습니다.
상단에 코일 끝부분에서 스파크가 나오는데 ... 음.. 사진이 제대로 찍힌게 없어서 올리지는 못하겠네요.
나중에 제대로 나온 사진이 있으면 본 포스트에 추가하도록 하겠습니다.
오늘도 재미있는 놀거리를 하나 만들었습니다. 만들기도 쉽고 가격도 저렴하고요. 아이들과 니콜라 테슬라라는 과학자에 대한 이야기를 나누어 볼수도 있겠네요.
이제는 콤보박스의 선택정보가 변경될 때 시리얼 포트가 열려있지 않다면 포트이름과 설정을 지정해 주고 열도록 하겠습니다.
UI 메뉴에서 콤보 박스를 더블클릭하면 함수가 자동으로 생성되는데요. 만들어진 함수에 아래와 같이 코드를 작성하시면 됩니다.
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (mySerial.IsOpen) // 특정 포트가 이미 열려 있다면 설정이 되지 않기 때문에 우선 닫는다.
{
mySerial.Close();
}
if (!mySerial.IsOpen) //시리얼포트가 닫혀있을 때만
{
mySerial.PortName = comboBox1.Text; // 선택된 combobox 의 이름으로 포트명을 지정하자
mySerial.BaudRate = 9600; //아두이노에서 사용할 전송률를 지정하자
mySerial.DataBits = 8;
mySerial.StopBits = StopBits.One;
mySerial.Parity = Parity.None;
mySerial.Open(); //시리얼포트 열기
}
else
{
MessageBox.Show("해당포트가 이미 열려 있습니다.");
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;
namespace csharp2arduino_serial
{
public partial class Form1 : Form
{
private SerialPort mySerial;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
mySerial = new SerialPort();
comboBox1.DataSource = SerialPort.GetPortNames();
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (mySerial.IsOpen)
{
mySerial.Close();
}
if (!mySerial.IsOpen) //시리얼포트가 닫혀있을 때만
{
mySerial.PortName = comboBox1.Text; // 선택된 combobox 의 이름으로 포트명을 지정하자
mySerial.BaudRate = 9600; //아두이노에서 사용할 전송률를 지정하자
mySerial.DataBits = 8;
mySerial.StopBits = StopBits.One;
mySerial.Parity = Parity.None;
mySerial.Open(); //시리얼포트 열기
}
else
{
MessageBox.Show("해당포트가 이미 열려 있습니다.");
}
}
private void button1_Click(object sender, EventArgs e)
{
// 텍스트 박스 추가한 버전
string myMsg = textBox1.Text;
if (myMsg != "")
{
myMsg += "\n";
}
else
{
myMsg = "Hello Arduino?\n";
}
byte[] datas = StringToByte(myMsg);
mySerial.Write(datas, 0, datas.Length);
}
private byte[] StringToByte(string _str)
{
byte[] tmpBytes = Encoding.UTF8.GetBytes(_str);
return tmpBytes;
}
}
}
아두이노에서 시리얼 메시지 받기
아두이노에서 시리얼 메시지를 받는것은 사실 매우 쉽습니다. 아두이노 기본 예제 중에 Serial 을 사용하는 것을 많이 보셨죠? 아두이노는 Serial 을 사용하기 위하여 별도로 설정할것이 거의 없습니다.
아두이노를 열어 주시고 아래와 같이 코드를 작성합니다.
String myStr = "";
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
}
void loop() {
if(Serial.available()){//시리얼에 데이터가 있다면
char data = (char)Serial.read();//한 문자씩 읽어 문자형 변수에 담고
if((int)data != 10){ //개행문자 '\n' -> newline 이 아니라면 스트링에 계속 저장
myStr += data;
}else{
// \n 을 만나면 여기로 와서 문자열을 출력하면 된다.
// LCD 에 문자를 여기서 출력하면 됨
//그리고 문자열은 다시 초기화를 해주겠습니다.
myStr = "";
}
}
}
완전 간단하죠? 시리얼 신호가 들어오면 \n 이라는 줄바꿈 문자열이 오기 전까지 계속해서 한글자씩 문자열 변수에 추가를 해주었다가 \n 을 만나면 필요한 결과를 수행하고 원래 문자열 변수를 초기화 하는 것이죠.
아두이노로 통합(만능) 리모콘 만들기 3/3 이라 쓰고 왠지 이번 포스트에서 끝나지 않을 것 같은 느낌이 강하게 듭니다. 지난 포스트에서 아두이노 IR 센서를 이용하여 신호를 해킹하고 또 필요한 신호를 따서 기록하는 것까지 소개해 드렸는데요. 해당 포스트는 아래 링크를 참고해 주세요.
이번 포스트에서는 본격적으로 SW 를 설계하고 HW 를 만들어가는 과정을 소개해 드릴까 합니다.
먼저 조사했던 여러가지 기능을 모두 소화하기에 아두이노의 입력핀은 너무 적기 때문에 기기 전환 버튼같은 기능을 두어서 버튼은 동일한 레이아웃을 가지고 아두이노의 동일한 핀으로 입력 신호가 들어가더라도 실제 출력해주는 IR 신호는 다르게 보내주는 방식으로 구현을 할 계획입니다.
필요한 재료
3cm x 7cm 양면 만능기판 (2.54mm 규격) x 2EA
아두이노 나노
Attiny85
SW-200D 진동/틸트 스위치 양쪽 다리형
Push switch (2pin) x 14 EA
LED (red, SMD) x 4EA
LED (green, SMD) x 1EA
5V DCDC Converter, Step Up Power Supply 보드
TP4056 18650 charge module
0.1F 전해콘덴서 (슈퍼콘덴서??) 꼭 필요한지 모르겠음
대충 33옴 정도되는 저항, 낮아도 별 상관 없음 (SMD LED 연결용)
IR LED (송신용) x 1EA
18650 배터리 1EA
SW 를 대충 설계해보자.
먼저 아두이노의 인풋, 아웃풋 키와 함께 각각의 기능을 매칭하는 테이블을 만들어야겠습니다. 아무래도 여러가지 기능이 동작되어야 하므로 나중에 실수하지 않으려면 각각의 입력핀에 연결될 버튼과 기능을 정의하는게 중요합니다.
위와 같이 각각의 기능을 테이블로 만들어 보았습니다. 가장 우측의 비고에 해당하는 열이 아두이노의 핀번호가 되겠으며 9~12번은 4개의 제품에 해당되는 LED 를 켜주기 위한 출력핀입니다. 18번은 제품전환용 버튼 입력핀이 됩니다.
제일 좌측에 S01~S14까지 번호가 있는데요. 이번호들은 각각 아래와 같은 형태로 배치할 계획입니다.
저는 양면 만능기판을 사용할 계획이고요. 만능기판의 끝부분에 단자용도로 사용할 수 있는 납이 붙어있어 그부분까지 일단 납땜을 하여 연결해 보기로 합니다. 중앙 상단의 네게의 흐릿한 동그라미가 LED 1234 와 연결이 되는 것이죠.
14개의 버튼은 모두 1개의 그라운드핀과 연결되며 나머지 한쪽 다리를 아래쪽 단자에 순차적으로 매칭을 시켜줍니다.
LED 역시 그라운드를 모두 한꺼번에 연결하고 아래쪽 LED 핀은 아두이노 디지털 출력핀과 연결해주어 선택된 제품에 불이 켜지도록 하겠습니다.
만능기판에 버튼을 실장한 사진은 아래와 같습니다.
총 14개의 버튼이 위와 같이 아름답게 배치됩니다. 만능기판의 크기를 생각해보면 아주 아담한 리모컨이 만들어 질 것 같네요.
아두이노 나노와 전원 공급 모듈
전원 입력은 3.7V 리튬이온 18650 배터리를 이용할 계획인데요. 아두이노가 5V 이상의 전압이 필요하기 때문에 5V 로 승압을 해주는 보드를 하나 장착이 필요하고요, 이 제품을 연속으로 사용하지 않을 경우 자동으로 전원 공급이 중단되도록 할 필요가 있을듯 하여 attiny85 를 이용하여 일정 시간이 지나면 전원 공급이 중단되도록 할 계획입니다. atiny는 sleep 모드라는 것을 지원하는데 sleep 모드로 들어가면 거의 전기를 먹지않는 놀라운 기능을 수행하게 됩니다.
다시 동작할때는 reset 핀에 GND 를 입력해주면 다시 동작을 시작하게 되는데 틸트 스위치를 이용하여 움직임을 감지하여 물리적으로 움직임이 발생되면 attiny85의 reset핀으로 신호를 보내줌으로써 attiny 가 전원 공급을 시작하는 것이죠. 이번 제작하는 리모컨 자체가 전류를 거의 사용하지 않기 때문에 문제는 없을 듯 하지만 그래도 attiny 의 디지털 출력핀이 충분한 전기를 공급할 수 있을지는 미지수입니다.
그래서 0.1F 정도의 콘덴서를 전원 공급용으로 하나 달아 보았습니다. ( 사실 전기/전자 지식이 매우 얕아서 저렇게 하면 되는지는 잘 모르겠어요)
그렇게 만들어진 보드가 바로 아래와 같이 만들어졌습니다.
위에서 설명드린 것처럼 우측 상단에 attiny85 가 자리잡고 있고요. (SMD 버전입니다) 중간에 검은 통이 틸트 스위치입니다. 약간 기울여서 달아주어야 평소에 눕혀져 있을때 신호가 끊어지기 때문에 기울여서 부착을 했고요, 아래 검은 네모박스가 0.1F 전해 콘덴서 입니다. 어디서 떼어낸건지는 기억이 안나는데 버리는 가전제품에서 떼어낸 부품입니다.
실제 아두이노 나노로 입력되는 전원은 전해콘덴서와 연결이 되어 있어 attiny 가 sleep 모드로 들어가더라도 일정시간 전원을 공급하여 주는 역할을 하게 됩니다.
우측의 단자부분은 이미 납땜이 마구 되어 있는데요, 위에 소개해드린 버튼부분과 연결이 되게 됩니다.
고난의 시작 ! 인정사정 없이 납땜시작
정말 납땜하다가 정신병 걸리는 줄 알았습니다.
왼쪽은 아두이노 나노를 포함한 메인 컨트롤 부, 오른쪽은 버튼 조작부와 LED 되겠습니다. LED 는 우측 끝에 매달려 있는데 잘 안보이시죠? 작은 회로기판 같은데 신호용으로 아주아주 작은 SMD 타입의 LED가 붙여 있는 것을 보셨을 텐데요, 고 녀석들을 떼어내서 부탁을 해주었습니다. 일부러 구입할일은 없으니까요.
각각의 선들은 위에서 설계한 것처럼 연결을 해주었는데 설계할때는 이게 이렇게나 복잡할거라고는 생각을 못했습니다.
위쪽에 보이는 작은 초록색 기판이 3.7 --> 5V 승압회로 , 그사이에 아주 작게 보이는 파란색 보드가 USB 전원을 이용하여 3.7V 배터리를 충전할 수 있는 충전 보드 입니다.
이렇게 하면 완전한 하나의 제품에 해당되는 부품을 모두 제작한 셈이 되겠네요.
위에서 보았던 두개의 보드는 위 사진처럼 접어서 조립할 계획입니다. 안쪽역시 매우 지저분하네요. 저렇게 만들어진 배선이 과연 잘 붙어있을까 궁금합니다.
두개의 보드 중간에는 절연을 위하여 얇은 실리폰 패드를 하나 넣어줄 계획입니다.
전원이 들어오게 되면 위사진과 같이 불이 켜집니다. 계획에는 LED가 4개였지만 메인 전원이 들어왔는지 여부를 판단하기 위하여 연두색 SMD LED를 하나 추가하였습니다.
코딩 시작!
자 순서가 좀 바뀐것 같지만 이제부터는 지루한 SW 코딩 부분입니다.
SW 구현할때 다음의 것들이 동작해야 하는 것이 중요합니다.
하나의 버튼에 의해 주어진 신호는 4개의 제품에 대한 신호를 보낼 수 있어야 한다.
마지막으로 사용한 제품을 기억했다가 다시 동작할때 세팅해준다.
신호가 한번에 입력이 안될 경우를 대비하여 연속으로 n번 보낼 수 있도록 구성한다.
뭐 별건 없습니다만 두번째에 해당되는 부분은 제가 처음해보는 관계로 저도 공부를 좀 했습죠.
EEPROM 을 사용해보자!
아두이노 나노에 사용되는 Atmega328 칩에는 무려 1kb 라는 비 휘발성 저장공간이 존재합니다. EEPROM 이라고 부르는데요, 프로그램이 저장되는 공간 외에 사용자가 데이터를 저장할 수 있는 공간말입니다.
무려 1kb 요.
-_-;;
1kb 라니.. 장난하냐..
싶겠지만 있는게 어딥니까?
이 저장공간을 이용하여 우리는 마지막 동작했던 제품의 정보를 기억할 건데요. 따지고 보면 차고도 넘치는 양이지요.
자 그럼 EEPROM 에 데이터는 어떻게 저장하고 읽어 들이는지 볼까요?
#include <EEPROM.h>
int sw_02;
int productIdx = 0; //0 : TV / 1: TV BOX / 2: BTV / 3: SPK
bool chkon = false;
//LED
const int L00 = 9; // TV
const int L01 = 10; // TV BOX
const int L02 = 11; // BTV
const int L03 = 12; // LONPOO SPEAKER
void setup()
{
pinMode(s02, INPUT_PULLUP);
productIdx = EEPROM.read(0); // EEPROM 에 저장된 제품의 번호를 불러오는 부분
}
void loop() {
sw_02 = digitalRead(s02);
// change product
if (sw_02 == HIGH) {
chkon = true; // 연속으로 눌리는 것을 방지하기 위하여 on 상태일때만 기기 변경이 되도록 한다.
ledON(productIdx);
}else{
if (chkon)
{
productIdx++;
if (productIdx > 3) productIdx = 0;
EEPROM.write(0, productIdx); // 이부분이 EEPROM 에 현재 제품의 번호를 저장하는 부분
chkon = false;
}
ledON(productIdx);
}
void ledON (int idx) // 선택된 인덱스에 맞게 LED 를 켜주는 함수
{
digitalWrite(L00, LOW);
digitalWrite(L01, LOW);
digitalWrite(L02, LOW);
digitalWrite(L03, LOW);
switch (idx) {
case 0:
digitalWrite(L00, HIGH);
break;
case 1:
digitalWrite(L01, HIGH);
break;
case 2:
digitalWrite(L02, HIGH);
break;
case 3:
digitalWrite(L03, HIGH);
break;
default:
break;
}
}
어렵지 않죠? 제일 위에 해당 라이브러리를 불러들여 주고요,
Setup 시에 저장되어 있는 값을 불러옵니다.
버튼은 눌렀을때 LOW 가 되도록 하고 항상 HIGH 한 상태를 만들어 줍니다. HIGH 한 상태가 되면 chkon 이 true 가되고 버튼이 눌렸을때 기기의 인덱스를 변경한 뒤 EEPROM 에 값을 저장하고 chkon 을 false 로 만들어 다음 신호를 기다리게 됩니다. 이렇게 하면 버튼을 연속으로 누르고 있어도 신호는 한번만 가게 되겠죠. 마지막으로 사용한 제품도 저장이 됩니다.
버튼 하나로 4개의 제품은 어떻게 제어를 할까요?
//setup, 변수 선언 등은 생략합니다.
void loop() {
if (sw_03 == HIGH) { //s03 은 전원 버튼입니다.
}else{
digitalWrite(13, HIGH);
press_S03(productIdx);
}
// 생략
}
void press_S03 (int idx) // power
{
switch (idx) {
case 0:
for (int i = 0; i < 1; i++) irsend.sendNEC(0x2DF10EF,32); // tv power
break;
case 1:
for (int i = 0; i < 1; i++) irsend.sendNEC(0x807F02FD,32); // tv box power
break;
case 2:
for (int i = 0; i < 1; i++) irsend.sendNEC(0x1FE807F,32); // Btv power1
break;
case 3:
for (int i = 0; i < 1; i++) irsend.sendNEC(0x40BF807F,32);
break;
default:
// statements
break;
}
}
바로 Switch 문을 이용하여 입력되는 idx 에 따라 각각 다른 신호를 보내주는 것이지요.
아래 press_S03 버튼이 바로 전원을 켜고 끄는기능을 담당하는 함수가 되는 것이죠.
저런 식으로 버튼 개수만큼 함수를 만들어 주면 됩니다. 좀더 효율적으로 코딩할수도 있겠지만 초보인 저에게는 저렇게 쉽게 코딩하는게 나중에 뜯어 고치지도 좋을 것 같아 이란 저런 방식으로 작성을 하였습니다.
포스트가 점점 길어지네요..
자 이제 전체 소스 갑니다.
중요한 내용은 위에 다 설명 드렸고 이전 포스트를 참고하시면서 내용 확인해 보시면 되고요. 꼭 저와 동일하게 만들 필요는 없으니 참고만 해주시면 됩니다.
길이가 대단하니 조심하세요~ ㅋ
#include <boarddefs.h>
#include <IRremote.h>
#include <IRremoteInt.h>
#include <ir_Lego_PF_BitStreamEncoder.h>
#include <EEPROM.h>
/*
* IRremote: IRsendDemo - demonstrates sending IR codes with IRsend
* An IR LED must be connected to Arduino PWM pin 3.
* Version 0.1 July, 2009
* Copyright 2009 Ken Shirriff
* http://arcfn.com
*/
/*
* tv (NEC)
* power : 0x2DF10EF, 32
* input : 0x2DFD02F, 32
* chnnel up : 0x2DF00FF, 32
* chnnel dn : 0x2DF807F, 32
* volumn up : 0x2DF40BF, 32
* volumn dn : 0x2DFC03F, 32
* OK : 0x2DF22DD, 32
* sw up : 0x2DF02FD, 32
* sw dn : 0x2DF827D, 32
* sw left : 0x2DFE01F, 32
* sw right : 0x2DF609F, 32
*
* android tv (NEC)
* power : 0x807F02FD, 32
* sw up : 0x807F6897, 32
* sw dn : 0x807F58A7, 32
* sw left : 0x807F8A75, 32
* sw right : 0x807F0AF5, 32
* sw OK : 0x807FC837, 32
* back : 0x807F9867, 32
* volumn up : 0x807F18E7, 32
* volumn dn : 0x807F08F7, 32
*
*
* lonpoo speaker
* power : 0x40BF807F, 32
* volumn up : 0x40BF50AF, 32
* volumn dn : 0x40BFD02F, 32
* bt : 0x40BFA05F, 32
* bt esc : 0x40BF906F, 32
* opt : 0x40BF20DF, 32
*
*
* LED
* tv : 9
* tv box : 10
* btv : 11
* spk : 12
*
* input
* s01
*
*
*
*
*/
#include <IRremote.h>
const int s01 = 0;
const int s02 = 18; // select sw
const int s03 = 1;
const int s04 = 2;
const int s05 = 19;
const int s06 = 4;
const int s07 = 5;
const int s08 = 6;
const int s09 = 7;
const int s10 = 8;
const int s11 = 14;
const int s12 = 15;
const int s13 = 16;
const int s14 = 17;
//LED
const int L00 = 9; // TV
const int L01 = 10; // TV BOX
const int L02 = 11; // BTV
const int L03 = 12; // LONPOO SPEAKER
//
// define sw value
int sw_01;
int sw_02;
int sw_03;
int sw_04;
int sw_05;
int sw_06;
int sw_07;
int sw_08;
int sw_09;
int sw_10;
int sw_11;
int sw_12;
int sw_13;
int sw_14;
//
int productIdx = 0; //0 : TV / 1: TV BOX / 2: BTV / 3: SPK
int addr = 0;
bool chkon = false;
IRsend irsend;
void setup()
{
pinMode(s01, INPUT_PULLUP);
pinMode(s02, INPUT_PULLUP);
pinMode(s03, INPUT_PULLUP);
pinMode(s04, INPUT_PULLUP);
pinMode(s05, INPUT_PULLUP);
pinMode(s06, INPUT_PULLUP);
pinMode(s07, INPUT_PULLUP);
pinMode(s08, INPUT_PULLUP);
pinMode(s09, INPUT_PULLUP);
pinMode(s10, INPUT_PULLUP);
pinMode(s11, INPUT_PULLUP);
pinMode(s12, INPUT_PULLUP);
pinMode(s13, INPUT_PULLUP);
pinMode(s14, INPUT_PULLUP);
pinMode(L00, OUTPUT);
pinMode(L01, OUTPUT);
pinMode(L02, OUTPUT);
pinMode(L03, OUTPUT);
pinMode(13, OUTPUT);
productIdx = EEPROM.read(0);
}
void loop() {
digitalWrite(13, LOW);
sw_01 = digitalRead(s01);
sw_02 = digitalRead(s02);
sw_03 = digitalRead(s03);
sw_04 = digitalRead(s04);
sw_05 = digitalRead(s05);
sw_06 = digitalRead(s06);
sw_07 = digitalRead(s07);
sw_08 = digitalRead(s08);
sw_09 = digitalRead(s09);
sw_10 = digitalRead(s10);
sw_11 = digitalRead(s11);
sw_12 = digitalRead(s12);
sw_13 = digitalRead(s13);
sw_14 = digitalRead(s14);
// change product
if (sw_02 == HIGH) {
chkon = true;
ledON(productIdx);
}else{
if (chkon)
{
productIdx++;
if (productIdx > 3) productIdx = 0;
EEPROM.write(0, productIdx);
chkon = false;
}
ledON(productIdx);
}
if (sw_01 == HIGH) {
}else{
digitalWrite(13, HIGH);
press_S01(productIdx);
}
if (sw_03 == HIGH) {
}else{
digitalWrite(13, HIGH);
press_S03(productIdx);
}
if (sw_04 == HIGH) {
}else{
digitalWrite(13, HIGH);
press_S04(productIdx);
}
if (sw_05 == HIGH) {
}else{
digitalWrite(13, HIGH);
press_S05(productIdx);
}
if (sw_06 == HIGH) {
}else{
digitalWrite(13, HIGH);
press_S06(productIdx);
}
if (sw_07 == HIGH) {
}else{
digitalWrite(13, HIGH);
press_S07(productIdx);
}
if (sw_08 == HIGH) {
}else{
digitalWrite(13, HIGH);
press_S08(productIdx);
}
if (sw_09 == HIGH) {
}else{
digitalWrite(13, HIGH);
press_S09(productIdx);
}
if (sw_10 == HIGH) {
}else{
digitalWrite(13, HIGH);
press_S10(productIdx);
}
if (sw_11 == HIGH) {
}else{
digitalWrite(13, HIGH);
press_S11(productIdx);
}
if (sw_12 == HIGH) {
}else{
digitalWrite(13, HIGH);
press_S12(productIdx);
}
if (sw_13 == HIGH) {
}else{
digitalWrite(13, HIGH);
press_S13(productIdx);
}
if (sw_14 == HIGH) {
}else{
digitalWrite(13, HIGH);
press_S14(productIdx);
}
delay(75); //5 second delay between each signal burst
}
void press_S14 (int idx) // vol -
{
switch (idx) {
case 0:
for (int i = 0; i < 1; i++) irsend.sendNEC(0x2DFC03F,32); // tv vol -
break;
case 1:
for (int i = 0; i < 1; i++) irsend.sendNEC(0x807F08F7,32); // tv box vol -
break;
case 2:
for (int i = 0; i < 1; i++) irsend.sendNEC(0x1FE42BD,32); // BTV box vol -
break;
case 3:
for (int i = 0; i < 1; i++) irsend.sendNEC(0x40BFD02F,32); // spk vol -
break;
default:
// statements
break;
}
}
void press_S13 (int idx) // chnl -
{
switch (idx) {
case 0:
for (int i = 0; i < 1; i++) irsend.sendNEC(0x2DF807F,32); // tv chnl -
break;
case 1:
//for (int i = 0; i < 1; i++) irsend.sendNEC(0x807F18E7,32); // tv box vol +
break;
case 2:
for (int i = 0; i < 1; i++) irsend.sendNEC(0x1FE827D,32); // Btv chnl -
break;
case 3:
//for (int i = 0; i < 1; i++) irsend.sendNEC(0x40BF50AF,32); // spk vol +
break;
default:
// statements
break;
}
}
void press_S12 (int idx) //vol +
{
switch (idx) {
case 0:
for (int i = 0; i < 1; i++) irsend.sendNEC(0x2DF40BF,32); // tv vol +
break;
case 1:
for (int i = 0; i < 1; i++) irsend.sendNEC(0x807F18E7,32); // tv box vol +
break;
case 2:
for (int i = 0; i < 1; i++) irsend.sendNEC(0x1FEC23D,32); // Btv vol +
break;
case 3:
for (int i = 0; i < 1; i++) irsend.sendNEC(0x40BF50AF,32); // spk vol +
break;
default:
// statements
break;
}
}
void press_S11 (int idx) // chnl +
{
switch (idx) {
case 0:
for (int i = 0; i < 1; i++) irsend.sendNEC(0x2DF00FF,32); // tv chnl +
break;
case 1:
//for (int i = 0; i < 1; i++) irsend.sendNEC(0x807F58A7,32); // tv box
break;
case 2:
for (int i = 0; i < 1; i++) irsend.sendNEC(0x1FE02FD,32); // Btv chnl +
break;
case 3:
for (int i = 0; i < 1; i++) irsend.sendNEC(0x40BF906F,32); // spk bt esc
break;
default:
// statements
break;
}
}
void press_S10 (int idx) // down
{
switch (idx) {
case 0:
for (int i = 0; i < 1; i++) irsend.sendNEC(0x2DF827D,32); // tv down
break;
case 1:
for (int i = 0; i < 1; i++) irsend.sendNEC(0x807F58A7,32); // tv box down
break;
case 2:
for (int i = 0; i < 1; i++) irsend.sendNEC(0x1FE52AD,32); // Btv down
break;
case 3:
//for (int i = 0; i < 1; i++) irsend.sendNEC(0x40BF20DF,32); //
break;
default:
// statements
break;
}
}
void press_S09 (int idx) // right
{
switch (idx) {
case 0:
for (int i = 0; i < 1; i++) irsend.sendNEC(0x2DF609F,32); // tv right
break;
case 1:
for (int i = 0; i < 1; i++) irsend.sendNEC(0x807F0AF5,32); // tv box right
break;
case 2:
for (int i = 0; i < 1; i++) irsend.sendNEC(0x1FE32CD,32); // Btv right
break;
case 3:
//for (int i = 0; i < 1; i++) irsend.sendNEC(0x40BF20DF,32); // tv box up
break;
default:
// statements
break;
}
}
void press_S08 (int idx) // ok
{
switch (idx) {
case 0:
for (int i = 0; i < 1; i++) irsend.sendNEC(0x2DF22DD,32); // tv ok
break;
case 1:
for (int i = 0; i < 1; i++) irsend.sendNEC(0x807FC837,32); // tv box ok
break;
case 2:
for (int i = 0; i < 1; i++) irsend.sendNEC(0x1FE629D,32); // Btv ok
break;
case 3:
//for (int i = 0; i < 1; i++) irsend.sendNEC(0x40BF20DF,32); // tv box up
break;
default:
// statements
break;
}
}
void press_S07 (int idx) // arrow left
{
switch (idx) {
case 0:
for (int i = 0; i < 1; i++) irsend.sendNEC(0x2DFE01F,32); // tv left
break;
case 1:
for (int i = 0; i < 1; i++) irsend.sendNEC(0x807F8A75,32); // tv box left
break;
case 2:
for (int i = 0; i < 1; i++) irsend.sendNEC(0x1FED22D,32); // Btv left
break;
case 3:
//for (int i = 0; i < 1; i++) irsend.sendNEC(0x40BF20DF,32); // tv box up
break;
default:
// statements
break;
}
}
void press_S06 (int idx)
{
switch (idx) {
case 0:
for (int i = 0; i < 1; i++) irsend.sendNEC(0x2DF02FD,32); // tv back
break;
case 1:
//for (int i = 0; i < 1; i++) irsend.sendNEC(0x807F9867,32); // tv box back
break;
case 2:
for (int i = 0; i < 1; i++) irsend.sendNEC(0x1FE728D,32); // Btv back
break;
case 3:
for (int i = 0; i < 1; i++) irsend.sendNEC(0x40BF20DF,32); // spk OPT
break;
default:
// statements
break;
}
}
void press_S05 (int idx) // arrow up
{
switch (idx) {
case 0:
for (int i = 0; i < 1; i++) irsend.sendNEC(0x2DF02FD,32); // tv up
break;
case 1:
for (int i = 0; i < 1; i++) irsend.sendNEC(0x807F6897,32); // tv box up
break;
case 2:
for (int i = 0; i < 1; i++) irsend.sendNEC(0x1FE926D,32); // Btv up
break;
case 3:
//irsend.sendNEC(0x40BFA05F,32);
break;
default:
// statements
break;
}
}
void press_S04 (int idx)
{
switch (idx) {
case 0:
for (int i = 0; i < 1; i++) irsend.sendNEC(0x2DFD02F,32); //외부입력
break;
case 1:
//irsend.sendNEC(0x2DF10EF,32);
break;
case 2:
//irsend.sendNEC(0x2DF10EF,32);
break;
case 3:
for (int i = 0; i < 1; i++) irsend.sendNEC(0x40BFA05F,32); // blue tooth
break;
default:
// statements
break;
}
}
void press_S03 (int idx) // power
{
switch (idx) {
case 0:
for (int i = 0; i < 1; i++) irsend.sendNEC(0x2DF10EF,32); // tv power
break;
case 1:
for (int i = 0; i < 1; i++) irsend.sendNEC(0x807F02FD,32); // tv box power
break;
case 2:
for (int i = 0; i < 1; i++) irsend.sendNEC(0x1FE807F,32); // Btv power1
break;
case 3:
for (int i = 0; i < 1; i++) irsend.sendNEC(0x40BF807F,32);
break;
default:
// statements
break;
}
}
void press_S01 (int idx) // S01
{
switch (idx) {
case 0:
for (int i = 0; i < 1; i++) irsend.sendNEC(0x2DF10EF,32);
break;
case 1:
for (int i = 0; i < 1; i++) irsend.sendNEC(0x807F02FD,32);
break;
case 2:
for (int i = 0; i < 1; i++) irsend.sendNEC(0x1FE807F,32);
break;
case 3:
for (int i = 0; i < 1; i++) irsend.sendNEC(0x40BF807F,32);
break;
default:
// statements
break;
}
}
void ledON (int idx)
{
digitalWrite(L00, LOW);
digitalWrite(L01, LOW);
digitalWrite(L02, LOW);
digitalWrite(L03, LOW);
switch (idx) {
case 0:
digitalWrite(L00, HIGH);
break;
case 1:
digitalWrite(L01, HIGH);
break;
case 2:
digitalWrite(L02, HIGH);
break;
case 3:
digitalWrite(L03, HIGH);
break;
default:
// statements
break;
}
}
자 이렇게 해서 프로그램까지 마쳤습니다.
원래 3편에 걸쳐 포스팅을 완료하려고 하였으나 너무 길어져서 최종 케이스제작과 동작 테스트는 다음 포스트로 미루도록 하겠습니다. 죄송합니다.
또 얼마가 걸릴지 모르겠네요.
어쨌든 핵심이 되는 내용은 이번 편까지인것 같고 하드웨어 구성은 여러분께서 마음껏 하셔도 될 것 같습니다. 기능도 변경해보시고요, 좀 고민해보면 더 많은 기능을 구성하는 것도 가능할 수도 있습니다.
이번 프로젝트로 무려 4개의 리모컨을 1개로 통합하는 작업을 해보았는데요, 사실 제가 생각했던것과 아주 유사한 제품이 판매되는 제품도 있습니다. 가격이 아주 비싼것도 아니고요. 다만 이런것을 직접 해봄으로 해서 우리는 또 많은 것을 배울 수 있지 않겠습니까?
저는 이번 프로젝트에서 EEPROM 과 IR 신호를 제어하는 것을 배울 수 있는 좋은 기회였던 것 같습니다.