이 블로그는 Web 환경을 이용한 원격 제어 기술에 필요한 지식을 공유 하기 위한 블로그 입니다.
실제 개발과 프로그램 예를 위하여 WiFi Module과 Raspberry Pi, Raspberry Pi Pico, ATmega128 보드, Arduino Mega 보드(ATmega2560)를 사용 합니다.

gpio-interrupt-arduino

ESP32 GPIO control - Arduino
ESP8266/ESP32 GPIO Port와 Interrupt - Arduino


  • ESP8266/ESP32 GPIO Port
    • ESP8266 GPIO Port
      • NodeMCU-8266의 Pin 예: 개발보드에 따라 Pin 배열이 다를 수 있기 때문에 자신이 사용하는 보드의 Pin 배열을 확인하여야 한다.
      • ESP8266 12-E chip에는 17개의 다 기능 핀이 있다. 그러나 모든 Pin이 개발보드의 Pin에 연결되어 있는 것은 아니다.
      • 위 NodeMCU-8266 개발보드(ESP8266 개발보드는 ESP-12E 기반 개발 보드 임)는 13개의 Pin을 갖고 있다. 개발보드에 따라 다른 Pin 배열을 갖고 있을 수 있기 때문에 자신 사용하는 개발보드의 Pin 배열을 확인하고 사용하여야 한다.
      • GPIO6 - GPIO11은 통합된 SPI flash에 연결되어 있기 때문에 다른 용도로는 권장되지 않는다. NodeMCU-8266 개발보드의 Pin에는 이들 Pin이 연결되어 있지 않다.
      • 아래 Pin은 Booting 시 영향을 받는다. Booting 시 영향을 고려하여 Pin을 사용하여야 한다.
        • GPIO0: 만약 LOW로 Pulled 상태이면 Booting에 실패하게 된다.
        • GPIO1: BOOT 시 HIGH 상태, 만약 LOW로 Pulled 상태이면 Booting에 실패하게 된다.
        • GPIO2: BOOT 시 HIGH 상태, 만약 LOW로 Pulled 상태이면 Booting에 실패하게 된다.
        • GPIO3: BOOT 시 HIGH 상태가 된다.
        • GPIO9: BOOT 시 HIGH 상태가 된다.
        • GPIO10: BOOT 시 HIGH 상태가 된다.
        • GPIO15: 만약 HIGH로 Pulled 상태이면 Booting에 실패하게 된다.
        • GPIO16: BOOT 시 HIGH 상태가 된다.
      • GPIO0는 개발보드의 Switch에 연결되어 있고 Booting 시 LOW 이면 FLASH Mode, HIGH 이면 BOOT Mode 가 된다. Booting이 종료된 다음에는 다른 용도로 사용할 수 있다.
      • GPIO2는 개발보드의 LED에 연결되어 있다. LED와 함께 연동되는 것이 문제되지 않는 경우에는 다른 용도로 사용할 수 있다.
      • GPIO16을 사용하여 ESP8266을 Deep sleep에서 Wake up 할 수 있다. Deep sleep에서 Wake up 용도로 사용하려면 GPIO16을 RST 핀에 연결해야 한다.
    • ESP32 GPIO Port
      • NodeMCU-32의 Pin 예: 개발보드에 따라 Pin 배열이 다를 수 있기 때문에 자신이 사용하는 보드의 Pin 배열을 확인하여야 한다.
      • ESP32 chip에는 48개의 다 기능 핀이 있다. 그러나 모든 Pin이 개발보드의 Pin에 연결되어 있는 것은 아니다.
      • 위 NodeMCU-32 개발보드(ESP32 개발보드는 ESP32-WROOM-32E Module 기반 개발보드 임)는 38개의 Pin을 갖고 있다. ESP32 DEVKIT V1 DOIT 개발보드는 36 Pin을 갖고 있기 때문에 자신이 사용하는 개발보드의 Pin 배열을 확인하고 사용하여야 한다.
      • 입력 전용 Pin: GPIO34, 35,36,39는 입력 전용 Pin 이다. 또한 이들 Pin은 내부 pull-down 저항이 없다.
      • GPIO6 - GPIO11은 ESP-WROOM-32에 통합된 SPI flash에 연결되어 있기 때문에 다른 용도로는 권장되지 않는다. 따라서 프로젝트에서 이들 핀을 사용하지 않아야 한다.
      • GPIO1,3,5,6 - 11(ESP-WROOM-32에 통합된 SPI flash에 연결됨), 14, 15는 부팅 또는 Reset 시 HIGH 상태이거나 PWM 신호를 출력(Boot mode selection 자료를 참고요)한다. 이러한 GPIO에 연결된 장치가 있는 경우 ESP32가 Reset 되거나 부팅될 때 예기치 않은 결과가 발생할 수 있다.
      • 각각의 GPIO의 최대 전류는 40mA 이다. LED 하나는 약 10 - 15mA의 전류를 필요로 한다.
      • GPIO0는 개발보드의 Switch에 연결되어 있고 Booting 시 LOW 이면 FLASH Mode, HIGH 이면 BOOT Mode 가 된다. Booting이 종료된 다음에는 다른 용도로 사용할 수 있다.
      • GPIO2는 개발보드의 LED에 연결되어 있다. LED와 함께 연동되는 것이 문제되지 않는 경우에는 다른 용도로 사용할 수 있다.
    • Arduino에서 자주 사용하는 GPIO 관련 함수
      • pinMode(pin, mode): GPIO Pin의 Mode를 설정한다.
        • pin: GPIO Pin 번호
        • mode: Pin mode
          • INPUT: 해당 Pin을 Input port로 설정(High impedance 상태)한다.
          • INPUT_PULLUP: 해당 Pin을 Input port로 설정하고, Pull Up 저항을 Enable 한다.
          • 주: Pin과 GND 사이에 Switch를 연결한 경우 Switch가 Open 상태일 때 Pin은 High 상태가 되고 Close 상태일 때 Low가 된다.

          • INPUT_PULLDOWN: 해당 Pin을 Input port로 설정하고, Pull Down 저항을 Enable 한다.
          • 주: Pin과 VDD 사이에 Switch를 연결한 경우 Switch가 Open 상태일 때 Pin은 Low 상태가 되고 Close 상태일 때 High가 된다.

          • OUTPUT: 해당 Pin을 Output port로 설정한다.
      • digitalWrite(pin, value)
        • value: Pin에 value 값(HIGH or LOW)을 출력한다.
      • digitalRead(pin): Pin의 상태(HIGH or LOW) 값을 읽는다.

    • ESP32 개발보드에 내장된 Switch(Push button)와 LED
      • Push button SW(GPIO0)와 LED(GPIO2) 실험을 위한 회로 구성 예
        • 위 회로의 SW(GPIO0)와 LED(GPIO2)는 아래와 같이 ESP32 개발보드에 내장되어 있기 때문에 실제 회로 구성은 하지 않아도 된다.


        ESP32 개발보드에 내장된 SW(GPIO0)와 LED(GPIO2) 위치

    • 프로그램 예: Switch(Push button)와 LED
      • Switch의 상태를 LED에 출력하는 프로그램 예: sw_status_led.ino

        
        // Pin 번호를 설정한다.
        // ESP 개발 보드에 내장된 Button SW(GPIO0)를 사용한다.
        const int buttonPin = 0;
        // ESP 개발 보드에 내장된 LED(GPIO2)를 사용한다.
        const int ledPin =  2;
        
        // Button 상태를 저장하는 Variable
        int buttonState = 0;
        
        void setup() {
          // Pushbutton pin을 Input pin으로 설정한다.
          pinMode(buttonPin, INPUT_PULLUP);
          // LED pin을 Output pin으로 설정한다.
          pinMode(ledPin, OUTPUT);
        }
        
        void loop() {
          // Pushbutton의 상태를 읽는다.
          buttonState = digitalRead(buttonPin);
          // if Pushbutton 이 pressed 되었으면
          if (buttonState == HIGH) {
            // LED를 on 한다.
            digitalWrite(ledPin, HIGH);
          } else {
            // LED를 off 한다.
            digitalWrite(ledPin, LOW);
          }
        }
                  
      • 실험을 위한 준비
        • LED: 개발보드에 내장(GPIO2)되어 있기 때문에 별도의 회로를 필요로 하지 않는다.
        • Button switch: 개발보드에 내장(GPIO0)되어 있기 때문에 별도의 회로를 필요로 하지 않는다.
      • 실험 방법
        • Arduino IDE를 실행하고Arduino IDE의 사용 환경(실행에 사용할 보드와 COM Port 선택)이 바르게 설정되어 있는지 확인한다.
        • 참고자료: "Arduino IDE에 ESP8266/32 Board Manager 설치하기"

        • 위 프로그램을 복사하여 Arduino IDE의 편집 창에 복사한다.
        • 편집 창의 프로그램을 File name "sw_status_led.ino"로 저장 한다.
        • 실험
          • "업로드" Icon을 클릭하면 프로그램이 컴파일되고 개발보드로 전송이 시작되는 매세지(Connecting... )가 출력된다.
          • 참고자료: "ESP8266/32에 Code Uploading 하기"

          • "Connecting... " 메세지가 출력된 다음 약 2Sec 동안 개발보드의 GPIO0 SW를 누르고 있으면(NodeMCU ESP8266 개발보드는 GPIO0를 프로그램에서 제어하기 때문에 GPIO0 SW를 누르지 않아도 됨) 개발 보드에 업로드가 시작된다.
          • 업로드가 종료되면 프로그램이 자동으로 실행된다.
          • 개발보드의 BOOT 버튼(GPIO0 Pin을 사용함)을 누르면 ESP32 보드인 경우 LED(GPIO2)가 On 되고 누르지 않으면 Off 상태가 된다. ESP8266 보드는 누르면 LED(GPIO2)가 Off 되고 누르지 않으면 On 상태가 된다.

  • 외부 인터럽트(External interrupt)
    • External interrupt 개요
      • External interrupt 은
        • External interrupt는 주변장치의 서비스 요청에 맞추어(동기 하여) 서비스를 실행 한다.
        • 외부 장치의 요구에 의해서 Interrupt가 발생하면 현재 실행 중인 프로그램을 잠시 멈추고, Interrupt에 의하여 요구된 작업을 먼저 수행한 후에 다시 원래의 프로그램으로 복귀하여 실행 한다.
        • Embedded System의 Program은 대부분 Interrupt Drive 방식으로 작성 한다.
      • External Interrupt에 사용하는 GPIO Pins
        • ESP32의 GPIO Pin은 모두 외부 신호를 받아 이 신호에 대응하는 인터럽트(External interrupt)를 발생 시키는 목적으로 사용 할 수 있다.
        • ESP8266의 경우 GPIO16을 제외한 모든 GPIO 핀을 사용하여 외부 인터럽트를 생성할 수 있다.
      • External Interrupt Trigger Events
        • 각 외부 인터럽트 핀에 대해 인터럽트를 트리거하는 5가지 다른 이벤트(응용 프로그램에 따라 선택)가 있다.

        • RISING : Rising Edge에서 Interrupt이 Trigger 된다.
        • FALLING : FALLING Edge에서 Interrupt이 Trigger 된다.
        • HIGH : HIGH 상태에서 Interrupt이 Trigger 된다.
        • LOW : LOW 상태에서 Interrupt이 Trigger 된다.
        • CHANGE : Pin의 상태가 변하면(HIGH -> LOW or LOW -> HIGH) Interrupt이 Trigger 된다.
        • 펄스 신호의 4가지 상태 예: 4가지 상태에 CHANGE를 포함하면 5가지 상태가 된다.

      • External Interrupt 설정에 사용하는 함수
        • Arduino Core에서는 아래와 같은 함수를 이용하여 인터럽트 기능을 활성화 한다.
        • attachInterrupt(GPIO_pin, ISR, Event);

          • GPIO_pin: External Interrupt Trigger에 사용하는 Pin 번호
          • ISR: Interrupt Service Routine 이름
          • Event: Trigger Event Type
        • Arduino Core에서는 아래와 같은 함수를 이용하여 인터럽트 기능을 비 활성화 한다.
        • detachInterrupt(GPIO_pin);

          • GPIO_pin: External Interrupt Trigger에 사용하는 Pin 번호
        • IRAM_ATTR 식별자(Identifier)
        • ISR을 내부 RAM memory에 배치하기 위하여 Espressif에서 권장하는 식별자(Identifier)이다. ISR을 내부 RAM memory에 배치하면 Flash memory에 배치된 경우에 비교하여 매우 빠르게 컨텍스트 전환 및 서비스가 실행된다.

        • 아래 함수는 noInterrupts()에 의해 비활성화된 인터럽트를 다시 활성화 한다.
        • interrupts();

        • 아래 함수는 Interrupts를 비 활성화 한다.
        • noInterrupts();

        주: External interrupt 이해에 도움이 되는 참고자료: "ATMega128 External Interrupt"

      • 프로그램 실행 중 Interrupts를 Turn on(interrupts()) 또는 Turn off(noInterrupts()) 하는 예
        • 
          // 여기에  Interrupt Function(ISR)를 작성한다.
          
          
          // Power-On 또는 ResetSetup 시 첫번째로 한번만 실행되는 설정(Setup) 프로그램을 작성한다.
          void setup() 
          {
            
          }
          
          // Startup function이 실행된 후 반복(Loop)되는 프로그램을 작성한다.
          void loop()
          {
            noInterrupts();
            // 시간에 민감한(실행 중 Interrupt 가 발생하면 안되는 Code)가 이 곳에 위치 한다.
          
            interrupts();
            // 시간에 민감하지 않은(실행 중 Interrupt 가 발생하여도 되는 Code)가 이 곳에 위치 한다.
          }
                  

    • 프로그램 예: External Interrupt(SW)를 이용한 LED 제어
      • Switch를 누르면 LED의 상태가 Toggle(현재 상태가 On 이면 Off 상태로, Off 상태인 경우는 On 상태로 됨)되는 프로그램 예
      • 
        // ESP 개발 보드에 내장된 Button SW(GPIO0)를 사용한다.
        const int buttonPin = 0;
        // ESP 개발 보드에 내장된 LED(GPIO2)를 사용한다.
        const int ledPin =  2;
         
        // 외부 인터럽트가 발생하면 실행되는 ISR(interrupt service routine)
        void IRAM_ATTR Ext_INT_ISR()
        {
          // Toggle The LED
          digitalWrite(ledPin, !digitalRead(ledPin));
        }
        
        // GPIO 입출력 핀 과 AttachInterrupt를 초기화한다.
        void setup()
        {
          // Pushbutton pin을 Input pin으로 설정한다.
          pinMode(buttonPin, INPUT_PULLUP);
          // LED pin을 Output pin으로 설정한다.
          pinMode(ledPin, OUTPUT);
          // Button SW가 눌리는 순간(Falling edge)
          // 인터럽트 ISR(Ext_INT_ISR)가 실행되도록 설정한다. 
          attachInterrupt(buttonPin, Ext_INT_ISR, FALLING);
        }
        
        // 무한 Loop를 실행하며 외부 인터럽트가 발생하기를 기다린다. 
        void loop()
        {
          // Do Nothing...
        }
                  
      • 실험을 위한 준비
        • LED: 개발보드에 내장(GPIO2)되어 있기 때문에 별도의 회로를 필요로 하지 않는다.
        • Button switch: 개발보드에 내장(GPIO0)되어 있기 때문에 별도의 회로를 필요로 하지 않는다.
      • 실험 방법
        • Arduino IDE를 실행하고Arduino IDE의 사용 환경(실행에 사용할 보드와 COM Port 선택)이 바르게 설정되어 있는지 확인한다.
        • 위 프로그램을 복사하여 Arduino IDE의 편집 창에 복사한다.
        • 편집 창의 프로그램을 File name "switch_toggle_led_interrupt.ino"로 저장 한다.
        • 실험
          • "업로드" Icon을 클릭하면 프로그램이 컴파일되고 개발보드로 전송이 시작되는 매세지(Connecting... )가 출력된다.
          • "Connecting... " 메세지가 출력된 다음 약 2Sec 동안 개발보드의 GPIO0 SW를 누르고 있으면(NodeMCU ESP8266 개발보드는 GPIO0를 프로그램에서 제어하기 때문에 GPIO0 SW를 누르지 않아도 됨) 개발 보드에 업로드가 시작된다.
          • 업로드가 종료되면 프로그램이 자동으로 실행된다.
          • 개발보드의 BOOT 버튼(GPIO0 Pin을 사용함)을 누르면 ESP32 보드인 경우 LED(GPIO2)의 상태가 Toggle(현재 Off 인 경우는 On 상태로 되고, 현재 On 인 경우는 Off 상태로) 된다.

          주: Switch의 상태가 이상적이지 않기 때문에 Switch를 누르면 Switch bouncing 현상에 의하여 가끔 오동작이 발생한다.


  • ESP8266/ESP32 GPIO Port와 Interrupt 관련 페이지 보기