[아두이노] millis() 함수 활용과 오버플로우 처리

아두이노 millis() 함수활용 및 오버플로우 처리

흔히 사용되는 delay() 함수는 프로그램을 ms 단위로 정지시키기 위해서 사용합니다. 그에 반히 millis() 함수는 아두이노 프로그램이 구동된 후 경과시간을 ms 단위로 반환합니다.


delay() 함수 대신 millis() 함수를 사용하면 어떤 장점이 있는지 보겠습니다. loop() 함수를 1초마다 주기로 구동시키려 아래와 같이 작성했다고 가정합니다.


위 코드는 의도한대로 거의 1초마다 loop() 구간을 반복합니다. 만약 위 코드에서 millis() 함수 대신 delay(1000)을 사용하면 어떤 문제가 생길까요?

delay() 함수를 사용한 코드는 정확히 1초마다 동작되지 않습니다. Serial.println("Hello"); 명령은 다소 시간이 걸리는 코드이기 때문입니다. 그렇다고 Serial.println("Hello"); 명령이 실행되는데 걸리는 시간을 빼고 delay() 함수를 실행시키는 것도 무언가 비합리적입니다.


이처럼 millis() 함수는 데이터 샘플링과 같이, 비교적 정확한 타이밍 처리가 필요할 때 적합합니다. 


delay() 함수는 실행되는 동안 delay() 함수 다음의 명령어들이 실행되는 것을 막지만 millis() 함수를 활용하면 millis() 함수 다음의 명령어들을 계속해서 실행할 수 있습니다. 즉, 논블로킹(Non-blocking) 모드가 되는 것입니다.


millis() 함수를 사용하는 경우 한가지 유의해할 점은, 50일 정도가 지나면 millis() 반환값이 오버플로우(overflow)가 된다는 것입니다. 즉 millis() 반환값이 0으로 작아졌다가 다시 증가한다는 것입니다. micros()를 사용하는 경우 70분 정도 지나면 오버플로우가 됩니다.


위 코드에서 millis() 함수가 오버플로우 되는 시점에 millis() 반환값이 time_now값보다 작아지면서 위 로직이 성립이 안되게 되는 것입니다. 이 문제를 해결하기 위해서는 아래와 같이 if문 안에 부등식을 조금 수정하면 됩니다.


위와 같이 부등식을 변경하면 unsigned int의 뺄샘 속성(정확히는 modulo wrapping 처리에 의한)에 의해 우리가 애초에 원하는 방식대로 동작하게 됩니다. 간단한 코드로 이 내용을 재확인해 봅시다.



위 코드를 실행하면 숫자 2가 표기됩니다. 따라서 loop()내 if문에서 millis() 반환값이 time_now보다 적어도 문제가 없이 실행이 됩니다.

여러 플렛폼에서 정상적으로 동작시키기 위해 아래와 같이 명시적으로 데이터 타입을 기술해 주는 것도 좋은 방법입니다.

끝.

댓글

이 블로그의 인기 게시물

[PLC] PLC 아날로그 입출력 기본

전력(kW) 계산하기 (직류, 교류 단상, 교류 삼상)

공압 속도 제어: 미터인 vs 미터아웃

[PLC] 채터링 현상과 입력 필터

제너 다이오드에 저항을 연결하는 이유

[python] 파이썬 pyplot 2차원 그래프 샘플 코드

[PLC] 래더 다이어그램과 PLC

공압회로 기호

[PLC] PLC 입출력 타입 - 싱크 & 소스 (Sink & Source)

3선 결선식 센서의 타입 PNP, NPN