[아두이노] 아두이노등의 임베디드 시스템의 변수 값 오버플로우 문제

아두이노등의 임베디드 시스템의 변수 값 오버플로우 문제(Variable overflow problem in embedded systems)

아두이노에서 10ms 마다 스위치 상태를 검사하는 코드를 작성한다고 해 보자.

void loop() {
  static unsigned long last = 0;
  static boolean swPrev = HIGH;
  unsigned long now;

  now = millis();
  if ((now-last)>=10) {
    digitalWrite(13,digitalRead(10));
    last = millis();
  }
}

Untitled.jpg





위와 같은 코드가 될텐데 동작시켜 보면 생각한대로 아무 문제 없이 동작한다. 하지만 이 코드의 경우 치명적인 버그가 숨어있다. millis() 함수는 unsigned long 타입의 값을 리턴해 준다. unsigned long 타입의 경우 0 ~ 4,294,967,295 까지의 숫자가 들어갈 수 있다. 4,294,967,295 ms면 엄청나게 긴 시간(대략 50일)임에는 틀림없다. 하지만 임베디드 시스템의 경우 한번 켜 놓으면 전원을 끄지 않고 몇년씩 계속 동작시키는 경우도 흔하다. 위의 코드를 사용하면 처음부터 약 50일간은 문제없이 동작하지만 약 50일 정도가 지나 4,294,967,295 -> 0으로 변한 이후부터는 동작하지 않는 문제가 발생한다.

예를 들어 마지막으로 스위치를 감지했을 때 시간값이 last 변수에 들어가게 되는데 그 값이 4,294,967,290이었다고 해 보자. 그 때 부터 5 ms 후에는 4,294,967,295가 되고 다시 1ms가 더 지나면 4,294,967,256이 아니고 0이 되어 버린다. 즉 now-last 값이 6이 아니고 -4,294,967,290이 되어 버리는 것이다. 즉 그때 부터는 (now-last) > 10 이라는 조건이 만족될 수가 없게 되어 버리기 때문에 스위치가 눌렸는지 검사를 하지 않게 된다. 

Untitled%2B2.jpg

이런 타입의 에러가 임베디드 시스템에서 아주 악성인 이유는 프로그램을 만들어 테스트 해 보면 정상적으로 잘 동작한다는 것이다. 그래서 제품을 출시해도 아무 문제가 없는데 출시 시작한지 약 두달 정도가 지나면 문제가 발견되기 시작한다는 것이다. 그리고 디버깅을 위해 버그를 재현하기 위해 개발실에서 다시 테스트 해 보면 전원을 넣은지 50일이 지나지 않았기 때문에 버그를 재현할 수 없다. 개발자가 버그를 재현할 수 없으면 버그의 원인을 찾기 힘들기 때문에 디버깅이 매우 어렵다. 

처음부터 이런 부분을 생각해 변수 값이 overflow 되는 경우에도 동작할 수 있도록 프로그램을 작성하는 연습을 해야만 한다.

위의 코드라면 이런식으로 수정해 주면 된다.

#define MAX 0xFFFFFFFF

boolean diff(unsigned long now, unsigned long prev, unsigned long d)
{
  if (now>prev) return ((now-prev)>=d);
  else return (((MAX-prev)+now+1)>=d);
}

void loop() {
  static unsigned long last = 0;
  static boolean swPrev = HIGH;
  unsigned long now;

  now = millis();
  if (diff(now, last, 10)) {
    digitalWrite(13,digitalRead(10));
    swPrev = LOW;
    last = millis();
  }

}

Untitled%2B3.jpg

이제 now 변수의 값이 overflow 되어 0으로 돌아가도 정상적으로 비교되어 위에서 이야기 한 버그가 발생하지 않는걸 확인할 수 있다. 
0
0
이 글을 페이스북으로 퍼가기 이 글을 트위터로 퍼가기 이 글을 카카오스토리로 퍼가기 이 글을 밴드로 퍼가기

임베디드 보드

번호 제목 글쓴이 날짜 조회수
78 마이크로비트 아날로그 홀 센서 활용 (아두이노 센서 활용) icon HellMaker 08-08 8,555
77 마이크로비트 마이크로비트로 가위바위보 게임 일산메이커 08-01 8,505
76 마이크로비트 마이크로 비트로 led 문자 출력하기 2 #microbit #마이크로비트 #led Wavy 07-31 8,426
75 마이크로비트 마이크로비트 - led로 문자출력하기 #마이크로비트 #led #문자 #microbit +1 Wavy 07-30 7,889
74 마이크로비트 마이크로 비트로 간단하게 led켜기 (microbit easy led) #microbit #LED #led Wavy 07-24 8,084
73 마이크로비트 마이크로비트 교육자료 - 반응속도 게임 +1 일산메이커 07-19 9,374
72 아두이노 C 언어 비교문에서 == 사용 방법 icon 양재동메이커 04-12 9,593
71 아두이노 [아두이노 실습] 푸쉬버튼 long press, short press 판단하기 icon 양재동메이커 03-27 11,303
70 아두이노 [아두이노 실습] Push button 스위치로 FND 카운트 증가/감소 icon 양재동메이커 03-27 14,236
69 아두이노 Blynk를 사용해 아두이노에서 IoT 맛보기 icon 양재동메이커 03-27 11,828
68 아두이노 아두이노에서 u8glib로 0.96" OLED 사용하기 icon 양재동메이커 03-27 11,834
67 아두이노 아두이노에서 여러개의 스위치를 1개의 analog input핀으로 검사하기 icon 양재동메이커 03-27 10,918
66 아두이노 아두이노에서 RTOS 사용하기 (FreeRTOS in Arduino) icon 양재동메이커 03-27 13,775
65 아두이노 아두이노에서의 delay() 함수 icon 양재동메이커 03-27 10,077
64 아두이노 아두이노의 pinMode()에서 INPUT과 INPUT_PULLUP의 차이 icon 양재동메이커 03-27 12,216
63 아두이노 아두이노등의 임베디드 시스템의 변수 값 오버플로우 문제 icon 양재동메이커 03-27 8,827
62 아두이노 아두이노에서 외부 라이브러리 설치하기 (Install library in arduino) icon 양재동메이커 03-27 10,506
61 아두이노 WS2812 color LED 사용하기 icon 양재동메이커 03-27 9,672
60 아두이노 WS2812와 APA102의 차이 비교 (Comparison between WS2812 and APA102) icon 양재동메이커 03-27 11,265
59 아두이노 [강좌] 51. 와이파이 통신 (5) - WebServer 예제 (2) icon 양재동메이커 03-21 9,527