신호선을 전원(VCC)에 저항으로 연결해 기본 상태를 High로 유지하는 부품.
왜 필요한가 — 플로팅 방지
- 아무 데도 연결되지 않은 입력 핀 = 플로팅(floating)
- 주변 전자기 노이즈에 따라 0과 1이 무작위로 읽힌다
- 손을 가까이 대기만 해도 값이 바뀐다
"버튼을 안 눌렀는데 눌린 것으로 인식된다" 는 증상의 원인이다.
VCC
│
[R] 10kΩ
│
├──── MCU 입력 핀
│
[버튼]
│
GND
버튼 안 누름 → 저항을 통해 VCC → High 읽힘
버튼 누름 → GND 로 직결 → Low 읽힘
"눌렀을 때 Low" 가 되므로 논리가 반전된다(active low). 이것이 임베디드에서 버튼이 대부분 active low인 이유다.
저항값 선택
- 작을수록(1kΩ) — : 노이즈에 강하다. 상승이 빠르다. 전류 소모 큼 큰 값(100kΩ) : 전류 절약. 노이즈에 약하다. 상승이 느리다
일반 용도: 10kΩ 이 표준
버튼을 누르고 있을 때 흐르는 전류 I = 3.3V / 10kΩ = 0.33mA 배터리 기기에서 항상 눌려 있는 스위치가 있다면 이 전류가 문제가 된다. 그럴 때는 100kΩ이나 내부 풀업을 쓴다.
내부 풀업 — 별도 부품 없이
GPIO_InitStruct.Pull = GPIO_PULLUP; // 내부 풀업 활성화
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
대부분의 MCU가 30~50kΩ 정도의 내부 풀업을 제공한다. 버튼 입력에는 충분하고 부품이 줄어든다.
한계 값이 부정확하다 (30~50kΩ 범위로 명시) 저전력 모드에서 비활성화될 수 있다
- I2C처럼 정확한 값이 필요한 곳에는 부적합 — ★
I2C에서 특히 중요하다
I2C는 오픈드레인이라 풀업이 없으면 High가 만들어지지 않는다. 통신 자체가 불가능하다.
저항값 계산 최소값: 싱크 전류 제한 R_min = (VCC - V_OL) / I_OL = (3.3 - 0.4) / 3mA ≈ 1kΩ
최대값: 상승 시간 제한
- t_rise = 0.8473 × R × C — ≤ 300ns (Fast mode) C = 200pF 이면 → R ≤ 1.8kΩ
실무 기준 100kHz, 짧은 배선 → 4.7kΩ ~ 10kΩ
- 400kHz — → 2.2kΩ ~ 4.7kΩ 긴 배선·장치 많음 → 1kΩ ~ 2.2kΩ
여러 장치에 각각 풀업이 달려 있으면 병렬로 합쳐져 값이 작아진다. 모듈 3개를 연결했더니 각각 4.7kΩ이 병렬로 1.57kΩ이 되어 싱크 전류를 초과하는 일이 있다. 하나만 남기고 제거해야 한다.
파형으로 진단
정상 : ┌── 가파른 상승
느림 : ╱── RC 시정수가 커서 삼각형 → 저항을 낮춘다
못 올라감: ── 풀업 없음 또는 누군가 계속 당기고 있음
오실로스코프로 SDA/SCL을 보면 바로 판별된다. I2C 문제의 상당수가 풀업 문제다.
풀다운 저항
- 반대로 GND에 연결해 기본 상태를 Low로 만든다
- 버튼을 누르면 High (active high)
어느 쪽을 쓰나 풀업이 관례인 이유
- 오픈드레인/오픈컬렉터 출력이 Low만 구동하는 구조와 맞는다
- 옛 TTL 로직에서 High 구동 능력이 약했던 역사
- 대부분의 MCU가 내부 풀업을 기본 제공 (풀다운은 없는 경우도)
부팅 중 상태도 고려한다
- MCU가 리셋 중이면 GPIO는 하이임피던스(입력)
- 외부 회로가 예상치 못한 상태가 될 수 있다
예: MOSFET 게이트가 플로팅 → 반쯤 켜져 발열
- 릴레이가 의도치 않게 동작
전원 인가부터 펌웨어가 GPIO를 설정하기까지의 구간을 외부 풀업/풀다운으로 안전한 쪽으로 고정해 두는 것이 페일세이프 설계의 기본이다. 내부 풀업은 이 구간에 없다.