아두이노 기초 강좌 13 – 시간에 따른 작업 관리 millis()
아두이노 기초 강좌는 아두이노를 처음 접하시는 전자분야 비 전공자를 위한 강좌입니다. 이해를 위해서는 간단한 프로그래밍 지식이 필요할 수 있습니다. 프로그래밍이 처음이라면 [아두이노 프로그래밍 기초] 강좌를 먼저 읽으시길 권해 드립니다.
=============================================================
1. 아두이노의 시간 함수 millis()
앞선 강좌 12에서 delay 함수와 주의점에 대해서 살펴봤습니다. 버튼 입력처럼 빠르게 입력 상태를 체크해야 하는 경우 delay는 독이 될 수도 있다고 했죠.
그런데 앞선 강좌 12의 버튼 예제를 실행해보면 PC의 Serial monitor에 굉장히 빠르게 버튼의 상태가 표시됩니다. 아래처럼요.
000000011111100000…
보기도 불편하고 필요없이 PC로 너무 자주 데이터를 보내는 것 같습니다. 버튼의 상태 체크는 빠르게 계속 하면서 PC로 데이터를 보내는 것은 긴 간격(1초 정도?)으로 조절할 필요를 느끼실 겁니다.
그래서 필요한 것이 시간 함수 millis() 입니다.
unsigned long currentMillis = millis();
위와 같이 사용하면 millis() 함수가 현재시간(아두이노가 시작된 후부터 경과된 시간)을 밀리초 단위로(1/1000 초) 리턴해줍니다. 이걸 loop() 반복문을 돌때마다 체크하면 경과된 시간이 얼마인지를 알 수 있습니다.
이제 강좌 12에서 사용한 소스를 수정해 보겠습니다. 사용자 입력을 놓치지 않도록 버튼은 빠르게 계속 체크하면서, 1초에 한 번씩 PC로 버튼 상태를 전송하도록 하겠습니다.
2. 수정된 소스 예제
수정된 소스부터 보시죠.
// digital pin 2 has a pushbutton attached to it. Give it a name: int pushButton = 2; void setup() { // initialize serial communication at 9600 bits per second: Serial.begin(9600); // make the pushbutton's pin an input: pinMode(pushButton, INPUT); } int isClicked = LOW; unsigned long prev_time = 0; void loop() { // read the input pin: int buttonState = digitalRead(pushButton); if(buttonState == HIGH) { isClicked = HIGH; } unsigned long current_time = millis(); // if 1 second has passed after last check if(current_time - prev_time > 1000) { // print out the state of the button: Serial.println(isClicked); isClicked = LOW; } delay(1); // delay in between reads for stability }
수정된 부분 위주로 살펴 보겠습니다.
int isClicked = LOW: unsigned long prev_time = 0;
PC로 메시지를 보내기 전 1초 동안 클릭이 있었는지 저장하기 위해 isClicked 변수를 전역으로 만들었습니다. prev_time 변수는 PC로 메시지를 보내면 현재 시간을 저장해 두는 용도로 씁니다. 다음번 1초 경과를 체크할 때 이 값을 가지고 계속 비교합니다.
알고 갑시다!! 시간을 저장하는 prev_time 값은 unsigned long 형태입니다. 시간은 무조건 양수의 값을 사용하기 때문에 음수의 값을 사용하지 않고, 대신 저장할 숫자의 크기를 늘린겁니다. unsigned 구문이 의미하는 것이 이것입니다. 아두이노에서는 long 이 4byte 이고 [-2,147,483,648 ~ 2,147,483,647] 사이의 정수를 표현합니다. unsigned long은 음수를 버리는 대신 양수의 표현 범위가 2배로 늘어납니다. unsigned long으로 시간을 표현할 때 아두이노 실행 후 약 50일이 지나면 최대값에 도달하는데, 최대값이 되면 다시 0부터 계산하게 됩니다.
이제 loop 반복문 안을 살펴보겠습니다.
// read the input pin: int buttonState = digitalRead(pushButton); if(buttonState == HIGH) { isClicked = HIGH; }
사용자가 버튼을 누를 경우 buttonState 값은 HIGH 가 됩니다. HIGH 일 때 isClicked 값도 HIGH 로 기록해주면 1초 동안 한번이라도 사용자 입력이 감지되면 클릭이 된걸로 간주합니다. 1초 뒤 PC로 데이터를 보내고 나면 isClicked 값을 LOW로 초기화 해줘야 합니다. 다음 1초 동안의 사용자 입력 여부를 기록해야 하니까요.
unsigned long current_time = millis();
current_time 에 현재 시간을 기록해 둡니다. 이걸 미리 기억해둔 prev_time 과 비교해서 1초(=1000 ms)가 지났는지 확인할겁니다.
// if 1 second has passed after last check if(current_time - prev_time > 1000) { // print out the state of the button: Serial.println(isClicked); isClicked = LOW; prev_time = current_time; }
현재 시간에서 prev_time(지난번에 처리한 시간) 을 뺀 값이 1000 보다 크면 1초가 지난겁니다. 따라서 이때는 PC로 버튼 상태를 전송해주고, 다음번 체크를 위해 isClicked를 LOW로 초기화하고 prev_time 을 현재 시간인 current_time으로 교체합니다.
이 코드를 실행해보면 PC로 약 1초 마다 버튼 클릭여부가 전송될겁니다.
시간 함수 millis() 를 이용한 위와 같은 형태의 루틴은 사용할 일이 많습니다. 아두이노 뿐 아니라 다른 프로그래밍 언어나 플랫폼에서도 동일하니 기억해 둘 만한 코드입니다.
===============================================================
이 문서는 작성자의 동의없이 개인적인 목적 외의 상업적인 목적으로 활용되어서는 안됩니다.
이 문서의 일부 혹은 전체를 수정, 삭제, 재배포 하여서는 안됩니다.
작성자 : GodsTale (godstale@hotmail.com)