← Embedded C 강의 목록으로
🔌
8051
8051 · 선수: 07강

08. GPIO 입력 — 버튼/스위치 읽기

7편이 핀으로 신호를 내보냈다면 이번엔 핀으로 신호를 읽어들입니다. 8051 특유의 함정은 포트가 준쌍방향(quasi-bidirectional)이라, 입력으로 읽기 전에 그 핀에 먼저 1을 써 두어야 외부 신호를 제대로 읽는다는 점입니다. P3.2 버튼을 읽어 P1.0 LED를 제어하고, "누르는 순간마다 토글"하는 에지 검출 로직을 익힙니다. 채터링은 21편에서 다룹니다.

GPIO입력버튼준쌍방향풀업에지검출
소요 시간
약 1시간
난이도
📊 초급
선수 조건
🎯 07강
결과물
준쌍방향 포트에서 입력 전 1을 써 버튼을 읽고, 미러링과 에지 검출(1→0)을 구분해 "누르는 순간"만 반응하는 로직을 구현할 수 있습니다.

이 강의에서 배우는 것

  • 1준쌍방향 포트에서 입력 전 1을 써야 하는 이유를 설명한다
  • 2sbit 으로 입력 핀을 읽어 조건 분기한다
  • 3풀업/액티브 로우 버튼(평소 1, 누르면 0)을 이해한다
  • 4버튼 상태를 LED로 미러링한다
  • 5에지 검출(1→0)로 누르는 순간만 감지한다

소개

버튼·스위치·센서의 디지털 신호를 받아 프로그램이 반응하게 만드는 일입니다. 8051 준쌍방향 포트의 함정을 이해하는 것이 이번 편의 핵심입니다.

핵심 개념

1) 준쌍방향 포트 — 읽기 전에 1을 써라

8051 포트 핀은 출력 래치와 입력 버퍼를 공유합니다. 래치에 0을 써 두면 핀이 강하게 Low로 고정되어 외부 High가 읽히지 않습니다. 입력으로 쓸 핀에는 먼저 1을 써 핀을 "풀어 둬야" 합니다.

c
sbit BTN = P3 ^ 2;
BTN = 1;            /* 입력 준비: 핀을 1(약한 풀업)로 */
if (BTN == 0) { }   /* 이제 외부에서 0 을 주면 읽힌다 */

2) 풀업+액티브 로우 버튼

상태핀 값
안 누름1 (풀업)
누름0 (GND)

그래서 "눌림"의 판단은 `BTN == 0` 입니다.

3) 미러링 vs 에지 검출

c
if (prev_btn == 1 && btn == 0) {   /* 하강 에지 = 막 눌린 순간 */
    led = !led;                    /* 토글 (한 번만) */
}
prev_btn = btn;
ℹ️

미러링은 눌린 동안 계속 반응(레벨), 에지 검출은 누르는 순간만 한 번 반응. "한 번 누를 때 한 번만"이 필요하면 에지 검출이 필수입니다. 접점 떨림(채터링)은 21편 디바운싱에서.

핵심 예제

c
#include <reg52.h>
sbit BTN = P3 ^ 2;   /* 입력 */
sbit LED = P1 ^ 0;   /* 출력(액티브 로우) */
void main(void) {
    BTN = 1;                 /* 입력 준비 */
    while (1) {
        if (BTN == 0) LED = 0;   /* 눌림 → LED ON */
        else          LED = 1;   /* 뗌  → LED OFF */
    }
}

시뮬레이터: Port 3 창에서 P3.2 비트를 클릭해 0/1을 바꿔 "버튼"을 누르면 Port 1의 P1.0이 따라 바뀝니다.

자주 하는 실수

Q. 버튼을 눌러도 입력이 항상 같은 값으로 읽혀요.

A. 준쌍방향 포트 함정입니다. 그 핀에 출력 0을 써 둔 적이 있으면 입력이 막힙니다. 읽기 전에 BTN = 1; 로 핀을 풀어 두세요.

Q. 한 번 눌렀는데 LED가 여러 번 토글돼요.

A. 루프가 너무 빨라 "누르고 있는 동안" 여러 번 도는 것을 토글로 착각한 경우 → 에지 검출로 바꾸세요. 채터링이면 디바운싱(21편).

Q. if (P3 & 0x04 == 0) 이 이상해요.

A. 우선순위 함정. ==가 &보다 먼저라 0x04==0 이 먼저 계산됩니다. 괄호로 if ((P3 & 0x04) == 0), 또는 sbit 으로 if (BTN == 0) 이 명확합니다.

정리

  • 준쌍방향 포트는 입력으로 읽기 전 핀에 1을 써 둔다
  • 풀업+액티브 로우 버튼은 평소 1, 누르면 0 — 판단은 BTN == 0
  • 미러링은 현재 상태를 따르고, 에지 검출은 누르는 순간만 잡는다
  • 에지 검출은 직전 상태와 현재 상태를 비교한다(prev==1 && cur==0)
  • 채터링은 디바운싱으로 해결한다(21편)

과제

  1. 버튼을 누를 때마다 LED 밝기 단계(흐르는 위치)를 1칸씩 옮기는 에지 검출 코드 작성
  2. 버튼 상태 시퀀스 {1,1,0,0,1,0}에 대해 토글 결과를 손으로 예측한 뒤 pc_test 로 검산
  3. 두 버튼(P3.2/P3.3)을 읽어 각각 다른 LED를 제어
예제 코드 / 강의 자료

전체 강의 자료와 예제 코드(과제·정답 포함)는 GitHub에서 자유롭게 받아볼 수 있습니다.

GitHub에서 보기 ↗