[아두이노] 시간 millis()함수로 읽은 숫자 쪼개기
[아두이노] 시간 millis()함수로 읽은 숫자 쪼개기
- 온라인 가상시뮬레이터 : https://www.tinkercad.com
- 공개회로도 : https://www.tinkercad.com/things/5SiT1rqbOsh
최근 내용들이 코딩 난이도를 살작 올려서 포스팅이 되고 있는데 오늘도 코딩에 대한 내용을 채워질 것 같습니다. 아두이노의 전원이 공급되면 타이머가 돌기 시작합니다. 타이머가 도는 시간을 가져오기 위해서 millis()함수를 사용합니다. 현재 타이머의 시간값을 읽어오게 됩니다. 1초당 1000의 값을 갖게 되는데 이 시간값을 통해 우리는 시간을 만들어 낼 수 있습니다. 여기서, millis()함수를 통해서 읽은 각 자리의 숫자들을 하나씩 쪼개는 실험을 하겠습니다.
1. millis()함수
unsigned long millisTime = millis();
이렇게 시간값을 최대사이즈로 담을 수 있는 변수를 선언합니다. 아두이노에 전원이 공급되면 그때부터 타이머가 동작하고 타이머 변수에 숫자가 증가하는데 그 값을 millis()함수가 읽어서 millisTime 변수에 저장하게 됩니다.
1초 = 1000
정확히 어떤 값이 찍히는지 아래 움짤로 살펴보도록 할까요.
[소스]
1 2 3 4 5 6 7 8 9 | void setup() { Serial.begin( 9600 ); } void loop() { unsigned long millisTime = millis(); Serial.println(millisTime); } |
[결과]
가상시뮬레이터의 실행 시키면 타이머가 동작하여 millis()함수를 통해 읽은 시간값을 시리얼모니터로 출력되는 것을 보실 수 있을 꺼에요. 1초가 1000입니다.
2. millis()함수로 읽은 시간값 쪼개기
1) 수식
1 2 3 4 5 6 | unsigned long millisTime = millis(); int v1 = millisTime% 10 ; //일의 자리 int v2 = (millisTime/ 10 )% 10 ; //10의 자리 int v3 = (millisTime/ 100 )% 10 ; //100의 자리 int v4 = (millisTime/ 1000 )% 10 ; //1000의 자리 |
C언어에선 몫과 나머지 구하는 코딩을 알아야 합니다.
몫 : 123/10 => 12
나머지 : 123%10 =>3
그러면, millisTime에 저장된 시간값의 일의 자리를 구할려면 millisTime값을 10으로 나눈 나머지 값이 1의 자리가 됩니다. 이 원리를 이용해서 다음 10의 자리를 구할려면 어떻게 할까요. 일의 자리가 필요 없기 때문에 1의 자리를 버릴려면 millisTime값을 10으로 나눈 몫의 값을 구하면 됩니다. 그러면, 10이하의 1의 자리가 버려 집니다. 그 몫에다 다시 10을 나눈 나머지 값을 구하면 10의 자리 숫자를 구할 수 있게 됩니다.
쉽게 수식으로 살펴보면,
123%10 => 3
(123/10)%10 => (12)%10 => 2
(123/100)%10 => (1)%10 => 1
이렇게 자릿수 값들을 구하게 됩니다. 한번 가상시뮬레이터로 돌려 볼까요.
[소스]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | void setup() { Serial.begin( 9600 ); } void loop() { unsigned long millisTime = millis(); int v1 = millisTime% 10 ; int v2 = (millisTime/ 10 )% 10 ; int v3 = (millisTime/ 100 )% 10 ; int v4 = (millisTime/ 1000 )% 10 ; Serial.print(v4); Serial.print( " : " ); Serial.print(v3); Serial.print( " : " ); Serial.print(v2); Serial.print( " : " ); Serial.println(v1); } |
[결과]
각 숫자의 자리 수값들을 구하는게 그렇게 어렵지 않죠.
참고로, 원래 초단위로 일의 자리를 출력되게 할려면 다음과 같이 해줘야 합니다.
millisTime = millis()/1000;
처음 millisTime에 millis() 값을 1000으로 나눈 몫으로 하면 millisTime변수에 1이 들어 있으면 그 숫자는 1초가 됩니다. 그런데 가상시뮬레이터로 실험하는데 일의 자리를 1초로 실행시키면 전체 결과를 보는데 한참 걸리겠죠. 그래서 1000으로 나누지 않고 그냥 직접 숫자를 쪼개서 출력했네요.
2) 또 다른 방법
1 2 3 4 5 | unsigned long millisTime = millis()/ 1000 ; int v1 = millisTime% 10 ; int v2 = (millisTime/ 10 )% 10 ; int v3 = (millisTime/ 100 )% 10 ; int v4 = (millisTime/ 1000 )% 10 ; |
위 코딩에서 millis()/1000으로 세팅하면 1초가 일의 자리로 해서 출발하게 됩니다. 이 방법과 유사하게 아래와 같은 방식으로도 표현이 가능합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | unsigned long timeVal= 0 ; //이전 시간 void loop(){ if (millis()-timeVal>= 1000 ){ d1++; timeVal=millis(); } if (d1== 10 ){ d1= 0 ; d2++; } if (d2== 10 ){ d2= 0 ; d3++; } if (d3== 10 ){ d3= 0 ; d4++; } if (d4== 10 ){ d4= 0 ; } } |
if문으로 현재시간(millis()) - 이전시간(timeVal)의 차이가 1000보다 크거나 같다면 1초를 의미하게 됩니다 .그 때 d1을 1씩 증가 시키게 됩니다 이 말은 1초씩 증가한다는 의미랑 같습니다. 그리고, 1초일때 마다 timeVal은 millis()함수의 값을 저장함으로써 다음 1초를 비교하기 위한 이전시간값이 저장됩니다.
이걸 움짤로 촬영할려고 했더니 가상시뮬레이터가 너무 느리게 반응해서 다음과 같이 수정했습니다.
1 2 3 4 | if (millis()-timeVal>= 10 ){ d1++; timeVal=millis(); } |
d1 카운터를 10으로 낮추어서 돌도록 설정 했네요. 1초가 1000이니깐 0.01초 카운터가 되겠죠.
[결과]
3. 시간을 쪼개는 이유
7-segment display 와 같은 부품에 값을 출력할 때는 각 자리 숫자를 분해가 필요 합니다. 타이머 카운터 같은곳에서 응용으로 사용하기 딱 좋겠죠. 그리고, 이번에 post에서 다룬 이유는 다음에 4-digit 7-segment display를 사용한 실험을 하기 위해서 입니다. 1초 단위로 숫자를 4-digit 7-segment display에 출력을 한다면 millis()함수에서 읽은 시간값을 분해를 할 수 있는 능력이 필요하기 때문에 사전에 미리 학습차원으로 다루었네요.
마무리
오늘은 millis()함수에 대해서 간단히 살펴보았습니다. 알아두시면 나중에 아두이노를 다룰 때 유용하게 써먹을 수 있습니다.
'IOT > 아두이노' 카테고리의 다른 글
[아두이노] 시간(시/분/초) 변환 (0) | 2019.06.06 |
---|---|
[아두이노] 시간 millis()함수로 시간 카운트 (0) | 2019.06.05 |
[아두이노] 온도센서를 이용한 경보 온도계 다른 접근 (0) | 2019.06.03 |
[아두이노] 온도센서(TMP36)+LCD16x2 경보 온도계 응용 (0) | 2019.06.02 |
[아두이노] 수위 센서(Water Level Sensor) 제어 (2) | 2019.06.01 |