아날로그 스타일 LED POV 시계 - 아두이노 나노 DIY 프로젝트
부품 및 소모품
| 아두이노 나노 R3 |
1개 |
| LED (일반, 색상별 그룹핑) |
17개 |
| 홀 이펙트 센서 |
1개 |
| 100Ω 저항 |
17개 |
| DC 모터 (제네릭) |
1개 |
| 부스트(승압) 컨버터 (고정 출력) |
1개 |
필요한 도구
앱 및 온라인 서비스
프로젝트 개요
POV(Persistence of Vision, 잔상 효과) 디스플레이는 LED를 고속 회전시키며 한 줄씩 이미지를 표시해, 사람의 눈이 연속된 이미지로 인식하게 하는 기술입니다.
본 프로젝트는 아날로그 시계 형태의 POV 디스플레이로, 아두이노 나노, 17개 LED, 홀 센서로 구성됩니다. LED 그룹(d1~d11, d12~d16, d17)은 색상을 달리해 시각 효과를 높였습니다. 리튬이온 배터리 + 승압 컨버터로 구동.
기계적 안정성 확보가 핵심
초기 버전은 배터리가 편심 배치되어 고속 회전 시 진동이 심했습니다. 배터리를 회전 중심축에 배치해 진동 문제를 해결했습니다.
회전 구동
12V DC 모터 + 가변 전원장치로 회전 속도 제어. 회전 속도에 맞춰 코드 내 delayMicroseconds() 값 조정 필요 (저속=값 증가, 고속=값 감소).
동작 원리
- 홀 센서로 1회전 기준점(자석 통과) 감지
- 1초마다 시/분/초 카운트 업데이트
- 한 회전 동안 60개 위치(분 단위)에 맞춰 LED 패턴 출력
- 분 마커, 시 마커, 15분 마커, 시/분/초침 순차 표시
- 이너 서클(중심점) 표시로 기준점 보정
코드
// 아두이노 나노 프로펠러 LED 아날로그 시계
// 핀 매핑: LED 1~11 → D2~D12, LED 12~16 → A1~A5, 센서 → A0
int LED[16] = {2,3,4,5,6,7,8,9,10,11,12,A1,A2,A3,A4,A5};
int sensorPin = A0;
unsigned int n, propeller_posn;
unsigned long previousTime = 0;
byte hours = 12, minutes = 15, seconds = 0;
void setup() {
for (int i=0; i<16; i++) pinMode(LED[i], OUTPUT);
pinMode(sensorPin, INPUT_PULLUP);
if (hours == 12) hours = 0;
}
void loop() {
// 홀 센서 LOW(자석 감지) 대기
while (digitalRead(sensorPin) == LOW);
// 1초마다 시간 업데이트
if (millis() >= previousTime) {
previousTime += 1000;
seconds++;
if (seconds == 60) { seconds = 0; minutes++; }
if (minutes == 60) { minutes = 0; hours++; }
if (hours == 12) hours = 0;
}
// 한 회전(60 스텝) 동안 패턴 출력
propeller_posn = 30; // 시작 위치 오프셋
n = 0;
while (n < 60) {
drawMinuteMarker(); // 분 마커 (LED16)
if (isHourMarker(propeller_posn)) drawHourMarker(); // 시 마커 (LED14,15)
if (isQuarterMarker(propeller_posn)) drawQuarterMarker(); // 15분 마커 (LED12,13)
if (isHourHand(propeller_posn)) drawHourHand(); // 시침 (LED1~7)
if (isMinuteHand(propeller_posn)) drawMinuteHand(); // 분침 (LED1~9)
if (isSecondHand(propeller_posn)) drawSecondHand(); // 초침 (LED1~11)
delayMicroseconds(140); // LED 픽셀 폭 (모터 속도에 맞춰 조정)
displayClear();
drawInnerCircle(); // 중심점 표시
delayMicroseconds(600); // 픽셀 간 간격
n++;
propeller_posn++;
if (propeller_posn == 60) propeller_posn = 0;
}
// 홀 센서 HIGH(자석 벗어남) 대기 → 다음 회전 동기화
while (digitalRead(sensorPin) == HIGH);
}
// --- 헬퍼 함수들 ---
void displayClear() { for(int i=0;i<16;i++) digitalWrite(LED[i],LOW); }
void drawMinuteMarker() { digitalWrite(LED[15], HIGH); }
void drawHourMarker() { digitalWrite(LED[13],HIGH); digitalWrite(LED[14],HIGH); }
void drawQuarterMarker() { digitalWrite(LED[11],HIGH); digitalWrite(LED[12],HIGH); }
void drawHourHand() { for(int i=0;i<7;i++) digitalWrite(LED[i],HIGH); }
void drawMinuteHand() { for(int i=0;i<9;i++) digitalWrite(LED[i],HIGH); }
void drawSecondHand() { for(int i=0;i<11;i++) digitalWrite(LED[i],HIGH); }
void drawInnerCircle() { digitalWrite(LED[0],HIGH); delayMicroseconds(30); digitalWrite(LED[0],LOW); }
bool isHourMarker(int pos) {
return (pos%5==0); // 0,5,10...55
}
bool isQuarterMarker(int pos) {
return (pos%15==0); // 0,15,30,45
}
bool isHourHand(int pos) {
return (pos == hours*5) || (pos==0 && hours==0);
}
bool isMinuteHand(int pos) { return pos == minutes; }
bool isSecondHand(int pos) { return pos == seconds; }
회로도
첨부 이미지 참조 (브레드보드/PCB 배선도)
제작 팁
- 회전체 밸런싱이 가장 중요: 배터리, MCU, LED 보드 모두 회전 중심에 배치
- 홀 센서와 자석 간격 1~2mm 유지
- 모터 속도 안정화 위해 PWM 드라이버 또는 ESC 사용 권장
- 카메라 프레임레이트 제한으로 영상 촬영 시 플리커 발생 가능 (실제 육안으론 깨끗함)
- 배터리 용량에 따라 구동 시간 결정 (승압 컨버터 효율 고려)