ESP32 GPIO 기반 LED 제어 및 디지털 신호 입출력 실무 분석

LED 전기적 특성과 보호 회로 설계

일반적으로 5mm 직경의 LED 는 연속 작동 시 권장 전류가 20mA 이하입니다. 가변 전원 공급 장치와 직렬 저항기를 사용하여 각 색상별 전압 강하와 밝기의 상관관계를 실험적으로 확인했습니다. 170 옴 저항을 통한 측정한 결과, 특정 LED 배치에서 다음과 같은 전압-전류 특성을 나타냅니다.

색상 1mA 시작 5mA (밝음) 10mA (매우 밝음) 15mA (강렬) 20mA (위험)
빨간색 시작 지점 1.98V 2.04V 2.08V 2.13V
초록색 시작 지점 1.96V 2.00V 2.03V 2.04V
노란색 시작 지점 1.96V 2.01V 2.04V 2.07V
파란색 시작 지점 2.72V 2.77V 2.85V 2.91V
흰색 시작 지점 2.82V 2.92V 3.01V 3.07V

실험 데이터를 바탕으로 분석했을 때, 1~2mA 구간에서도 가시적인 발광이 시작되며, 10mA 에서 충분한 밝기를 확보합니다. ESP32 의 GPIO 포트는 최대 40mA까지 전류를 공급할 수 있어, 저항 없이 연결 시 LED 소자 또는 보드가 손상될 위험이 있습니다. 특히 단락 상태로 파손된 LED 가 ESP32 의 안정성에 악영향을 줄 수 있으므로, 반드시 제한 저항을 직렬로 삽입해야 합니다. 안전 설계를 위해 계산값은 보통 100옴에서 200옭 사이로 선정하는 것이 좋습니다.

GPIO 출력 설정 및 플래시 업 프로세스

EEPROM 관련 기능이나 내부 결함으로 인해 비권장 되는 핀을 제외한 경우, 일반 출력용으로 사용할 수 있는 GPIO 핀들은 보드 제조사에 따라 차이가 있을 수 있으며, 일반적으로 번호가 명확히 정의된 핀들을 사용해야 합니다. 예를 들어 내장 LED 가 연결된 핀은 주로 GPIO 2 번이며, 높은 레벨 (HIGH) 신호에 반응합니다. 초기 출력 테스트 코드는 다음과 같습니다:


#define TARGET_PIN 2

void setup() {
  pinMode(TARGET_PIN, OUTPUT);
}

void loop() {
  digitalWrite(TARGET_PIN, HIGH);
  delay(1000);
  digitalWrite(TARGET_PIN, LOW);
  delay(1000);
}

Average MCU 개발 환경과 달리 ESP32 플랫폼의 일부 보드는 프로그램 다운로드 시 별도의 하드웨어 조작이 필요합니다. ATmega 칩셋과 같이 IDE '업로드' 버튼 하나로 자동 리셋되지 않는 경우가 많으므로, 다운로드 과정에는 BOOT 버튼 조작이 동반되어야 합니다. 성공적인 다운로드를 위해서는 다음과 같은 두 가지 절차를 준수해야 하며, 첫 번째 방식이 가장 안정적입니다.

  • 권장 방식: BOOT 버튼을 누른 상태에서 USB 연결 후 IDE 업로드 명령어를 실행합니다. IDE 에서 '접속 중...' 메시지 출현 시 BOOT 버튼을 해제한 뒤, RST 버튼을 눌러 새 프로그램을 실행합니다.
  • 변형 방식: 업로드 진행 상황을 모니터링하며 '접속 중' 단계에만 잠깐 BOOT 버튼을 탭하는 방법입니다. 하지만 이 방법은 통신 안정성이 낮아 다운로드 실패율이 높으므로 권장하지 않습니다.

여러 개의 LED 를 제어하여 출력 핀 매핑을 검증해 볼 수 있습니다. 다음 예제는 GPIO 0, 13, 23 번 핀을 제어하여 점등 시간을 다르게 하여 동작을 구분하는 코드입니다.


const int PIN_1 = 0;
const int PIN_2 = 13;
const int PIN_3 = 23;

void setup() {
  pinMode(PIN_1, OUTPUT);
  pinMode(PIN_2, OUTPUT);
  pinMode(PIN_3, OUTPUT);
}

void loop() {
  // 모든 LED ON - 2 초 대기
  digitalWrite(PIN_1, HIGH);
  digitalWrite(PIN_2, HIGH);
  digitalWrite(PIN_3, HIGH);
  delay(2000);

  // PIN_1 ON, 나머지 OFF - 2 초
  digitalWrite(PIN_1, HIGH);
  digitalWrite(PIN_2, LOW);
  digitalWrite(PIN_3, LOW);
  delay(2000);

  // PIN_2 ON, 나머지 OFF - 1 초
  digitalWrite(PIN_1, LOW);
  digitalWrite(PIN_2, HIGH);
  digitalWrite(PIN_3, LOW);
  delay(1000);

  // PIN_3 ON, 나머지 OFF - 0.5 초
  digitalWrite(PIN_1, LOW);
  digitalWrite(PIN_2, LOW);
  digitalWrite(PIN_3, HIGH);
  delay(500);
}

어떤 보드의 물리적 핀 배치를 참고하여 연결한 후 위 코드를 적용하면预期대로 동작함을 확인할 수 있습니다. 이는 AVR 기반 언도와 달리 ESP32 의 모든 GPIO 핀이 범용 출력을 지원하지 않으며, 특정 핀 번호만 지정 가능하다는 점을 시사합니다.

디지털 입력 모드 및 터치 인터페이스

범용 출력 핀보다 입력 전용으로 더 유연하게 활용 가능한 핀들로는 G34, G35, G36, G39 등이 있습니다. 이러한 핀들은 내부 저항 구조가 다르므로 입력 모드 설정에 주의가 필요합니다.

플로팅 입력 불안정성

먼저 일반적인 INPUT 모드를 사용합니다. 입력 핀을 3.3V(GND 포함) 로 확정하거나 공중에 띄우는 (float) 상태를 만들었을 때, 확정이 되지 않은 상태 (float) 에서는 신호가 잡혀 들리는 현상이 발생합니다. 아래 코드는 8 개의 핀을 출력 및 입력 쌍으로 구성한 예제입니다.


// 출력용 핀 배열
const int OUT_PINS[] = {23, 22, 1, 3, 21, 19, 18, 5}; 
// 입력용 핀 배열
const int IN_PINS[] = {36, 39, 34, 35, 32, 33, 25, 26}; 

void setup() {
  for(int i = 0; i < 8; i++) {
    pinMode(IN_PINS[i], INPUT);       // 기본 모드 선언
    pinMode(OUT_PINS[i], OUTPUT);
    digitalWrite(OUT_PINS[i], LOW);   // 초기화
  }
  delay(3000); 
  for(int i = 0; i < 8; i++) digitalWrite(OUT_PINS[i], HIGH);
}

void loop() {
  for(int i = 0; i < 8; i++) {
    // 입력값 그대로 출력
    digitalWrite(OUT_PINS[i], digitalRead(IN_PINS[i]));
  }
}

결과적으로 명확한 High/Low 전압이 입력되지 않으면 LED 가 불안정하게 점멸합니다. 따라서 외부 노이즈에 의한 false trigger 를 막기 위해서는 내부 저항 기능을 켜야 합니다.

내부 저항 기능의 한계

INPUT_PULLUP 는 입력이 접지되지 않았을 때 자동으로 High 를 유지하도록 설정하지만, 앞서 언급한 G34, G35, G36, G39 핀은 하드웨어적으로 내부 상/하단 저항을 지원하지 않습니다. 따라서 해당 핀들에 PULLUP/PULLDOWN 을 지정해도 실제 하드웨어 효과는 발생하지 않아 신호 불안정은 해소되지 않습니다. 반면 그 외의 핀들은 정상적으로 내부 저항 동작을 수행하여 안정적인 신호를 제공합니다. PULLDOWN 을 사용한 경우, 연결선이 개방되면 Low 가 유지되도록 기본 상태가 역전됩니다.

커패시터 터치 감지 구현

ESP32 만의 고유 기능으로, 정전기나 손가락 접촉에 의한 용량 변화를 포착하여 디지털 신호로 변환하는 터치 입력 기능이 내장되어 있습니다. 지원 핀은 약 10 개 정도이며, 인터럽트를 기반으로 동작합니다.


#define T_SENSOR 4  
#define ACT_LED 23
volatile bool ledState = false;

void handleTouch() {
  ledState = !ledState;
  digitalWrite(ACT_LED, ledState);
  Serial.println("Touch detected");
}

void setup() {
  pinMode(ACT_LED, OUTPUT);
  Serial.begin(115200);
  // 임계값 40 은 하드웨어에 따라 조정 필요
  touchAttachInterrupt(T_SENSOR, handleTouch, 40); 
}

void loop() {
  // 터치는 백그라운드 처리되므로 루프는 비워둠
}

이러한 인터럽트 핸들러 내에서 임계값 (threshold) 을 조절하여 민감도를 조정할 수 있습니다. 값이 작을수록 미세한 접촉에도 반응하므로 오작동 가능성이 커지지만 응답 속도는 빨라집니다. 반대로 값이 크면 확실한 접촉이 있어야 트리거됩니다. 또한 소프트웨어적으로 지연 시간을 추가하거나 필터링 로직을 넣어 단일 접촉 시 여러 번 동작하는 것을 방지하는 것이 좋은 관례입니다.

태그: ESP32 Microcontroller GPIO EmbeddedDevelopment cpp

9월 20일 12:19에 게시됨