AT89C51 마이크로컨트롤러에서 I2C 프로토콜을 비트뱅 방식으로 구현하는 C 코드를 작성해드리겠습니다. 비트뱅 I2C는 소프트웨어로 SCL(클럭)과 SDA(데이터) 라인을 제어하여 I2C 통신을 구현하는 방식입니다. 아래는 기본적인 I2C 마스터 구현 코드입니다.
Hardware 설정
- 마이크로컨트롤러: AT89C51 (8051 기반)
- I2C 핀:
- SCL: P2.0
- SDA: P2.1
- 컴파일러: Keil uVision 또는 SDCC와 같은 8051용 C 컴파일러
- 외부 풀업 저항: I2C 라인(SCL, SDA)에 4.7kΩ 풀업 저항이 연결되어 있다고 가정
- 속도: 약 100kHz I2C 클럭 속도 (비트뱅이므로 대략적인 타이밍)
#include <reg51.h> // AT89C51 헤더 파일
#include <intrins.h> // _nop_() 함수를 위한 헤더
// I2C 핀 정의
sbit SDA = P2^1; // SDA: P2.1
sbit SCL = P2^0; // SCL: P2.0
// 지연 함수 (타이밍 조정을 위해)
void I2C_Delay(void) {
_nop_(); _nop_(); _nop_(); _nop_(); // 약 5us 지연 (12MHz 클록 기준)
}
// I2C 초기화
void I2C_Init(void) {
SDA = 1; // SDA를 HIGH로 설정 (오픈 드레인)
SCL = 1; // SCL을 HIGH로 설정 (오픈 드레인)
}
// I2C 시작 조건
void I2C_Start(void) {
SDA = 1; // SDA HIGH
SCL = 1; // SCL HIGH
I2C_Delay();
SDA = 0; // SDA를 LOW로 (시작 조건)
I2C_Delay();
SCL = 0; // SCL을 LOW로
}
// I2C 정지 조건
void I2C_Stop(void) {
SDA = 0; // SDA LOW
SCL = 1; // SCL HIGH
I2C_Delay();
SDA = 1; // SDA를 HIGH로 (정지 조건)
I2C_Delay();
}
// I2C 1바이트 쓰기
bit I2C_WriteByte(unsigned char dat) {
unsigned char i;
bit ack;
// 8비트 데이터 전송
for (i = 0; i < 8; i++) {
SCL = 0; // SCL LOW
SDA = (dat & 0x80) ? 1 : 0; // MSB부터 전송
I2C_Delay();
SCL = 1; // SCL HIGH (데이터 읽기 타이밍)
I2C_Delay();
dat <<= 1; // 다음 비트로 이동
}
// ACK 확인
SCL = 0; // SCL LOW
SDA = 1; // SDA를 입력 모드로 (HIGH, 풀업 저항)
I2C_Delay();
SCL = 1; // SCL HIGH
I2C_Delay();
ack = SDA; // ACK 비트 읽기 (0: ACK, 1: NACK)
SCL = 0; // SCL LOW
return ack;
}
// I2C 1바이트 읽기
unsigned char I2C_ReadByte(bit send_ack) {
unsigned char i, dat = 0;
// 8비트 데이터 수신
SDA = 1; // SDA를 입력 모드로
for (i = 0; i < 8; i++) {
dat <<= 1; // 데이터 비트 이동
SCL = 0; // SCL LOW
I2C_Delay();
SCL = 1; // SCL HIGH (데이터 읽기 타이밍)
I2C_Delay();
dat |= SDA; // SDA에서 비트 읽기
}
// ACK 또는 NACK 전송
SCL = 0; // SCL LOW
SDA = send_ack ? 0 : 1; // ACK(0) 또는 NACK(1) 설정
I2C_Delay();
SCL = 1; // SCL HIGH
I2C_Delay();
SCL = 0; // SCL LOW
SDA = 1; // SDA를 다시 입력 모드로
return dat;
}
// 예제: I2C 장치에 데이터 쓰기
void I2C_WriteData(unsigned char device_addr, unsigned char reg_addr, unsigned char data) {
I2C_Start(); // 시작 조건
I2C_WriteByte(device_addr << 1); // 슬레이브 주소 (쓰기: LSB = 0)
I2C_WriteByte(reg_addr); // 레지스터 주소
I2C_WriteByte(data); // 데이터 쓰기
I2C_Stop(); // 정지 조건
}
// 예제: I2C 장치에서 데이터 읽기
unsigned char I2C_ReadData(unsigned char device_addr, unsigned char reg_addr) {
unsigned char dat;
I2C_Start(); // 시작 조건
I2C_WriteByte(device_addr << 1); // 슬레이브 주소 (쓰기: LSB = 0)
I2C_WriteByte(reg_addr); // 레지스터 주소
I2C_Start(); // 반복 시작 조건
I2C_WriteByte((device_addr << 1) | 1); // 슬레이브 주소 (읽기: LSB = 1)
dat = I2C_ReadByte(0); // 데이터 읽기 (NACK)
I2C_Stop(); // 정지 조건
return dat;
}
// 메인 함수
void main(void) {
I2C_Init(); // I2C 초기화
// 예제: EEPROM (24C02) 쓰기 및 읽기
I2C_WriteData(0x50, 0x10, 0xAA); // 주소 0x10에 0xAA 쓰기 (0x50: EEPROM 주소)
unsigned char data = I2C_ReadData(0x50, 0x10); // 주소 0x10에서 데이터 읽기
while (1); // 무한 루프
}
코드 설명
- 핀 정의:
- SDA와 SCL은 P2.0과 P2.1에 연결되어 있습니다. 필요에 따라 다른 포트로 변경 가능합니다.
- AT89C51은 오픈 드레인 출력이 없으므로, 외부 풀업 저항이 필수입니다.
- 지연 함수 (I2C_Delay):
- _nop_()을 사용하여 약 5us 지연을 구현 (12MHz 클록 기준).
- 클록 속도에 따라 타이밍을 조정해야 할 수 있습니다.
- I2C 기본 함수:
- I2C_Start(): I2C 시작 조건 (SDA HIGH → LOW while SCL HIGH).
- I2C_Stop(): I2C 정지 조건 (SDA LOW → HIGH while SCL HIGH).
- I2C_WriteByte(): 1바이트 데이터를 전송하고 ACK를 확인.
- I2C_ReadByte(): 1바이트 데이터를 읽고 ACK/NACK을 전송.
- 응용 함수:
- I2C_WriteData(): 특정 슬레이브 장치의 레지스터에 데이터를 쓰는 함수.
- I2C_ReadData(): 특정 슬레이브 장치의 레지스터에서 데이터를 읽는 함수.
- 메인 함수:
- 예제로 24C02 EEPROM(주소 0x50)에 데이터를 쓰고 읽는 동작을 포함.
- 실제 사용 시 슬레이브 주소와 레지스터 주소를 장치 데이터시트에 맞게 수정해야 합니다.
주의사항
- 타이밍 조정: I2C_Delay()는 시스템 클록(예: 12MHz)에 따라 조정 필요. 다른 클록 속도에서는 _nop_() 호출 횟수를 변경하거나 타이머를 사용할 수 있습니다.
- 슬레이브 주소: I2C 장치의 주소는 데이터시트를 확인하여 설정. 위 코드에서는 7비트 주소(예: 0x50)를 사용하며, LSB는 읽기(1)/쓰기(0)를 나타냅니다.
- 풀업 저항: SCL과 SDA 라인에 4.7kΩ 또는 10kΩ 풀업 저항이 필요합니다.
- 인터럽트: 이 코드는 폴링 기반이며, 인터럽트를 사용하려면 추가 수정이 필요합니다.
디버깅 팁
- 오실로스코프 또는 로직 애널라이저로 SCL/SDA 신호를 확인하여 타이밍과 신호 무결성을 점검.
- ACK 비트가 제대로 수신되지 않으면 슬레이브 주소나 연결을 확인.
- 실제 하드웨어 테스트 전 시뮬레이터(Keil uVision의 디버거 등)로 동작 확인.
'MCU > 8051' 카테고리의 다른 글
8051 SPI 비트뱅 코드 구현 : 모드 선택 가능 예제 (3) | 2025.08.22 |
---|---|
8051 SPI 비트뱅(bit-bang)을 STM32 HAL API 스타일로 코드 구현 (0) | 2025.08.02 |
8051 I2C 비트뱅(bit-bang)를 STM32 HAL API 스타일로 코드 구현 (0) | 2025.08.02 |