[아두이노] 4-Digit 7-Segment Display 시계 만들기
[아두이노] 4-Digit 7-Segment Display 시계 만들기
- 온라인 가상시뮬레이터 : https://www.tinkercad.com
- 참고 :
[아두이노] 4-Digit 7-Segment Display 제어
[아두이노] 시간 millis() 함수로 시계 코딩
지난 시간에 4-Digit 7-Segment Display을 사용하는 방법을 실험 하였습니다. 오늘은 지난시간에 만든 회로도와 기본소스를 기반으로 아두이노 시계를 실제 만들어 보겠습니다.
1. 4-Digit 7-Segment Display 회로도
- 준비물 : 4-Digit 7-Segment Display 1개, 스위치버턴 1개, 아두이노우노
- 내용 : 4-Digit 7-Segment Display 부품의 핀 번호 순서에 맞게 아두이노우노에 연결하고, 스위치 버턴은 2번핀에 연결하시오.
- 참조 : [아두이노] 4-Digit 7-Segment Display 제어
지난 시간의 회로도와 동일합니다.
2. 시계 코딩
시간을 참조 Post에 가셔서 사전 학습 해주세요.
1) 시간 구하기
시간은 시리얼통신으로 입력을 받을 경우를 가정해서 시간을 구해 볼까요.
if(Serial.available()){ String inString = Serial.readStringUntil('\n'); }
inString에 시간 문자열을 읽습니다.
int index1 = inString.indexOf(':'); int index2 = inString.indexOf(':',index1+1); int index3 = inString.length(); hour = inString.substring(0, index1).toInt(); min = inString.substring(index1+1,index2).toInt(); sec = inString.substring(index2+1,index3).toInt();
위와 같이 코딩해서 hour, min, sec 구하게 됩니다. 지난시간에 설명을 다했기 때문에 간단히 넘어 갑니다.
timer0_millis = ((long)hour*3600+min*60+sec)*1000;
hour, min, sec 값을 초로 변환하여 timer0_millis 변수에 저장하면 타이머는 입력된 시간을 기준으로 돌아가게 됩니다. 즉, 입력된 시간에서 타이머 시간이 흐른다고 보시면 됩니다.
readTime = millis()/1000; sec = readTime%60; min = (readTime/60)%60; hour = (readTime/(60*60))%24;
readTime 변수에는 millis()함수에서 읽은 타이머 시간값을 1000으로 나눈 몫 값을 저장하기 때문에 입력된 시간을 기준으로 1초 단위로 값이 변화가 일어 나겠죠. 입력시간을 기준으로 흐르는 시간값을 hour, min, sec값으로 다시 구하면 현재 시간을 구할 수 있게 됩니다.
이 값을 4-Digit 7-Segment Display로 출력하면 실제 아두이노 시계가 완성 됩니다.
2) 시간 타이머리셋 지정
24시간을 기준으로 시간을 리셋 시킬 예정입니다. 그러면 어떻게 코딩해야 할까요.
if(millis()>=86400000){ //타이머 리셋 timer0_millis=0; }
if문으로 1day는 24시간이고 이 시간은 "60x60x24" 가 됩니다. 여기에 1초(1000)을 곱해주면 86400000의 타이머 시간값이 만들어 집니다. 이 시간이 되면 timer0_millis=0으로 리셋 시키면 24시간 단위로 타이머는 처음부터 다시 돌게 됩니다.
3) 인터럽트 스위치버턴 활용
지난시간에 인터럽트 스위치버턴을 추가했는데 그러면 이 스위치버턴을 그냥 두기가 아쉬워서 어떤 기능을 넣을까 고민하다가 시간 표시를 제어하는 스위치버턴으로 변경해 보았습니다.
void switchFn(){ state=!state; }
스위치 버턴이 눌러지면 state 변수가 반전이 일어나게 했습니다.
if(state==true){ //12시 or 24시 출력모드 hour = hour%12; }
이렇게 수정했습니다. 현재 시간 hour를 12시 기준으로 출력할 것인지 24시 기준으로 출력할 건지를 스위치버턴으로 제어하는 기능을 추가 했네요.
4) 종합소스
이제 지난시간의 소스에다가 위 설계 코딩을 삽입하면 아래와 같이 완성 됩니다.
//a,b,c,d,e,f,g 상태값 const byte segValue[10][7] = { {1,1,1,1,1,1,0}, //0 {0,1,1,0,0,0,0}, //1 {1,1,0,1,1,0,1}, //2 {1,1,1,1,0,0,1}, //3 {0,1,1,0,0,1,1}, //4 {1,0,1,1,0,1,1}, //5 {1,0,1,1,1,1,1}, //6 {1,1,1,0,0,0,0}, //7 {1,1,1,1,1,1,1}, //8 {1,1,1,1,0,1,1} //9 }; const byte segPin[8]={7,3,A3,A1,A0,6,A4,A2}; //사용핀{a,b,c,d,e,f,g,dp} 순서대로임 const byte digitPin[4] = {8,5,4,A5}; //segment 위치 핀 const byte interruptPin = 2;//인터럽트핀 boolean state = false;//시간 출력형식 지정 extern volatile unsigned long timer0_millis; //타이머변수 unsigned long readTime; //현재타이머시간 int hour, min, sec; void setup() { Serial.begin(9600); pinMode(interruptPin, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(interruptPin), switchFn, FALLING); for(int i=0;i<10;i++){ pinMode(segPin[i], OUTPUT); } for(int j=0;j<4;j++){ pinMode(digitPin[j], OUTPUT); digitalWrite(digitPin[j], HIGH); } } void loop() { if(Serial.available()){ //입력시간 읽기 String inString = Serial.readStringUntil('\n'); int index1 = inString.indexOf(':'); int index2 = inString.indexOf(':',index1+1); int index3 = inString.length(); hour = inString.substring(0, index1).toInt(); min = inString.substring(index1+1,index2).toInt(); sec = inString.substring(index2+1,index3).toInt(); timer0_millis = ((long)hour*3600+min*60+sec)*1000; //입력시간 초변환 } if(millis()>=86400000){ //타이머 리셋 timer0_millis=0; } readTime = millis()/1000; //현재시간 읽기 sec = readTime%60; min = (readTime/60)%60; hour = (readTime/(60*60))%24; if(state==true){ //12시 or 24시 출력모드 hour = hour%12; } segOutput(3,min%10,0); //min 1의 자리 segOutput(2,min/10,0); //min 10의 자리 segOutput(1,hour%10,1); //hour 1의 자리 segOutput(0,hour/10,0); //hour 10의 자리 } //12시 or 24시 출력 변경 void switchFn(){ state=!state; } //LED 초기화 void segClear(){ for(int i=0;i<8;i++){ digitalWrite(segPin[i], LOW); } } //LED 출력 void segOutput(int d, int Number, int dp){ segClear(); digitalWrite(digitPin[d], LOW); for(int i=0;i<7;i++){ digitalWrite(segPin[i], segValue[Number][i]); } digitalWrite(segPin[7], dp); delayMicroseconds(1000); digitalWrite(digitPin[d], HIGH); }
3. 결과
1) 분/초 출력
숫자를 4개 뿐이 출력을 못하기 때문에 간단히 시간이 흐르는 것을 확인 할 수 있게 출력 숫자는 분/초로 세팅했습니다.
segOutput(3,sec%10,0); //min 1의 자리 segOutput(2,sec/10,0); //min 10의 자리 segOutput(1,min%10,1); //min 1의 자리 segOutput(0,min/10,0); //min 10의 자리
입력은 정상적으로 시간 "23:59:50"을 입력할 때는 내부적으로 시간은 정확하게 흘러갑니다. 여기서, 출력은 분/초만 표시될 뿐이죠
분/초만 아래와 같이 출력되어 정상적으로 시간이 흘러가네요.
2) 시/분 출력
종합 소스에 시/분 코딩을 그대로 실험한 결과입니다. 출력은 시/분만 출력됩니다.
segOutput(3,min%10,0); //min 1의 자리 segOutput(2,min/10,0); //min 10의 자리 segOutput(1,hour%10,1); //hour 1의 자리 segOutput(0,hour/10,0); //hour 10의 자리
입력은 시간 "23:59:10"을 입력했습니다.
결과는 아래의 동영상에 보시면 "23:59"만 출력됩니다. 내부적으로 초는 계속 흘러가고 있습니다. 인터럽트 스위치버턴을 누르면 12시 기준으로 시간을 표시되고 다시 누르면 23시 기준으로 시간이 표시 되는 실험 결과를 보실 수 있을 꺼에요. 그리고 24시가 되면은 "00:00"으로 리셋되는 것 까지 보실 수 있을 꺼에요.
마무리
4-Digit 7-Segment Display 부품 밖에 없어서 안타깝게 6자리 시간 표시를 못했네요. 그러다보니 분/초 아니면 시/분으로 표시할 수 밖에 없었고 결과 동영상으로는 표현의 한계가 있었네요.
개별 7-Segment가 2개 있으면 추가로 연결해서 표시 할 수 있었겠지만 한개뿐이라 연결을 포기 했습니다. 아무튼 이런식으로 아두이노 시계를 만들 수 있다는 것을 보여드리는 걸로 정리를 할까 합니다. Stepper Motor로 시계를 표시하고 싶은데 4-Digit 7-Segment Display가 post 주제에서 나중에 응용편으로 기회가 된다면 그때 보여드릴게요. 주제에 맞게 post를 하기 위해서 그 실험은 생략하도록 하겠습니다.
가상시뮬레이터에서 6개 7-Segment를 이용해서 확실히 시계를 만들어서 보여드릴까 고민 좀 해보겠습니다. 여러분들은 실제 제작을 안하더라고 가상시뮬레이터에서 동일한 실험이 체험할 수 있게 귀찮은 회로선 연결을 해야하지만 한번 생각해보고 다음 post으로 올릴지 결정할께요. 될 수 있으면 가상시뮬레이터로 한번 제작해서 보여드리는 방향으로 할께요.
'IOT > 아두이노' 카테고리의 다른 글
[아두이노] 6-Digit 7-Segment Display 시계 리모콘 제어 (0) | 2019.06.19 |
---|---|
[아두이노] 4-Digit 7-Segment Display 가상시뮬레이터 실험 (1) | 2019.06.18 |
[아두이노] 4-Digit 7-Segment Display 제어 (1) | 2019.06.14 |
[아두이노] 2-Digit 7-Segment Display (0) | 2019.06.13 |
[아두이노] 시간 millis() 함수로 시계 코딩 (0) | 2019.06.07 |