Arduino II에서 대기: 구조를 위한 millis() 함수
소개: 지연 없이 LED 깜박임()
첫 번째 게시물에서 우리는
delay()
패턴이 작업 사이를 기다리는 데 사용되지 않는 이유를 인용하기 위해 official Arduino tutorial에 연결했습니다. 그 당시에 완전히 읽었다면 아마도 이 게시물에서 제시할 대안인 millis()
function을 대신 사용하는 것을 망쳤을 것입니다.millis()
"Arduino 보드가 현재 프로그램을 실행하기 시작한 이후 경과된 밀리초 수를 반환"하므로 delay()
를 대체할 수 없습니다(그렇지 않으면 동일한 방법일 뿐입니다!).다음은
delay()
를 millis()
로 바꾸는 데 사용할 수 있는 패턴입니다( 와 비교할 수 있음).const int waitingMs = 2000; // 2 seconds
unsigned long previousMillis = 0;
bool ledState = LOW;
void setup() { pinMode(LED_BUILTIN, OUTPUT); }
void loop()
{
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= waitingMs)
{
previousMillis = currentMillis;
ledState = !ledState;
digitalWrite(LED_BUILTIN, ledState);
}
}
이 코드here도 찾을 수 있습니다.
previousMillis
)를 저장하기 위해 전역 변수를 생성하고 이를 0으로 초기화합니다. ledState
). millis()
를 호출하여 현재 밀리초 수를 가져오고 그 값을 currentMillis
라는 로컬 변수에 저장합니다. currentMillis
)와 저장한 밀리초 수( previousMillis
) 사이의 차이를 비교하여 대기하려는 시간( waitingMs
)보다 큰지 확인합니다.previousMillis
를 현재 밀리초 수(currentMillis
)로 업데이트하고 계획했던 모든 작업을 수행합니다(이 경우 LED 상태 변경: 값 업데이트 ledState
변수를 만들고 digitalWrite
메서드를 사용하여 적용합니다. 사례 연구로 돌아가기
우리는 간단한 레이저 절단기를 만들고 싶습니다.
우리는 상당히 올바른 상태 기계를 기반으로 식별했지만 주요 결함이 있었습니다. 크고 둥근 빨간색 비상 정지 버튼을 눌렀을 때 즉시(또는 전혀) 식별할 수 없다는 것입니다.
첫 번째 구현의 주요 문제는
delay()
method 을 사용하는 것인데, 기본적으로 우리가 원하는 만큼 자주 비상 버튼을 확인할 수 없습니다.millis()를 사용하는 솔루션
방금 배운 패턴을 코드에 적용해 보겠습니다.
const unsigned long waiting_time_ms = 3000; // 3s
unsigned long saved_moment = 0;
int state = 0;
void setup() { Serial.begin(9600); }
void loop()
{
unsigned long current_moment = millis();
if (current_moment - saved_moment >= waiting_time_ms)
{
saved_moment = current_moment;
state = ++state % 2; // 0 -> 1 -> 0 -> 1 -> 0 -> 1 -> 0 ...
do_action();
}
stop_in_case_of_emergency(); // This is checked every few milliseconds
}
void do_action()
{
switch(state)
{
case 0:
{
turn_laser_off();
turn_motor_on();
break;
}
case 1:
{
turn_motor_off();
turn_laser_on();
break;
}
}
}
void turn_laser_on() { Serial.println("laser on"); }
void turn_laser_off() { Serial.println("laser off"); }
void turn_motor_on() { Serial.println("motor on"); }
void turn_motor_off() { Serial.println("motor off"); }
bool is_emergency_button_pressed()
{
// Serial.println("Checking emergency button");
if(Serial.available())
{
Serial.println("Stopping due to emergency: " + Serial.readString());
Serial.println("Please reset");
return true;
}
return false;
}
void stop_in_case_of_emergency()
{
if (is_emergency_button_pressed())
{
turn_motor_off();
turn_laser_off();
while (0 != 1) { }
}
}
이 코드here도 찾을 수 있습니다.
이 구현과 이 구현 간의 주요 기능적 차이점은 여기에서 각 루프 반복이 몇 밀리초 동안만 지속된다는 것입니다(다른 경우에는 6초 이상).
Arduino는 이 코드를 실행하는 동안 더 많은 작업을 수행하지만 결국 그것이 우리가 가지고 있는 것입니다. 맞습니까? 우리는 추가 '가격'*을 지불하지 않습니다.
사실, 그것은 정반대입니다. 우리(제조자/프로그래머)에게 Arduino는
millis()
의 값을 계산하고 몇 밀리초마다 저장된 변수의 내용과 비교하는 것이 Arduino가 delay()
메서드에서 기다리는 것보다 훨씬 효율적입니다. , 전자를 사용하면 '대기'하는 동안 다른 작업을 수행할 수 있기 때문입니다.일반적으로 이
millis()
패턴은 Arduino 코딩 수준을 높이거나 실제 프로젝트에 사용하려는 경우 채택해야 하는 접근 방식입니다.이 시리즈에는 이 문제를 해결하는 더 복잡한 방법을 탐구하는 더 많은 항목이 있지만(계속 지켜봐 주십시오!), 모두 언급된
millis()
패턴에 의존하므로 먼저 해당 패턴을 이해하는 것이 중요합니다.* 단순한 일화로서 다음은 두 스케치를 컴파일한 결과입니다(arduino-cli 사용).
* Compiling 1_delay_implementation
Sketch uses 3664 bytes (11%) of program storage space. Maximum is 32256 bytes.
Global variables use 302 bytes (14%) of dynamic memory, leaving 1746 bytes for local variables. Maximum is 2048 bytes.
* Compiling 3_basic_millis_implementation
Sketch uses 3588 bytes (11%) of program storage space. Maximum is 32256 bytes.
Global variables use 282 bytes (13%) of dynamic memory, leaving 1766 bytes for local variables. Maximum is 2048 bytes.
millis를 사용하는 것이 스토리지 및 메모리 측면에서 약간 더 효율적입니다! 물론 실행할 때 초당 더 많은 작업을 실행하지만 동일한 코드를 반복해서 실행하는 이러한 종류의 장치에서 우리가 기꺼이 지불하는 가격은 작업 시간이 매우 짧기 때문입니다!
Reference
이 문제에 관하여(Arduino II에서 대기: 구조를 위한 millis() 함수), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/eduherminio/waiting-in-arduino-ii-millis-function-to-the-rescue-33k6텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)