[아두이노] 시간 millis()함수로 읽은 숫자 쪼개기

IOT/아두이노|2019. 6. 4. 09:00

[아두이노] 시간 millis()함수로 읽은 숫자 쪼개기



최근 내용들이 코딩 난이도를 살작 올려서 포스팅이 되고 있는데 오늘도 코딩에 대한 내용을 채워질 것 같습니다. 아두이노의 전원이 공급되면 타이머가 돌기 시작합니다. 타이머가 도는 시간을 가져오기 위해서 millis()함수를 사용합니다. 현재 타이머의 시간값을 읽어오게 됩니다. 1초당 1000의 값을 갖게 되는데 이 시간값을 통해 우리는 시간을 만들어 낼 수 있습니다. 여기서, millis()함수를 통해서 읽은 각 자리의 숫자들을 하나씩 쪼개는 실험을 하겠습니다.


1. millis()함수


unsigned long millisTime = millis();

이렇게 시간값을 최대사이즈로 담을 수 있는 변수를 선언합니다. 아두이노에 전원이 공급되면 그때부터 타이머가 동작하고 타이머 변수에 숫자가 증가하는데 그 값을 millis()함수가 읽어서 millisTime 변수에 저장하게 됩니다.

1초 = 1000

정확히 어떤 값이 찍히는지 아래 움짤로 살펴보도록 할까요.
[소스]

void setup()
{
  Serial.begin(9600);  
}
void loop()
{
  unsigned long millisTime = millis();
  Serial.println(millisTime);  
}

[결과]


가상시뮬레이터의 실행 시키면 타이머가 동작하여 millis()함수를 통해 읽은 시간값을 시리얼모니터로 출력되는 것을 보실 수 있을 꺼에요. 1초가 1000입니다.

2. millis()함수로 읽은 시간값 쪼개기


1) 수식

  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

이렇게 자릿수 값들을 구하게 됩니다. 한번 가상시뮬레이터로 돌려 볼까요.

[소스]

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) 또 다른 방법


  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초가 일의 자리로 해서 출발하게 됩니다. 이 방법과 유사하게 아래와 같은 방식으로도 표현이 가능합니다.

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초를 비교하기 위한 이전시간값이 저장됩니다.

이걸 움짤로 촬영할려고 했더니 가상시뮬레이터가 너무 느리게 반응해서 다음과 같이 수정했습니다.

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()함수에 대해서 간단히 살펴보았습니다. 알아두시면 나중에 아두이노를 다룰 때 유용하게 써먹을 수 있습니다.

댓글()