I2C: 선 두 가닥에 여러 칩 달기
SCL과 SDA 두 선, 7비트 주소, ACK, 풀업 저항. 센서 통신의 표준인 I2C의 동작과 막혔을 때 푸는 법.
구조
모든 칩이 SCL(클럭), SDA(데이터) 두 선을 공유하고, 선은 오픈드레인 + 풀업 저항입니다. 누구든 선을 LOW로 당길 수 있고, 아무도 당기지 않으면 풀업이 HIGH로 만듭니다.
한 번의 읽기
START → 주소(7비트)+W → ACK → 레지스터 번호 → ACK
→ 재START → 주소+R → ACK → 데이터 → ACK … → 마지막 데이터 → NACK → STOP
- ACK: 받은 쪽이 9번째 클럭에 SDA를 LOW로 당겨 "받았다"고 알림
- 주소에 해당하는 칩이 없으면 NACK가 오고, 이것으로 연결 확인(I2C 스캔)을 할 수 있음
풀업 저항 고르기
| 너무 크면 | 너무 작으면 |
|---|---|
| 상승 에지가 느려 고속에서 깨짐 | 칩이 LOW로 당기는 전류 한계 초과 |
100kHz는 4.7~10kΩ, 400kHz는 2.2~4.7kΩ가 보통입니다. 버스 커패시턴스(선 길이, 칩 수)가 크면 더 작게 합니다.
클럭 스트레칭
슬레이브가 준비가 덜 되면 SCL을 LOW로 붙잡아 마스터를 기다리게 할 수 있습니다.
버스가 멈췄을 때
통신 도중 MCU가 리셋되면 슬레이브가 SDA를 LOW로 붙잡은 채 멈출 수 있습니다. 시작할 때 SCL을 GPIO로 9번 토글해 슬레이브를 풀어 주는 버스 복구 코드를 넣어 둡니다.
그림으로 보기: 시작, 주소, ACK
데이터는 SCL이 LOW일 때만 바뀝니다. SCL이 HIGH인 동안 SDA가 바뀌는 경우는 시작(내려감)과 정지(올라감) 둘뿐이라, 이 두 조건을 데이터와 구분할 수 있습니다.
오픈 드레인과 풀업
I2C의 두 선은 아무도 당기지 않으면 풀업 저항 때문에 HIGH입니다. 장치는 LOW로 당기기만 할 수 있습니다. 그래서 두 장치가 동시에 구동해도 단락이 나지 않고, 슬레이브가 SCL을 붙잡아 마스터를 기다리게 할 수도 있습니다(클럭 스트레칭).
풀업 저항값은 속도와 버스 정전용량으로 정합니다.
| 속도 | 흔히 쓰는 값 |
|---|---|
| 100 kHz | 4.7 kΩ ~ 10 kΩ |
| 400 kHz | 2.2 kΩ ~ 4.7 kΩ |
저항이 크면 HIGH로 올라가는 시간이 길어져 파형 모서리가 둥글어집니다. 오실로스코프에서 상승 구간이 완만한 곡선이면 저항을 줄입니다. 모듈마다 풀업이 달려 있는 경우 여러 개를 연결하면 병렬이 되어 값이 너무 작아질 수 있습니다.
3D 실험실여기까지 읽은 내용을 직접 돌려 볼 수 있습니다→레지스터 읽기는 두 단계
// 1) 쓰기로 "몇 번 레지스터를 읽을지" 알려 주고
// 2) 반복 시작(정지 없이 다시 시작) 뒤 읽기
i2c_start();
i2c_write((0x68 << 1) | 0); // 주소 + 쓰기
i2c_write(0x3B); // 레지스터 번호
i2c_start(); // 반복 시작
i2c_write((0x68 << 1) | 1); // 주소 + 읽기
hi = i2c_read(ACK);
lo = i2c_read(NACK); // 마지막 바이트는 NACK
i2c_stop();
7비트 주소와 8비트 주소
데이터시트에 0x68이라고 적혀 있으면 7비트 주소이고, 실제 선에는 한 칸 밀려 0xD0(쓰기), 0xD1(읽기)로 나갑니다. 문서에 0xD0이라고 적는 회사도 있어서, 응답이 없으면 먼저 한 칸 밀거나 당겨 봅니다. 라이브러리가 어느 쪽을 받는지도 확인합니다.
멈춘 버스를 살리는 코드
슬레이브가 데이터를 보내던 중에 마스터가 리셋되면, 슬레이브는 SDA를 LOW로 잡은 채 다음 클럭을 기다립니다. 마스터는 버스가 사용 중이라고 보고 아무것도 못 합니다.
// SCL을 GPIO로 바꿔 9번 흔들어 슬레이브가 SDA를 놓게 한 뒤 정지 조건을 낸다
for (int i = 0; i < 9 && !sda_read(); i++) { scl_low(); delay_us(5); scl_high(); delay_us(5); }
제품 펌웨어에는 이 복구 코드와 모든 I2C 동작의 타임아웃을 반드시 넣습니다.
현업에서 자주 터지는 문제
- 주소 스캔에서 아무것도 안 잡힘: 풀업 누락, SDA와 SCL 뒤바뀜, 전원 미공급 순으로 확인
- 같은 주소의 센서 두 개: 주소 선택 핀이 없으면 I2C 멀티플렉서가 필요
- 긴 케이블: 정전용량이 커져 400 kHz가 불안정해짐. 속도를 낮추거나 버퍼 사용
영상으로 이어 보기통신 시리즈 13편UART 통신 완벽정리 | 전기전자, 전자과, 임베디드 개발자 필수 시청PROJECT COURSEI2C로 MPU6050을, UART로 블루투스 모듈을 직접 붙여 보고 싶다면밸런싱 로봇 하나를 요구사항, 회로와 PCB, 펌웨어, 앱까지 실무 순서대로 만드는 강의입니다. 10파트 165강.강의 살펴보기 →FREE PDF무료 전자책 3권 받기이 주제를 한 권으로 이어서 읽고 싶다면. BLDC 모터 제어, 직렬통신, 센서를 책 분량으로 묶었습니다. 이메일만 남기면 바로 받습니다.무료로 받기 →