Search
Duplicate

millis()를 활용한 아두이노 중수되기

목차(클릭하세요)
delay함수가 이상한 이유: 매개변수에 정한 시간(밀리 초) 동안 프로그램 멈춤. (1초는 1000 밀리 초) 멈춘동안 다른 그 어떤것도 하지 못함

1. delay()함수의 딜레마

Q. 아두이노에서 다음과 같은 상황이 가능할까?
초록불은 1초마다 깜빡이고, 빨간불은 버튼 클릭시에만 불이 켜지는??
int green=10; int red=9; int push=3; void setup() { pinMode(green, OUTPUT); pinMode(red, OUTPUT); pinMode(push, INPUT); } void loop() { digitalWrite(green, HIGH); delay(1000); digitalWrite(green, LOW); delay(1000); digitalWrite(red, digitalRead(push)); delay(10); }
Arduino
복사
이런 식의 작동방식이 떠오르겠지만, 결론은 안됨
왜? 안될까?
delay()함수를 사용하게 되면 delay시간동안 아무것도 하지 않고 “기다리기 때문”에 하나의 동작이 끝나야 다음 동작을 하게 됨
결론: 여러가지의 동작(=작업)을 동작하려는 시간에 정확하게 동작하게 하기 위해서는 delay가 없는 코드를 사용해야 함

1-1. 해결방안 3가지

1.
시간 분할 방식 (Time Division Multiplexing):
“시간함수(millis)”를 사용
단일 실행 흐름에서 시간을 기반으로 특정 작업을 스케줄링하는 방법
스레드를 사용하는 방식은 아님
타이머 함수를 사용하여, 현재 시간과 이전에 수행된 작업의 시간 차이를 계산
2.
인터럽트 기반 방식
인터럽트는 특정 이벤트(예: 타이머, 외부 신호)가 발생했을 때, 주 실행 흐름을 잠시 중단하고, 해당 이벤트를 처리하는 함수(인터럽트 서비스 루틴, ISR)를 실행한 후, 중단된 실행 흐름을 다시 재개하는 방식
중요한 작업을 즉시 처리할 수 있으며, 배경에서 실행되는 다른 작업의 진행을 방해받지 않음
3.
멀티태스킹을 구현한 라이브러리 사용
ProtoThread, FreeRTOS와 같은 라이브러리를 사용

참고. 멀티쓰레드란?

하나의 프로세스 내에서 여러 개의 쓰레드가 동시에 실행되는 기술
각 쓰레드는 프로세스의 자원을 공유하면서 독립적인 작업을 수행

2. millis함수 사용해보기

2-1. 예제코드

const int ledPin = LED_BUILTIN; // the number of the LED pin // Variables will change: int ledState = LOW; // ledState used to set the LED // Generally, you should use "unsigned long" for variables that hold time // The value will quickly become too large for an int to store unsigned long previousMillis = 0; // will store last time LED was updated // constants won't change: const long interval = 1000; // interval at which to blink (milliseconds) void setup() { // set the digital pin as output: pinMode(ledPin, OUTPUT); } void loop() { unsigned long currentMillis = millis(); if (currentMillis - previousMillis >= interval) { // save the last time you blinked the LED previousMillis = currentMillis; // if the LED is off turn it on and vice-versa: if (ledState == LOW) { ledState = HIGH; } else { ledState = LOW; } // set the LED with the ledState of the variable: digitalWrite(ledPin, ledState); } }
Arduino
복사

2-2. 1초마다 hello를 전송하기(delay사용하지 않고)

millis() 함수의 리턴값이 매우 크므로 사용하는 변수는 항상 unsigned long으로 선언(양수 소수점만 취급)
2.
currTime = millis();
현재시간을 저장
3.
if(currTime - prevTime >= 1000)
1초가 지나면 해당 조건문이 참이 됨
4.
millis ()의 반환 값은 unsigned long 이므로 만약 int 와 같은 작은 자료형으로 산술을 수행하려고하면 논리 오류가 발생할 수 있음
unsigned long currTime = 0; unsigned long prevTime = 0; void setup() { Serial.begin(9600); } void loop() { currTime = millis(); if(currTime - prevTime >= 1000) { prevTime = currTime; Serial.println("hello"); } }
Arduino
복사

2-3. 1초마다 hello를 전송하고 0.5초마다 LED On(delay사용하지 않고)

1.
currTime 의 역할
1초마다 hello를 출력하기 위한 현재시간 저장 변수
2.
currTime1 의 역할
0.5초마다 LED를 출력하기 위한 현재시간 저장 변수
#define LED_RED 5 unsigned long currTime = 0; unsigned long prevTime = 0; unsigned long currTime1 = 0; unsigned long prevTime1 = 0; int ledState = 0; void setup() { Serial.begin(9600); pinMode(LED_RED,OUTPUT); } void loop() { currTime = millis(); if(currTime - prevTime >= 1000) { prevTime = currTime; Serial.println("hello"); } currTime1 = millis(); if(currTime1 - prevTime1 >= 500) { prevTime1 = currTime1; digitalWrite(LED_RED,ledState); ledState = !ledState; } }
Arduino
복사

3. millis와 사용자 정의 함수를 사용한 코드 가독성 높이기

왜 사용자 정의함수를 사용하는가? 코드가 길어지면 가독성이 떨어지므로

3-1. 사용자 정의함수

1.
사용자 정의함수란?
프로그래머가 직접 만든 함수
2.
작성법
앞에 반환되는 자료형을 붙임
void는 반환되는 값이 없음을 의미
int는 반환되는 값이 정수임을 의미
위치는 void loop() 하단, 또는 void setup()상단
3.
함수의 유형 4가지
유형1. 매개변수와 반환값이 모두 없는 경우. 매개변수(x), 반환값(x)
유형2. 매개변수는 있고 반환값이 없는 경우. 매개변수(o), 반환값(x)
유형3. 매개변수는 없고 반환값이 있는 경우. 매개변수(x), 반환값(o)
유형4. 매개변수와 반환값이 모두 있는 경우. 매개변수(o), 반환값(o)

3-2.코드 구현

static 변수란?(= 정적 변) 함수 내에서 선언되었을 때 그 함수를 벗어나도 그 값이 유지되게 하는 변수
1.
static변수의 특징
static 변수는 프로그램이 실행될 때 단 한 번만 초기화되며, 프로그램이 종료될 때까지 메모리에 남아있음
그 변수의 사용 범위(scope)는 선언된 함수 내로 제한
변수가 전역 변수처럼 동작하게 하면서도, 해당 변수를 선언한 함수 외부에서는 접근할 수 없게 하고 싶을 때 유용
#define LED_RED 5 void setup() { Serial.begin(9600); pinMode(LED_RED,OUTPUT); } void loop() { sayHelloSerial(); redLedFlash(); } //사용자 정의함수1 void sayHelloSerial() { static unsigned long currTime = 0; // 정적 변수 초기화 static unsigned long prevTime = 0; // 정적 변수 초기화 currTime = millis(); if(currTime - prevTime >= 1000) { prevTime = currTime; Serial.println("hello"); } } //사용자 정의함수2 void redLedFlash() { static unsigned long currTime = 0; //정적 변수 초기화 static unsigned long prevTime = 0; //정적 변수 초기화 static int ledState = 0; currTime = millis(); if(currTime - prevTime >= 500) { prevTime = currTime; digitalWrite(LED_RED,ledState); ledState = !ledState; } }
Arduino
복사