[아두이노] [강좌] 26. 시간 관련 함수 (1) - delay() / millis()

강좌가 tone() 함수 앞에 왔어야 되는데..brown_and_cony-21



*줄줄이사탕 주의 : 최대한 쉽게 설명하려고 했지만, 타이머/카운터 기능 자체가 쉽게 설명이 되는 기능이 아니라 강좌를 쓰다보니 주절주절하게 됐..ㅜㅜ 중요하지 않으므로, 함수를 사용하는 방법만 이해하고 넘어가도 됨.



우리가 처음 살펴봤던 예제 “Blink”에서 LED 1초 간격으로 켜고 끄기 위해 delay() 함수를 사용했었다그리고 다른 많은 예제에서도delay() 함수는 유용하게 사용되며이 전의 인터럽트 강좌에서는 delayMicroseconds() 함수까지 사용했었다.

 

그때 delay() 함수는 타이머 인터럽트를 사용하는 함수이므로 ISR(Interrupt Service Routine, 인터럽트 처리 함수)에서는 사용할 수 없으며대신 타이머 인터럽트를 사용하지 않는 delayMicroseconds() 함수는 사용할 수 있다고 잠시 설명했었는데이건 참고에 있던 내용이라 못 본 사람도 있겠군.

 

 

아두이노에서는 시간과 관련된 기능을 제공하기 위해서 하나의 타이머를 기본 타이머로 설정하여 사용하고 있으며이 타이머를 이용하는 기본 함수는 delay() 함수와 millis() 함수이다.



타이머에 관해서는 나중에 따로 자세히 포스팅하려고 계획 중이지만, 개념에 관한 설명이 될 것 같아서 넣을까 말까 아직 고민 중임. 간단하게는 지난 강좌에서 설명했고. 이 것도 "참고"에 있던 내용이라 못 봤을 수도..ㅎㅎㅎㅎ



 




아무튼 아두이노에 전원을 딱 넣으면 setup() 함수의 내용을 실행하기 전 기본 세팅을 하도록 되어있는데바로 여기에서 타이머가 설정된다설정되는 타이머는 0번 타이머.

 

아두이노 보드의 종류에 따라 각각 보유하고 있는 타이머의 개수가 다른데우노는 3메가는 6이 타이머들을 모두 항상 사용하는 건 아니지만, 0번 타이머 하나는 항상 사용된다고 보면 된다. 나머지는 analogWrite() 함수라던지, tone() 함수 등에 사용된다.

 



우선 함수부터 살펴보자. 



millis()

 


 반환 값


 ms : 전원이 인가된 이후의 시간. 밀리초. (unsigned long 타입)

 

 



말했다시피 아두이노 보드에 전원이 인가된 후 얼마만큼의 시간이 지났는지를 밀리초 단위로 반환한다반환 값의 데이터 타입은 unsigned long 타입이고, unsigned long 타입(4바이트)이 가질 수 있는 최대 값은 4,294,967,295이며이 값으로 약 49.71일을 셀 수 있다 50일 정도가 지나면 다시 0부터 시작한다는 뜻.

 

반환 타입이 unsigned long이라는 점에 유의해야 한다만일 int 같은 다른 데이터 타입으로 값을 저장할 경우 사용자의 의도와는 다른 결과가 나타날 수 있다라고 아두이노 홈페이지에 써있어요.

 

delay() 함수를 사용해서 동작을 멈추게 되면 시리얼 통신이나 센서 체크 등의 기능을 사용할 수 없게 되는 경우가 많기 때문에 delay() 함수 대신 millis() 함수를 이용한 시간 처리 루틴을 만들어 사용하기도 한다.

 

 

micros()

 

 

 반환 값


 us : 전원이 인가된 이후의 시간. 마이크로초. (unsigned long 타입)




millis()와 동일한 동작을 하지만 반환 값이 마이크로초 단위이다, 16MHz의 보드에서 (메가와 우노 모두 16MHz의 클럭 속도를 가진다) micros() 함수로 반환되는 값은 항상 4로 나누어 떨어지는 값이며따라서 최대 3.9999 마이크로초의 오차가 발생할 수 있다.

 

millis() 함수와 마찬가지로 반환 타입이 unsigned long이므로 micros()의 반환 값은 약 71분에 한번씩 0으로 되돌아간다.

 



위에서 말했다시피, millis() 함수와 micros() 함수는 모두 타이머/카운터 기능을 사용해서 동작한다. 


타이머/카운터는 칩이 구동하기 위한 클럭(clock)을 기준으로 증가하는 카운터를 활용하여 시간을 계산하는 기능이다클럭과 동일하게 카운터가 증가하게 되면 너무 큰 수의 값이 사용되기 때문에 적당한 값으로 클럭을 나눠서 사용(이를 분주(Prescale)라 한다)하고그렇게 증가하는 값이 일정한 값이 되었을 때 인터럽트가 발생인터럽트 처리 함수에서 그 카운터 값을 활용하여 실제 시간 값을 계산해 저장하게 된다.




brown_and_cony-53 


 


타이머 인터럽트를 사용하기 때문에, attachInterrupt() 함수로 설정한 인터럽트 처리 루틴에서 millis() 함수나 micros() 함수를 사용할 수 없다. (사용할 수는 있어도 값이 변하지 않기 때문에 소용이 없다하나의 인터럽트가 처리 중일 때 다른 인터럽트가 처리될 수 없으므로.)



 


delay(ms)

 

이미 많이 사용했던 함수지만 다시 한번 살펴보자.



 매개 변수

 

 ms : 밀리초 단위로 프로그램이 대기해야 할 시간을 지정한다. unsigned long 타입이므로최대 49.71일까지 설정할 수 있다. (근데 그만큼 설정할 일은 아마 없…)


 



간단히 설명하면 이렇고좀 더 자세히 설명하자면 우선 delay() 함수의 내용을 보자. (몰라도 됨 주의)



  

 void delay(unsigned long ms)

 {

           uint16_t start = (uint16_t)micros();

 

           while (ms > 0) {

                     if (((uint16_t)micros() - start) >= 1000) {

                                ms--;

                                start += 1000;

                     }

           }

 }


 

 



micros() 함수는 전원이 인가된 후로 지난 시간을 마이크로초 단위로 반환하고, delay() 함수가 시작될 때 start 변수에 저장된다그리고while() 문을 반복하며, micros() 함수가 반환하는 시간(시간이 지날수록 micros() 함수가 반환하는 값이 점점 커질테니)이 start 변수에 저장된 시간과 비교해서 1000을 넘을 경우 1000 마이크로초(=1 밀리초)가 지나면 매개 변수로 받은 ms 값을 1 감소시킨다이 동작을ms 값이 0보다 같거나 작아질 때까지 반복한다.

 

그래서 설정한 ms 밀리초만큼 대기하게 된다,는 원리.



delay() 함수 내에서 micros() 함수가 사용되므로, delay() 함수 역시 인터럽트 처리 루틴 내에서 사용할 수 없다. 




delayMicroseconds(us)

 

매개 변수 us는 마이크로초 단위의 시간을 나타내는 unsigned long 타입의 변수이다.

 

이 함수는 micros() 함수를 이용하지 않는다단지 us 값이 0이 될 때까지 us 값을 1씩 감소시키는 구문을 어셈블리어(기계어)로 처리한다이 어셈블리 구문이 총 4클럭을 소요하게 되므로 아두이노 보드의 클럭 속도에 맞춰 us 값을 적당히 곱해주는 작업이 이 전에 처리된다.



brown_and_cony-17brown_and_cony-17brown_and_cony-17brown_and_cony-17



어렵게 들릴지 모르겠지만, 간단하게 말하면 설정한 마이크로초만큼의 시간동안 아무 의미 없는 명령어를 읽어오고 분석하는 것을 반복한다는 뜻. delay() 함수처럼 micros() 함수를 사용하는 것이 아니므로, 인터럽트와는 상관 없이 사용할 수 있다. 





인터럽트 강좌에서는 millis() 함수나 micros() 함수에 대해 아직 다뤄보지 않았기 때문에 채터링 현상을 delayMicroseconds() 함수로 처리했지만, 사실은 인터럽트 루틴 내에서는 delay() 함수든 delayMicrosecodns() 함수든 사용하지 않는 것이 좋다. 인터럽트 루틴은 처리 시간이 최소화 되어야 다른 인터럽트에 영향이 없기 때문. 


다음 강좌에서는 delay() 함수나 delayMicroseconds() 함수를 사용하지 않고 시간 지연을 줄 수 있는 방법에 대해서 알아보자. 



그럼 이만. 뿅!


0
0
이 글을 페이스북으로 퍼가기 이 글을 트위터로 퍼가기 이 글을 카카오스토리로 퍼가기 이 글을 밴드로 퍼가기

임베디드 보드

번호 제목 글쓴이 날짜 조회수
118 아두이노 ESP32 Analog Inputs (ADC) +4 icon 양재동메이커 02-12 16,139
117 아두이노 TIP : Serial의 Port가 Open 시점 확인 icon 양재동메이커 01-21 12,992
116 아두이노 ESP32 Boot Mode icon 양재동메이커 12-28 12,835
115 아두이노 아두이노 에러 리스트(Arduino Error list) icon 양재동메이커 11-24 17,818
114 아두이노 ESP32 main.cpp +1 icon 양재동메이커 11-19 13,181
113 아두이노 ESP32 EEPROM 와 IR Remote icon 양재동메이커 08-06 13,074
112 아두이노 Learn ESP32 icon 양재동메이커 06-25 12,655
111 라즈베리 파이 라즈베리 파이 (Raspberry Pi) 기초 icon 양재동메이커 06-19 14,150
110 라즈베리 파이 (동영상 강의) 라즈베리 파이 강좌 Link icon 양재동메이커 06-17 13,249
109 STM32 / MBED [MED] Switch debouncing icon HellMaker 12-30 15,226
108 기타 [타이젠] 아두이노의 16x2 LCD Display라이브러리 LiquidCrystal_I2C의 타이젠 포팅 icon 양재동메이커 09-15 14,803
107 기타 [타이젠] GPIO의 디지탈 출력과 입력 인터럽트의 C++ Class 제작 icon 양재동메이커 09-12 14,280
106 마이크로비트 서보 모터 icon HellMaker 09-03 14,098
105 마이크로비트 아날로그 온도센서 (마이크로 비트 센서 활용) icon HellMaker 09-01 14,606
104 마이크로비트 터치센서 (마이크로 비트 센서 활용) icon HellMaker 09-01 13,720
103 마이크로비트 디지털 홀 센서 (마이크로 비트 센서 활용) icon HellMaker 08-29 12,900
102 마이크로비트 리니어 홀 센서 (마이크로 비트 센서 활용) icon HellMaker 08-29 12,455
101 마이크로비트 불꽃 감지 센서 (마이크로 비트 센서 활용) icon HellMaker 08-26 12,794
100 마이크로비트 로터리 엔코더 (마이크로 비트 센서 활용) icon HellMaker 08-25 12,901
99 마이크로비트 2컬러 LED(3mm) (센서 활용) icon HellMaker 08-22 12,901