코코아팹은 누구나 창의적 아이디어를 현실로 만들어 낼 수 있도록
만들고, 공유하고, 배울 수 있는 터전이
되고자 합니다.
아이디와 비밀번호를 잊으셨나요?아이디 / 비밀번호 찾기
코코아팹 회원이 아니신가요? 회원가입
2016-01-14 18:57:23
여러분은 손목시계, 전자시계 혹은 휴대폰 중 어떤 시계를 사용하시나요?
숫자로 나타내는 시계 말고 패턴으로 숫자를 나타내어서 사용하는 시계는 어떨까요?
최근에는 시계 하나도 인테리어 소품으로 많이 사용되고 있더라구요~!
휴대성보다는 인테리어용도를 더욱 살리는, LED를 이용한 시계를 만들어 보았습니다.
아래의 그림은 각각 1 7 3 9를 나타냅니다.
즉 17시 39분, 오후 5시 39 분이었답니다!
이 프로젝트는 instructables의 stregoi님의 프로젝트를 응용하여 만들었습니다.
- RTC 사용하기
NO | 부품명 | 수량 | 상세설명 |
1 | 오렌지보드 | 1 | 아두이노 우노 |
2 | Tiny RTC V1.1 | 1 | RTC 모듈 |
3 | Neopixel led | 44 | strip |
4 |
10KΩ 저항 |
1 |
10KΩ 저항 |
5 | 점퍼케이블 | 16 이상 | 점퍼케이블 |
6 | 스위치 | 1 | |
7 | 브레드보드 | 1 | 브레드보드 |
부품명 | 오렌지 보드 | Strip Neo Pixel | 스위치 | Tiny RTC | 10KΩ 저항 | 브레드 보드 | 점퍼 케이블 |
파트 | x 1 | x 44 |
x 1 |
x 1 | x 1 | x 1 |
x 16 이상 |
* 가독성을 높이기 위해 브레드보드와 회로도에는 일부 점퍼케이블을 생략했습니다. 크기나 모양에 맞추어 점퍼케이블의 수는 늘리면 될 것 같습니다^^
브레드보드 레이아웃
1. 오렌지보드의 GND 핀을 브레드보드의 - 버스에 연결합니다.
2. 오렌지보드의 5V 핀을 브레드보드의 + 버스에 연결합니다.
3. DS1307RTC의 SDA, SCL, GND, 5V 을 오렌지 보드와 브레드 보드에 각각 연결합니다.
4. Neo Pixel strip LED의 GND는 브레드보드의 - 버스에, 5V는 + 버스에, DIN은 좌측부터 각각 11번, 9번, 5번, 3번 핀에 연결합니다.
5. 스위치를 연결해 줍니다.
6. 스위치의 한쪽 끝이 연결 된 브레드보드를 + 버스와 연결합니다.
7. 반대쪽을 4번핀과 연결합니다.
8. 8에서 연결된 브레드보드와 저항을 연결합니다.
9. 저항의 끝을 - 버스와 연결합니다.
#include <Adafruit_NeoPixel.h>
#include <Time.h>
#include <Wire.h>
#include <DS1307RTC.h>
#define HourMonthPIN1 3
#define HourMonthPIN2 5
#define MinuteDayPIN1 9
#define MinuteDayPIN2 11// 3,5,9,11 번 핀에 NeoPixel을 연결
const int buttonPin = 4; // 4번 핀에 스위치를 연결
boolean buttonStatus; // 스위치의 상태를 읽어오기 위한 boolean 자료형으로 변수 선언
int Flag;
int color1[9] = {34,255,173,139,47,255,255,226,65};
int color2[9] = {27,0,0,34,48,88,235,121,199};
int color3[9] = {255,36,255,0,0,83,152,255,232}; // led의 색상을 나타내기 위한 배열
int lednum[9][9] =
{
{ 5, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 4, 6, 0, 0, 0, 0, 0, 0, 0 },
{ 4, 5, 6, 0, 0, 0, 0, 0, 0 },
{ 1, 2, 8, 9, 0, 0, 0, 0, 0 },
{ 1, 2, 5, 8, 9, 0, 0, 0, 0 },
{ 1, 2, 4, 6, 8, 9, 0, 0, 0 },
{ 1, 2, 4, 5, 6, 8, 9, 0, 0 },
{ 0, 1, 2, 3, 7, 8, 9, 10, 0 },
{ 0, 1, 2, 3, 5, 7, 8, 9, 10 }
}; // 숫자의 형태를 나타내기 위한 배열
Adafruit_NeoPixel strip[4] =
{
(Adafruit_NeoPixel(11, HourMonthPIN1, NEO_GRB + NEO_KHZ800)),
(Adafruit_NeoPixel(11, HourMonthPIN2, NEO_GRB + NEO_KHZ800)),
(Adafruit_NeoPixel(11, MinuteDayPIN1, NEO_GRB + NEO_KHZ800)),
(Adafruit_NeoPixel(11, MinuteDayPIN2, NEO_GRB + NEO_KHZ800))
}; // LED 객체 선언
void setup() {
Serial.begin(9600);
#if defined (__AVR_ATtiny85__)
if (F_CPU == 16000000) clock_prescale_set(clock_div_1);
#endif
pinMode(buttonPin, INPUT_PULLUP);
for (int i = 0; i<4; i++)
{ strip[i].begin(); }
for (int i = 0; i<4; i++)
{ strip[i].show(); }
while (!Serial);
}
void loop() {
Serial.print(digitalRead(buttonPin));
tmElements_t tm; // RTC 객체 선언
if(digitalRead(buttonPin)==HIGH)
{
if(Flag==0)
{
Flag = 1;
buttonStatus = !buttonStatus;
for(int k=0; k<4; k++)
{
LED_RESET (k);
}
}
}
else
{
Flag = 0;
} // 스위치의 상태를 변환
if (RTC.read(tm)) { //RTC 모듈로 부터 데이터가 들어온다면
int hourFirst = tm.Hour / 10; // 시(hour) 데이터의 십의 자리를 hourFirst 변수에 담는다.
int hourLast = tm.Hour % 10; // 시(hour) 데이터의 일의 자리를 hourLast 변수에 담는다.
int minuteFirst = tm.Minute / 10; // 분(mintue) 데이터의 십의 자리를 minuteFirst 변수에 담는다.
int minuteLast = tm.Minute % 10; // 분(mintue) 데이터의 일의 자리를 minuteLast 변수에 담는다.
int seconds = tm.Second; // 초(second) 데이터를 seconds에 담는다.
int monthFirst = tm.Month / 10; // 월(month) 데이터의 십의 자리를 monthFirst 변수에 담는다.
int monthLast = tm.Month % 10; // 월(month) 데이터의 일의 자리를 monthLast 변수에 담는다.
int dayFirst = tm.Day / 10; // 일(day) 데이터의 십의 자리를 dayFirst 변수에 담는다.
int dayLast = tm.Day % 10; // 일(day) 데이터의 일의 자리를 dayLast 변수에 담는다.
if(buttonStatus) // buttonStatus의 상태가 초기 값이라면
{
Filter(monthFirst, 0); Filter(monthLast, 1);// 월(hour) LED 출력
Filter(dayFirst, 2); Filter(dayLast, 3);// 일(minute) LED 출력
for (int i = 0; i<4; i++)
{ strip[i].show(); }
if(hourFirst==0 && hourLast == 0 && minuteFirst == 0 && minuteLast == 0 && seconds == 0)
{
for(int k=0; k<4; k++)
{
LED_RESET(k);
}
delay(1000);
} // 날짜가 변하는 시점인 hourFirst, hourLast, minuteFirst, minuteLast, seconds가 모두 0일 때에 LED 전체를 한번 reset 한다.
}
else // 그 외의 값에는
{
Filter(hourFirst, 0); Filter(hourLast, 1);// 시(hour) LED 출력
Filter(minuteFirst, 2); Filter(minuteLast, 3);// 분(minute) LED 출력
for (int i = 0; i<4; i++)
{ strip[i].show(); }
if(seconds == 0)
{ LED_RESET (3);
delay(1000);} // 다음 minuteLast 출력을 위해 seconds가 0일때 마지막 LED를 reset 한다.
if(minuteLast == 0 && seconds == 0)
{ LED_RESET (2);
delay(1000);} // 다음 minuteFirst 출력을 위해 seconds와 minuteLast가 0일때 세번째 LED를 reset 한다.
if(minuteFirst == 0 && minuteLast == 0 && seconds == 0)
{ LED_RESET (1);
delay(1000);} // 다음 hourLast 출력을 위해 seconds, minuteLast, minuteFirst가 0일때 두번째 LED를 reset 한다.
if(hourLast == 0 && minuteFirst == 0 && minuteLast == 0 && seconds == 0)
{ LED_RESET (0);
delay(1000);} // 다음 hourFirst 출력을 위해 seconds, minuteLast, minuteFirst,hourLast가 0일때 첫번째 LED를 reset 한다.
}
}
}
void Filter(int timenum, int stripnum) // 각각의 자리에 필요한 숫자를 설정받는 함수
{
if (timenum == 0)
{ LED_RESET(stripnum); } // 각각의 자리가 0이라면 LED 전체를 RESET
for (int t = 1; t < 10; t++) // 각각의 자리에 따라 Repeat 함수를 반복
{
if (timenum == t)
{ Repeat(timenum, stripnum); }
}
}
void Repeat(int clocknum, int stripnum) // 각각의 자리의 숫자를 받아 미리 선언된 패턴, 순서, 색에 따라 LED를 점등시켜주는 함수
{
int i = clocknum - 1;
for (int j = 0; j <= clocknum - 1; j++)
{
strip[stripnum].setPixelColor(lednum[i][j], color1[i], color2[i], color3[i]);
strip[stripnum].show();
}
} //
void LED_RESET (int stripnum) // LED를 reset 하는 함수
{
for (int i = 0; i<11; i++)
{
strip[stripnum].setPixelColor(i, 0, 0, 0);
strip[stripnum].show();
}
}
int color1[9] = {34,255,173,139,47,255,255,226,65};
int color2[9] = {27,0,0,34,48,88,235,121,199};
int color3[9] = {255,36,255,0,0,83,152,255,232}; // led의 색상을 나타내기 위한 배열
Klant님의 도움으로 Adobe Color CC라는 사이트를 알게 되어 각각 숫자에 따른 색상의 값을 미리 배열로 선언해두었습니다.
Neo pixel LED 에서는 흰끼가 많은 파스텔톤 느낌의 색상보다는 원색에 가까운 계열의 색상이 더 선명하게 보였습니다.
<Adobe Color CC>
int lednum[9][9] =
{
{ 5, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 4, 6, 0, 0, 0, 0, 0, 0, 0 },
{ 4, 5, 6, 0, 0, 0, 0, 0, 0 },
{ 1, 2, 8, 9, 0, 0, 0, 0, 0 },
{ 1, 2, 5, 8, 9, 0, 0, 0, 0 },
{ 1, 2, 4, 6, 8, 9, 0, 0, 0 },
{ 1, 2, 4, 5, 6, 8, 9, 0, 0 },
{ 0, 1, 2, 3, 7, 8, 9, 10, 0 },
{ 0, 1, 2, 3, 5, 7, 8, 9, 10 }
}; // 숫자의 형태를 나타내기 위한 배열
LED에서 패턴에 따라 숫자를 나타내기 위해 순서를 배열로 설정해 주었습니다.
1을 점등할 때는 한개의 숫자만 필요하지만 2차원 배열로 선언해 주었기 때문에
나머지 값들은 일단 0으로 설정하고 Repeat 함수에서 필요한 부분까지만 반복문을 이용하였습니다.
각각의 숫자에 따른 패턴은 아래와 같습니다.
int hourFirst = tm.Hour / 10; // 시(hour) 데이터의 십의 자리를 hourFirst 변수에 담는다.
int hourLast = tm.Hour % 10; // 시(hour) 데이터의 일의 자리를 hourLast 변수에 담는다.
int minuteFirst = tm.Minute / 10; // 분(mintue) 데이터의 십의 자리를 minuteFirst 변수에 담는다.
int minuteLast = tm.Minute % 10; // 분(mintue) 데이터의 일의 자리를 minuteLast 변수에 담는다.
int seconds = tm.Second; // 초(second) 데이터를 seconds에 담는다.
int monthFirst = tm.Month / 10; // 월(month) 데이터의 십의 자리를 monthFirst 변수에 담는다.
int monthLast = tm.Month % 10; // 월(month) 데이터의 일의 자리를 monthLast 변수에 담는다.
int dayFirst = tm.Day / 10; // 일(day) 데이터의 십의 자리를 dayFirst 변수에 담는다.
int dayLast = tm.Day % 10; // 일(day) 데이터의 일의 자리를 dayLast 변수에 담는다.
RTC 모듈에서는 시간과 날짜를 int 값으로 전달합니다. 전달 받은 값들을 일의자리와 십의 자리로 나눠서 출력하기 위한 변수를 선언해준 구간 입니다.
예를 들어 전달받은 시간이 23시 37분이라면 23을 10으로 나눠 몫과 나머지를 출력하여 각각 나타내었습니다.
여기서는 시간과 날짜를 출력 하였지만 RTC 모듈에서는 연도도 출력 할 수 있습니다.
연도를 출력 하고 싶다면 int yearFirst = tmYearToCalendar(tm.Year) / 1000; 처럼 각각의 자리에 맞는 연산을 실행해 주면 됩니다
이연정