시간(시/분/초) 변환(아두이노)
시간(시/분/초) 변환(아두이노)
- 온라인 가상시뮬레이터 : https://www.tinkercad.com
- 참고 :
시간 millis()함수로 읽은 숫자 쪼개기 (아두이노)
시간 millis()함수로 시간 카운트(아두이노) - 공개회로도 :
https://www.tinkercad.com/things/eyAI1iP1V3R (초 변환)
https://www.tinkercad.com/things/l0EI3eJgoHR (시간 분리)
https://www.tinkercad.com/things/esLSzgrWHWG (시간 변환)
오늘은 시간 변환을 실험을 하겠습니다. 초를 입력하여 시/분/초로 변환하는 실험과 문자열 시/분/초를 입력하여 시간, 분, 초로 분리해내는 실험을 하겟습니다 이 원리를 기반으로 시/분/초를 초로 변환시키 후 변환 시킨 초를 기준으로 시/분/초로 다시 원상 복구하여 시간 변환 코딩이 정상적으로 이루어지는지 실험 하겠습니다.

이제 본격적으로 실험을 해볼까요.
1. 초를 시/분/초로 변환
- 공개회로도 : https://www.tinkercad.com/things/eyAI1iP1V3R (초 변환)
초를 시/분/초로 변환식 :
readTime = 입력Sec;
sec = 전체수 % 60;
min = (전체수/60)%60;
hour = (전체수/(60x60)%24;
day = (전체수/(60x60x24)%365;
...
1분 = 60초
1시간 = 60x60초
1day = 60x60x24초
시리얼모니터에서 초를 입력하면,
if(Serial.available()){
unsigned long readTime = Serial.parseInt();
}
아두이노에서 parseInt()로 간단히 읽는다. 총 15자리 수까지 입력받을 수 있다.
계산은,
sec = readTime%60;
min = (readTime/60)%60;
hour = (readTime/(60*60))%24;
시/분/초만 출력하게 하기 위해서는 위 코딩과 같이 표현하시면 됩니다. 참고로, 24시간 이상이면 day까지 구하면 좋지만 그냥 day은 무시하고 시계처럼 시/분/초만 출력합니다.
[소스]
int hour, min, sec;
void setup()
{
Serial.begin(9600);
}
void loop()
{
//초 입력
if(Serial.available()){
unsigned long readTime = Serial.parseInt();
sec = readTime%60;
min = (readTime/60)%60;
hour = (readTime/(60*60))%24;
Serial.print(hour);
Serial.print(" : ");
Serial.print(min);
Serial.print(" : ");
Serial.println(sec);
}
}
[결과]

2. 시/분/초 문자열에서 시간 분리
- 사전학습 : Serial 통신 때 String 사용 (아두이노)
- 공개회로도 : https://www.tinkercad.com/things/l0EI3eJgoHR (시간 분리)
입력 => "시:분:초"
위와같이 시/분/초로 입력 받는 다면 어떻게 표현 할까요. 위에 사전학습에서 String에 대해 사전학습을 미리 해 주세요.
시간 문자열을 분리해 내는 방법을 간단히 복습해 봅시다.
String inString = "10:11:22"
위 문자열을 "시:분:초"를 어떻게 분리해 낼까요. 시/분/초의 문자열을 나누는 기호가 ':'입니다. 즉, ':'의 위치를 알고 있으면 이 위치를 기준으로 시/분/초를 읽으면 됩니다.
int index1 = inString.indexOf(':');
int index2 = inString.indexOf(':',index1+1);
int index3 = inString.length();
- indexOf(':') : ':'의 기호가 있는 위치
- index(':',검색시작위치) : 검색시작위치부터 ':'의 기호가 있는 위치
이렇게 index들을 구하면 즉, 문자열에서 수자를 읽을 마지막 위치값을 지정할 수 있습니다.
"10:11:22"
index1 = 2
index2 = 5
index3 = 8
index3이 7이 아니고 8인 이유는 문자열은 마지막 끝을 나타내는 문자기호가 포함되어 있기 때문에 index가 8입니다.
이제 위치값을 알았으니깐 시/분/초를 구해 볼까요.
hour = inString.substring(0, index1).toInt();
min = inString.substring(index1+1,index2).toInt();
sec = inString.substring(index2+1,index3).toInt();
- substring(시작위치,마지막위치) : 특정부분문자열 추출
- toInt() : 문자열을 정수형으로 변환
inString.substring(0, index1).toInt();
위 명령은 전체문자열에서 특정부분문자열을 추출하고 그 추출된 문자열을 정수형으로 변환시킨다는 명령입니다. hour, min, sec를 이 명령으로 시/분/초를 구할 수 있게 됩니다.
정확히 시/분/초가 분리되었는지 살펴 볼까요.
void setup()
{
Serial.begin(9600);
}
void loop()
{
// 시:분:초 입력
if(Serial.available()){
String inString = Serial.readStringUntil('\n');
int index1 = inString.indexOf(':');
int index2 = inString.indexOf(':',index1+1);
int index3 = inString.length();
int hour = inString.substring(0, index1).toInt();
int min = inString.substring(index1+1,index2).toInt();
int sec = inString.substring(index2+1,index3).toInt();
Serial.print(hour);
Serial.print(" : ");
Serial.print(min);
Serial.print(" : ");
Serial.println(sec);
}
}
[결과]

위 그림처럼 시/분/초를 입력한 문자열이 제대로 분리되어 정확히 시/분/초가 출력 됩니다.
3. 시/분/초 입력값을 초 변환 후 다시 시/분/초 변환
- 공개회로도 : https://www.tinkercad.com/things/esLSzgrWHWG (시간 변환)
이번에는 시/분/초를 입력 받은 후에 그 값을 초로 변환 시킵니다. 그리고 그 초 값을 다시 시/분/초로 변환하여 결과를 살펴보겠습니다. 시간 변환을 잘 이루어지는 살펴보기 위한 실험입니다.
시/분/초를 입력받은 문자열을 초로 변환하기 위해서는 다음과 같습니다.
totalSec = 시*3600 + 분*60 + 초;
시간 문자열을 읽어서 hour, min, sec 값을 분리 해내고 초로 변환하면 다음과 같이 코딩을 하면 되겠죠.
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();
readTime = (long)hour*3600+min*60+sec;
}
위 코딩 식의 의해서 readTime 총 sec 값을 저장하게 됩니다.
다시, readTime 시/분/초 변환을 시켜서 계산 상 아무런 문제가 없는지 확인해 봅시다.
readTime = (long)hour*3600+min*60+sec;
sec = readTime%60;
min = (readTime/60)%60;
hour = (readTime/(60*60))%24;
이렇게 다시 hour, min, sec 구하여 이 값이 시리얼모니터로 출력시키면 확인이 가능해 집니다.
[소스]
unsigned long readTime;
int hour, min, sec;
void setup()
{
Serial.begin(9600);
}
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();
readTime = (long)hour*3600+min*60+sec;
Serial.print("Total Sec : ");
Serial.println(readTime);
sec = readTime%60;
min = (readTime/60)%60;
hour = (readTime/(60*60))%24;
Serial.print(hour);
Serial.print(" : ");
Serial.print(min);
Serial.print(" : ");
Serial.println(sec);
}
}
[결과]

위 결과를 보면 "11:22:33" 시간이 입력되면 시간에 대한 초 변환 값 '40953'값이 나왔고 이 값을 다시 시/분/초로 변환하면 "11:22:33" 시간이 나옵니다. 시간 변환이 깔끔하게 되었네요.
마무리
오늘은 시간에 대한 코딩 트레이닝을 하였습니다. 아두이노에서 시간를 다룰 줄 알면 시간에 관한 다양한 표현을 할 수 있습니다. 오늘 배운 원리를 이해하시면 아두이노 시계를 만들 수 있습니다. 아두이노에 전원을 공급하고 현재 시간값을 입력하여 millis()함수를 이용하면 아두이노 시계를 만들 수 있습니다.
지난 시간에는 millis()함수로 시간값을 분리하고 카운트하는 방법을 살펴보았으며 오늘은 시간 변환을 살펴보았습니다. 한번 지끔까지 배운 원리를 종합하여 아두이노 시계를 만들어 보세요.
(jjangjjangman 태그 사용시 댓글을 남깁니다.)
호출에 감사드립니다! 즐거운 스티밋하세요!
짱짱맨 방문에 감사합니다. 오치님도 즐거운 스티밋하세요.^^
변환하는 루틴이 생각보다 복잡합니다.
문자열을 분해내서 숫자로 만들어내는 것이 약간 복잡할 꺼에요.
저 이거 해커톤에서 못해서 시간을 직접 써서 넣었어요. ㅎㅎㅎㅎ 진짜 무식하게 만들었음. 1초마다 하나씩 썼어요. ㅎㅎㅎㅎㅎ 아놬.
결과만 나오면 됐죠! ^^
오늘 실험은 시간을 초 입력과 시간 입력으로 해서 변환만 하는 거라서 시간은 움직이지는 않아요.
내일 post는 오늘 변환한 기법과 millis()함수를 이용해서 실제 아두이노 시계가 움직이게 할 예정이고요
무식무식 ㅎㅎㅎ 다행히 아무도 몰랐음. ㅎㅎㅎㅎ 아 그렇군요. 왠지 제가 못 찾은 게 아니군요. 시간을 어디서 받아온다고 생각했는데요. clock 이나 아니면 어디 라이브러리 같은데서 불러온다고 생각했는데 아닌가요? ㅇ_ㅇ???
시간이라기 보다는 아두이노 하드웨어에서 전기신호를 클럭을 만들어 내고 그 클럭을 기준으로 시간 카운트를 한다고 생각하시면 될꺼임
그걸 자체 아두이노라이브러리 시간을 만들어내고요. 그걸 delay() maillis() 시간 관련함수로 적용되는 거고요.
아두이노 자체는 카운트를 하는데 1000 카운트하는데 걸리는 시간이 1초이고요 그래서 delay(1000)이 1초에 해당됩니다.
카운트는 아두이노 자체 내부에서 timer0_millis변수에 카운트 값이 저장되는데 이 값을 millis()함수를 통해 읽어오게 됩니다.
초 = millis()/1000;
이렇게 전체 카운트 시간의 초값으로 나타내고 이 전체 초에서 시/분/초로 나누면 시간값이 나오게 됩니다.
그리고 외부입력으로 현재시간을 세팅할려고 하면 시/분/초를 초로 변환시켜서 timer0_millis에 저장시키면 현재시간이 되고요. 현재시간을 기준으로 카운트는 계속 진행되고 millis()함수를 1초 단위로 시간값을 출력하면 아두이노 시계가 완성이 됩니다.
이 부분에 대한 자세한 실험은 내일 post에 올릴 예정이고요.
아 그러면 클럭을 기준으로 쓰는 게 맞네요. ㅇ_ㅇ;;; 헐. 똑같이 구현했군요. 헐. 저는 클럭을 기준으로 하는 것도 있고, 시간을 웹으로 받아오는 것도 있는 줄 알았는데. 표준시간을 웹으로 받아오는 것은 없나보군요.
시간을 웹상으로 불러와서 타이머변수값을 갱신하시면 자동으로 시간을 잡을 수 있어요. 딱한번 외부에서 타이머변수값을 갱신을 하면 어짜피 그 값을 기준으로 타이머가 동작하게 하면 시간은 자연스럽게 만들어지지요.
돌아가는 건 똑같고, 웹으로 한 번 동기화 해주느냐 아니냐 정도네요. 웹으로 동기화 하는 걸 한 번도 안 해봐서 한 번 해봐야 되겠습니다. ㅎㅎㅎ