본문 바로가기
ESP32/ESP32

ESP32 인터럽트(Interrupt) 구현하기 - PIR(인체감지센서)

by 빈이쥬 2024. 10. 17.

 ESP32와 PIR 인체감지센서를 사용하여 인터럽트를 구현해 보겠습니다.

모션이 감지되면 ESP32는 타이머를 시작하고 정해진 시간 동안 LED를 켭니다. 타이머가 카운트를 마치면 LED가 자동으로 꺼집니다.

 

부품

ESP32

PIR 센서(인체감지센서)

5mm LED

330옴 저할

점퍼와이어 

브래드보드

 

인터럽트 소개

인터럽트는 마이크로컨트롤러 프로그램에서 특정 이벤트가 발생할 때 자동으로 처리를 수행하게 하며, 타이밍 문제 해결에 유용합니다. 이를 통해 핀의 값을 지속적으로 확인하지 않아도 되고, 값의 변화가 감지되면 즉시 이벤트(함수)가 트리거되어 필요한 작업을 수행합니다.

 

인터럽트 설정하기 

인수로 GPIO 핀, 실행할 함수 이름, 모드를 가지고 있습니다. 

attachInterrupt(digitalPinToInterrupt(GPIO), function, mode);

 

GPIO 인터럽트

첫 번째 인수는 GPIO 핀번호입니다. 

digitalPinToInterrupt(27); //GPIO27 사용

 

ESP32 보드에서 빨간색 박스핀을 제외한 모든 핀을 인터럽트 핀으로 구성할 수 있습니다.

 

 

GPIO6, 7, 8, 9, 10, 11 을 제외한 모든핀에 사용가능.

 

트리거 기능

두 번째 인수은 인터럽트가 발생할 때마다 호출되는 함수의 이름입니다. attachInterrupt()

 

mode

세 번째 인수는 mode입니다. 5가지 다른 mode가 있습니다.

  • LOW: 핀이 LOW일 때마다 인터럽트를 트리거 됩니다.
  • HIGH: 핀이 HIGH일 때마다 인터럽트를 트리거 됩니다.
  • CHANGE: 핀 값이 변경될 때마다 인터럽트를 트리거합니다. 예를 들어, HIGH에서 LOW로 또는 LOW에서 HIGH로 변경됩니다.
  • FALLING: 핀이 HIGH에서 LOW로 바뀔 때 트리거 됩니다
  • RISING: 핀이 LOW에서 HIGH로 바뀔 때 트리거 됩니다.

이 예제에서는 RISING 모드를 사용합니다. PIR 모션 센서가 움직임을 감지하면 연결된 GPIO가 LOW에서 HIGH로 전환되기 때문입니다.

 

회로도

사용하는 PIR센서가 3.3V로 작동한다면 PIR센서를 3.3V에 연결해야합니다. 

LED는 GPIO16 PIR센서는 GPIO 21에 연결합니다. 

코드 업로드

 

 

#define timeSeconds 10 // LED가 켜진 후 꺼질 때까지의 시간(초) 설정

// LED와 PIR 모션 센서를 위한 GPIO 핀 설정
const int led = 16; // LED가 연결된 핀 번호
const int motionSensor = 21 // 모션 센서가 연결된 핀 번호

// 타이머 변수
unsigned long now = millis(); // 현재 시간을 저장하는 변수
unsigned long lastTrigger = 0; // 마지막으로 모션이 감지된 시간을 저장하는 변수
boolean startTimer = false; // 타이머가 작동 중인지 여부를 저장하는 변수
boolean motion = false; // 모션 감지 상태를 저장하는 변수

// 모션이 감지되었을 때 LED를 HIGH로 설정하고 타이머 시작
void IRAM_ATTR detectsMovement() {
  digitalWrite(led, HIGH); // 모션이 감지되면 LED 켜짐
  startTimer = true; // 타이머 시작
  lastTrigger = millis(); // 마지막으로 모션이 감지된 시간을 현재 시간으로 설정
}

void setup() {
  // 시리얼 포트 설정
  Serial.begin(115200);
  
  // PIR 모션 센서 모드 설정 (INPUT_PULLUP 사용)
  pinMode(motionSensor, INPUT_PULLUP); 
  // 모션 센서 핀에 인터럽트 설정, 인터럽트 함수 할당 및 RISING 모드 설정
  attachInterrupt(digitalPinToInterrupt(motionSensor), detectsMovement, RISING);

  // LED를 LOW로 설정
  pinMode(led, OUTPUT); 
  digitalWrite(led, LOW); // 기본적으로 LED를 꺼둠
}

void loop() {
  // 현재 시간 저장
  now = millis();
  
  // 모션이 감지되었고, motion 상태가 false일 때 출력
  if((digitalRead(led) == HIGH) && (motion == false)) {
    Serial.println("MOTION DETECTED!!!"); // 모션이 감지되었다고 출력
    motion = true; // 모션 감지 상태로 설정
  }
  
  // timeSeconds 변수에 정의된 시간이 지나면 LED를 끔
  if(startTimer && (now - lastTrigger > (timeSeconds*1000))) {
    Serial.println("Motion stopped..."); // 모션이 멈췄음을 출력
    digitalWrite(led, LOW); // LED를 끔
    startTimer = false; // 타이머 종료
    motion = false; // 모션 감지 상태를 false로 변경
  }
}

 

코드 작동 방식

 먼저 두 개의 GPIO 핀을 할당합니다.

// LED와 PIR 모션 센서를 위한 GPIO 핀 설정
const int led = 16; // LED가 연결된 핀 번호
const int motionSensor = 21 // 모션 센서가 연결된 핀 번호

 

움직임이 감지되면 LED가 꺼지도록 타이머를 설정할 수 있는 변수를 만듭니다.

unsigned long now = millis(); // 현재 시간을 저장하는 변수
unsigned long lastTrigger = 0; // 마지막으로 모션이 감지된 시간을 저장하는 변수
boolean startTimer = false; // 타이머가 작동 중인지 여부를 저장하는 변수
boolean motion = false; // 모션 감지 상태를 저장하는 변수

setup()

 직렬 포트를 115200 통신 속도로 초기화하여 시작합니다.

  Serial.begin(115200);

 

PIR 모션 센서를 INPUT PULLUP으로 설정합니다.

pinMode(motionSensor, INPUT_PULLUP);

 

PIR 센서 핀을 인터럽트로 설정

attachInterrupt(digitalPinToInterrupt(motionSensor), detectsMovement, RISING);

 

LED는 pinMode설정 및 LED OFF

pinMode(led, OUTPUT);
digitalWrite(led, LOW);

 

loop()

 

현재 시간을 millis() 함수로 가져와 now 변수에 저장합니다. millis() 함수는 프로그램이 시작된 후 경과된 시간을 밀리초 단위로 반환하며, 이를 통해 타이머 기능을 구현합니다.

now = millis();

 

조건문은 LED가 켜져 있고(digitalRead(led) == HIGH), 아직 motion 상태가 false일 때 동작합니다. 즉, 모션이 처음 감지된 상황을 의미합니다. 이때 "MOTION DETECTED!!!"라는 메시지를 시리얼 모니터에 출력하고, motion 변수를 true로 설정하여 모션이 감지되었음을 기록합니다.

  // 모션이 감지되었고, motion 상태가 false일 때 출력
  if((digitalRead(led) == HIGH) && (motion == false)) {
    Serial.println("MOTION DETECTED!!!"); // 모션이 감지되었다고 출력
    motion = true; // 모션 감지 상태로 설정
  }

 

 

startTimer가 true로 설정되어 있고, 현재 시간(now)에서 마지막으로 모션이 감지된 시간(lastTrigger)을 뺀 값이 timeSeconds에 설정된 시간을 초과했을 경우(여기서는 10초), LED를 끄고 타이머를 종료합니다.

Serial.println("Motion stopped...")로 모션이 멈췄음을 시리얼 모니터에 출력하고, digitalWrite(led, LOW)로 LED를 끄며, startTimer와 motion을 false로 설정하여 타이머와 모션 감지 상태를 초기화합니다.

if(startTimer && (now - lastTrigger > (timeSeconds*1000))) { 
  Serial.println("Motion stopped..."); 
  digitalWrite(led, LOW); 
  startTimer = false; 
  motion = false; 
}

 

 

이렇게 loop 부분은 현재 시간을 추적하여 모션이 감지되었을 때 타이머를 설정하고, 일정 시간이 지나면 LED를 끄는 방식으로 동작합니다.

 

 

시리얼 모니터에 해당 값을 출력합니다. 

 

 

글자가 출력되지 않는다면 9600 baud 에서 115200 baud로 변경해주세요.

 

PIR센서를 사용하여 인터럽트를 구현해 보았습니다. 감사합니다