DIY 아두이노 눈꽃 장식: 30개 LED 디스플레이 프로젝트
부품 및 소모품
필요 도구
프로젝트 소개
30개 LED를 17개 독립 세그먼트로 그룹화해 아두이노 나노로 개별 제어하는 눈꽃 모양 장식입니다. 각 LED 그룹은 PWM으로 디밍 가능해 아름다운 애니메이션을 연출할 수 있습니다.
제작 과정
1. 패턴 선정 및 설계
아두이노 나노가 들어갈 육각형 코어 크기에 맞춰 눈꽃 결정 패턴을 출력.
2. 프리폼(Freeform) 구조물 제작
0.8mm 황동봉 2m를 주석 납땜으로 연결해 지지대 겸 배선 구조물 제작. 인내심과 기술의 테스트였습니다.
- 단일 봉을 구부려 코어 육각형 제작 후 양 끝 납땜
- 육각형 꼭짓점에 6개 봉 추가로 그라운드 배선 완성
- 모든 LED 캐소드를 그라운드 구조물에 납땜해 눈꽃 패턴 형성
- SMD LED 납땜을 위해 골판지+양면테이프 지그 제작 활용
3. 아두이노 나노 장착 및 배선
코어 구조물 아래 나노 장착, 3층 황동봉 배선으로 아두이노 핀과 LED 애노드 연결. 쇼트 방지, 전류 제한 저항(220Ω), 외관 모두 고려해 엄청난 인내심 필요.
- 잎 LED: 각자 별도 출력 핀 연결 (6개)
- 가지 LED: 2개씩 그룹화해 PWM 핀 연결 (6개 × 2 = 12개)
- 코어 LED: 2개씩 그룹화 (4개 핀), 남은 2개는 4개 그룹으로 묶음
나노는 18개 출력 핀(A6, A7 입력 전용), 터치 센서 1핀 사용으로 17핀 가용. 핀당 8mA (220Ω), 총 240mA로 ATmega328 안전 최대치(200mA) 초과하지만 작동함.
정전식 터치 센서
황동봉 하나 추가로 정전식 터치 센서 구현. Paul Stoffregen의 라이브러리/튜토리얼 활용. 터치로 애니메이션 변경, 온/오프, 스파클 효과 등 상호작용 가능.
마무리 팁
납땜 전 모든 다이오드 테스트 필수! 납땜 후 교체/극성 수정이 매우 어렵습니다.
코드 및 애니메이션
하드웨어 PWM 핀만 디밍 가능할 줄 알았으나, 소프트웨어 PWM 라이브러리(SoftPWM)로 모든 핀을 PWM처럼 사용 가능해 무한한 애니메이션 구현.
소스 코드 (snowflake.ino)
#include "SoftPWM.h"
#include
byte edgeLedPins[] = {13, A4, A5, 2, 8, 12}; // 잎 LED (6개)
byte middleLedPins[] = {10, 6, 3, 5, 9, 11}; // 가지 LED (6개)
byte innerLedPins[] = {A2, A3, A1, 4, 7, A1}; // 코어 LED (6개, A1 중복으로 4개 그룹)
ADCTouchSensor touchSensor = ADCTouchSensor(A0, 1);
void setup() {
Serial.begin(115200);
SoftPWMBegin();
}
byte animation = 0;
long touchAt = 0;
void loop() {
switch (animation) {
case 0: _fill(100); break; // 전체 켜기
case 1: shinyAnimation(); break; // 반짝임
case 2: circleAnimation(); break; // 원형 파동
case 3: loopAnimation(); break; // 순차 점등
case 4: // 폭죽
for(int i=0;i<6;i++) fireworkAnimation();
animation++; break;
case 5: smileAnimation(); break; // 스마일
default: animation = 0; break;
}
int touchValue = touchSensor.read();
if (touchAt + 2000 < millis() && touchValue > 1000) {
touchAt = millis(); // 2초 쿨다운
animation++;
_fill(0); // 전체 끄고 다음 애니메이션
}
}
// --- 애니메이션 함수들 ---
void _fill(byte value) {
for(int i=0;i<6;i++) {
SoftPWMSet(edgeLedPins[i], value);
SoftPWMSet(middleLedPins[i], value);
SoftPWMSet(innerLedPins[i], value);
}
}
void fireworkAnimation() {
for(int i=0;i<4;i++) { SoftPWMSet(innerLedPins[i], 100); delay(100); }
SoftPWMSet(innerLedPins[4], 100);
for(int i=0;i<6;i++) SoftPWMSet(middleLedPins[i], 255);
delay(50);
for(int i=0;i<6;i++) { SoftPWMSet(innerLedPins[i], 0); SoftPWMSet(edgeLedPins[i], 255); }
delay(50);
for(int i=0;i<6;i++) SoftPWMSet(middleLedPins[i], 0);
delay(50);
_fill(0);
}
void smileAnimation() {
SoftPWMSet(innerLedPins[1], 100); SoftPWMSet(innerLedPins[3], 100);
SoftPWMSet(middleLedPins[0], 255); SoftPWMSet(middleLedPins[5], 255);
SoftPWMSet(edgeLedPins[2], 255); SoftPWMSet(edgeLedPins[3], 255);
delay(2000);
SoftPWMSet(innerLedPins[1], 0); SoftPWMSet(innerLedPins[3], 0);
delay(100);
SoftPWMSet(innerLedPins[1], 100); SoftPWMSet(innerLedPins[3], 100);
delay(100);
SoftPWMSet(innerLedPins[1], 0); SoftPWMSet(innerLedPins[3], 0);
delay(100);
}
byte circleState[] = {100, 55, 10};
byte circleStateAnimation[] = {1, 1, 1};
void circleAnimation() {
for(int i=0;i<3;i++) {
if(circleState[i] >= 100) circleStateAnimation[i] = -1;
else if(circleState[i] <= 10) circleStateAnimation[i] = 1;
circleState[i] += circleStateAnimation[i];
}
for(int i=0;i<6;i++) {
SoftPWMSet(innerLedPins[i], circleState[0]);
SoftPWMSet(middleLedPins[i], circleState[1]);
SoftPWMSet(edgeLedPins[i], circleState[2]);
}
delay(5);
}
// 웨이브, 루프, 슬로우 온, 샤이닝, 페이딩 애니메이션 함수들도 포함됨
// (코드 원문 참조)
byte _prevIndex(short index, byte step) { index -= step; while(index < 0) index += 6; return index; }
byte _nextIndex(short index, byte step) { index += step; while(index > 5) index -= 6; return index; }
회로도
배선도 이미지 제공.