07–08. GPIO 출력 — LED 점멸 · GPIO 입력 — 버튼/스위치 읽기
임베디드의 "Hello, World"는 LED 깜빡이기입니다. 포트에 어떤 값을 써야 LED가 켜지는지(액티브 로우/하이 배선), 얼마나 기다려야 보이는지(지연), 여러 LED로 패턴을 만드는 법(비트 마스크)까지 GPIO 출력의 핵심이 다 들어 있습니다. P1에 연결된 LED 8개로 흐르는 불빛(running light)을 만들고 Logic Analyzer로 핀 파형을 관찰합니다. 7편이 핀으로 신호를 내보냈다면 이번엔 핀으로 신호를 읽어들입니다. 8051 특유의 함정은 포트가 준쌍방향(quasi-bidirectional)이라, 입력으로 읽기 전에 그 핀에 먼저 1을 써 두어야 외부 신호를 제대로 읽는다는 점입니다. P3.2 버튼을 읽어 P1.0 LED를 제어하고, "누르는 순간마다 토글"하는 에지 검출 로직을 익힙니다. 채터링은 21편에서 다룹니다.
이 강의에서 배우는 것
- 1GPIO 출력으로 LED를 제어하고 액티브 로우/하이 차이를 설명한다
- 2while(1) 안에서 포트 값을 바꿔 LED를 점멸시킨다
- 3소프트웨어 지연 루프의 동작과 한계(부정확)를 이해한다
- 4마스크 ~(1u<<pos) 로 흐르는 불빛 패턴을 만든다
- 5Logic Analyzer로 포트 핀 토글을 관찰한다
- 6준쌍방향 포트에서 입력 전 1을 써야 하는 이유를 설명한다
- 7sbit 으로 입력 핀을 읽어 조건 분기한다
- 8풀업/액티브 로우 버튼(평소 1, 누르면 0)을 이해한다
- 9버튼 상태를 LED로 미러링한다
- 10에지 검출(1→0)로 누르는 순간만 감지한다
07. GPIO 출력 — LED 점멸
임베디드의 "Hello, World"는 LED 깜빡이기입니다. 포트에 어떤 값을 써야 LED가 켜지는지(액티브 로우/하이 배선), 얼마나 기다려야 보이는지(지연), 여러 LED로 패턴을 만드는 법(비트 마스크)까지 GPIO 출력의 핵심이 다 들어 있습니다. P1에 연결된 LED 8개로 흐르는 불빛(running light)을 만들고 Logic Analyzer로 핀 파형을 관찰합니다.
소개
6편의 포트 SFR 쓰기를 무한 루프 안에서 반복해 패턴을 만듭니다. 많은 8051 보드가 LED를 액티브 로우(핀이 0일 때 ON)로 달기 때문에, "켜고 싶은 비트만 0"으로 만드는 감각이 중요합니다.
핵심 개념
1) LED 배선 — 액티브 로우 vs 하이
| 방식 | LED ON 조건 |
|---|---|
| 액티브 하이(핀→LED→GND) | 핀 = 1 |
| 액티브 로우(VCC→LED→핀) | 핀 = 0 |
8051은 0을 출력할 때(싱크) 전류를 더 흘릴 수 있어 보드들이 흔히 액티브 로우로 답니다. 이 편은 액티브 로우 가정.
2) 한 LED만 켜기 — ~(1u<<pos)
/* 액티브 로우: pos 번 비트만 0, 나머지 1 */
pos=0 -> ~(1<<0) = 0xFE = 11111110 (LED0 ON)
pos=3 -> ~(1<<3) = 0xF7 = 11110111 (LED3 ON)
/* pos 를 0->7 로 옮기며 반복하면 불빛이 한 칸씩 흐른다 */3) 소프트웨어 지연
static void delay(unsigned int n) {
unsigned int i;
for (i = 0; i < n; i++) { } /* 부정확! 정확한 시간은 9편 타이머 */
}컴파일러가 빈 루프를 최적화로 제거할 수 있습니다. 유지하려면 루프 변수를 volatile 로, 정밀 지연이 필요하면 타이머(9편)를 쓰세요.
핵심 예제
#include <reg52.h>
#define LED_PORT P1
static void delay(unsigned int n){ unsigned int i; for(i=0;i<n;i++){} }
void main(void) {
unsigned char pos = 0;
while (1) {
LED_PORT = (unsigned char)~(1u << pos); /* 액티브 로우 1개 ON */
delay(20000);
if (++pos >= 8) pos = 0;
}
}흐르는 불빛이 만드는 포트 값: 0xFE → 0xFD → 0xFB → 0xF7 → 0xEF → 0xDF → 0xBF → 0x7F. Logic Analyzer에 P1.0~P1.7을 추가하면 각 핀이 차례로 Low로 떨어지는 계단형 파형이 보입니다.
자주 하는 실수
Q. 포트에 1을 썼는데 LED가 안 켜져요.
A. 보드가 액티브 로우면 1은 OFF입니다. 0을 써야 켜집니다. 어느 쪽인지 모르면 회로도를 확인하세요(이 예제는 액티브 로우).
Q. LED가 깜빡이지 않고 그냥 켜져 있어요.
A. 지연이 없거나 너무 짧아 눈이 못 따라갑니다. delay 값을 키우거나 Logic Analyzer의 시간축으로 토글 자체를 확인하세요.
Q. 빈 지연 루프가 최적화로 사라져요.
A. 루프 변수를 volatile 로 선언하거나, 정확한 지연은 타이머(9편)를 쓰세요.
정리
- 배선에 따라 켜는 값이 다르다 — 액티브 로우는 0이 ON
- 한 LED만 켜기: ~(1u << pos)
- while(1)+지연으로 점멸/패턴을 만들되 소프트웨어 지연은 부정확하다
- 여러 LED는 마스크를 OR로 묶어(필요시 반전) 제어한다
- Logic Analyzer로 파형을, Port 창으로 비트 값을 본다
과제
- 흐르는 불빛을 7→0 역방향으로도 도는 왕복(knight rider) 패턴으로 확장
- 인접한 LED 2개를 동시에 켜며 흐르게 하는 마스크 작성
- 액티브 하이 보드라면 코드를 어떻게 바꿔야 하는지 설명하고 적용
08. GPIO 입력 — 버튼/스위치 읽기
7편이 핀으로 신호를 내보냈다면 이번엔 핀으로 신호를 읽어들입니다. 8051 특유의 함정은 포트가 준쌍방향(quasi-bidirectional)이라, 입력으로 읽기 전에 그 핀에 먼저 1을 써 두어야 외부 신호를 제대로 읽는다는 점입니다. P3.2 버튼을 읽어 P1.0 LED를 제어하고, "누르는 순간마다 토글"하는 에지 검출 로직을 익힙니다. 채터링은 21편에서 다룹니다.
소개
버튼·스위치·센서의 디지털 신호를 받아 프로그램이 반응하게 만드는 일입니다. 8051 준쌍방향 포트의 함정을 이해하는 것이 이번 편의 핵심입니다.
핵심 개념
1) 준쌍방향 포트 — 읽기 전에 1을 써라
8051 포트 핀은 출력 래치와 입력 버퍼를 공유합니다. 래치에 0을 써 두면 핀이 강하게 Low로 고정되어 외부 High가 읽히지 않습니다. 입력으로 쓸 핀에는 먼저 1을 써 핀을 "풀어 둬야" 합니다.
sbit BTN = P3 ^ 2;
BTN = 1; /* 입력 준비: 핀을 1(약한 풀업)로 */
if (BTN == 0) { } /* 이제 외부에서 0 을 주면 읽힌다 */2) 풀업+액티브 로우 버튼
| 상태 | 핀 값 |
|---|---|
| 안 누름 | 1 (풀업) |
| 누름 | 0 (GND) |
그래서 "눌림"의 판단은 `BTN == 0` 입니다.
3) 미러링 vs 에지 검출
if (prev_btn == 1 && btn == 0) { /* 하강 에지 = 막 눌린 순간 */
led = !led; /* 토글 (한 번만) */
}
prev_btn = btn;미러링은 눌린 동안 계속 반응(레벨), 에지 검출은 누르는 순간만 한 번 반응. "한 번 누를 때 한 번만"이 필요하면 에지 검출이 필수입니다. 접점 떨림(채터링)은 21편 디바운싱에서.
핵심 예제
#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편)
과제
- 버튼을 누를 때마다 LED 밝기 단계(흐르는 위치)를 1칸씩 옮기는 에지 검출 코드 작성
- 버튼 상태 시퀀스 {1,1,0,0,1,0}에 대해 토글 결과를 손으로 예측한 뒤 pc_test 로 검산
- 두 버튼(P3.2/P3.3)을 읽어 각각 다른 LED를 제어
댓글 0
아직 댓글이 없습니다. 첫 댓글을 남겨 주세요.
댓글은 회원만 쓸 수 있습니다.
광고·욕설·비방·개인정보·불법 내용이 담긴 댓글은 숨기거나 지웁니다. 댓글은 닉네임과 함께 공개됩니다. 개인정보처리방침