STM32의 HAL API 스타일로 AT89C51용 I2C 비트뱅 코드를 재작성하겠습니다. STM32 HAL API는 HAL_I2C_ 접두사를 사용하며, 상태 반환값(HAL_OK, HAL_ERROR 등)과 구조체 기반 설정을 활용합니다. AT89C51에는 하드웨어 I2C 모듈이 없으므로, 비트뱅 방식으로 HAL 스타일의 인터페이스를 모방하여 구현합니다. 아래 코드는 STM32 HAL API의 구조와 네이밍 컨벤션을 따라 설계되었습니다.
가정 및 설정
- 마이크로컨트롤러: AT89C51 (8051 기반)
- I2C 핀:
- SCL: P2.0
- SDA: P2.1
- 컴파일러: Keil uVision 또는 SDCC
- 외부 풀업 저항: SCL과 SDA에 4.7kΩ 풀업 저항
- 클럭 속도: 약 100kHz (비트뱅, 12MHz 시스템 클록 기준)
- HAL 스타일: HAL_I2C_ 함수, HAL_StatusTypeDef 반환값, I2C_HandleTypeDef 구조체 사용
코드
#include <reg51.h>
#include <intrins.h>
// HAL 상태 정의
typedef enum {
HAL_OK = 0x00,
HAL_ERROR = 0x01,
HAL_BUSY = 0x02,
HAL_TIMEOUT = 0x03
} HAL_StatusTypeDef;
// I2C 핀 정의
sbit SDA = P2^1; // SDA: P2.1
sbit SCL = P2^0; // SCL: P2.0
// I2C 핸들 구조체
typedef struct {
unsigned char scl_pin; // SCL 핀 (미사용, STM32 스타일 모방)
unsigned char sda_pin; // SDA 핀 (미사용, STM32 스타일 모방)
unsigned int timeout; // 타임아웃 (미사용, 예제 단순화)
} I2C_HandleTypeDef;
// 지연 함수
void I2C_Delay(void) {
_nop_(); _nop_(); _nop_(); _nop_(); // 약 5us 지연 (12MHz 클록)
}
// I2C 초기화
HAL_StatusTypeDef HAL_I2C_Init(I2C_HandleTypeDef *hi2c) {
// 핀 초기화 (오픈 드레인 모방)
SDA = 1; // SDA HIGH
SCL = 1; // SCL HIGH
hi2c->timeout = 1000; // 타임아웃 설정 (미사용)
return HAL_OK;
}
// I2C 시작 조건
HAL_StatusTypeDef HAL_I2C_Start(I2C_HandleTypeDef *hi2c) {
SDA = 1; // SDA HIGH
SCL = 1; // SCL HIGH
I2C_Delay();
SDA = 0; // SDA LOW (시작 조건)
I2C_Delay();
SCL = 0; // SCL LOW
return HAL_OK;
}
// I2C 정지 조건
HAL_StatusTypeDef HAL_I2C_Stop(I2C_HandleTypeDef *hi2c) {
SDA = 0; // SDA LOW
SCL = 1; // SCL HIGH
I2C_Delay();
SDA = 1; // SDA HIGH (정지 조건)
I2C_Delay();
return HAL_OK;
}
// I2C 바이트 쓰기
HAL_StatusTypeDef HAL_I2C_Master_TransmitByte(I2C_HandleTypeDef *hi2c, unsigned char data) {
unsigned char i;
bit ack;
// 8비트 데이터 전송
for (i = 0; i < 8; i++) {
SCL = 0; // SCL LOW
SDA = (data & 0x80) ? 1 : 0; // MSB부터 전송
I2C_Delay();
SCL = 1; // SCL HIGH
I2C_Delay();
data <<= 1;
}
// ACK 확인
SCL = 0; // SCL LOW
SDA = 1; // SDA 입력 모드
I2C_Delay();
SCL = 1; // SCL HIGH
I2C_Delay();
ack = SDA; // ACK 비트 읽기
SCL = 0; // SCL LOW
return ack ? HAL_ERROR : HAL_OK;
}
// I2C 바이트 읽기
HAL_StatusTypeDef HAL_I2C_Master_ReceiveByte(I2C_HandleTypeDef *hi2c, unsigned char *data, bit send_ack) {
unsigned char i;
*data = 0;
// 8비트 데이터 수신
SDA = 1; // SDA 입력 모드
for (i = 0; i < 8; i++) {
*data <<= 1;
SCL = 0; // SCL LOW
I2C_Delay();
SCL = 1; // SCL HIGH
I2C_Delay();
*data |= 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 HAL_OK;
}
// I2C 메모리 쓰기 (STM32 HAL 스타일)
HAL_StatusTypeDef HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, unsigned char dev_addr, unsigned char mem_addr, unsigned char *pData, unsigned char size) {
HAL_StatusTypeDef status;
// 시작 조건
status = HAL_I2C_Start(hi2c);
if (status != HAL_OK) return status;
// 슬레이브 주소 전송 (쓰기)
status = HAL_I2C_Master_TransmitByte(hi2c, dev_addr << 1);
if (status != HAL_OK) {
HAL_I2C_Stop(hi2c);
return status;
}
// 메모리 주소 전송
status = HAL_I2C_Master_TransmitByte(hi2c, mem_addr);
if (status != HAL_OK) {
HAL_I2C_Stop(hi2c);
return status;
}
// 데이터 전송
while (size--) {
status = HAL_I2C_Master_TransmitByte(hi2c, *pData++);
if (status != HAL_OK) {
HAL_I2C_Stop(hi2c);
return status;
}
}
// 정지 조건
return HAL_I2C_Stop(hi2c);
}
// I2C 메모리 읽기 (STM32 HAL 스타일)
HAL_StatusTypeDef HAL_I2C_Mem_Read(I2C_HandleTypeDef *hi2c, unsigned char dev_addr, unsigned char mem_addr, unsigned char *pData, unsigned char size) {
HAL_StatusTypeDef status;
// 시작 조건
status = HAL_I2C_Start(hi2c);
if (status != HAL_OK) return status;
// 슬레이브 주소 전송 (쓰기)
status = HAL_I2C_Master_TransmitByte(hi2c, dev_addr << 1);
if (status != HAL_OK) {
HAL_I2C_Stop(hi2c);
return status;
}
// 메모리 주소 전송
status = HAL_I2C_Master_TransmitByte(hi2c, mem_addr);
if (status != HAL_OK) {
HAL_I2C_Stop(hi2c);
return status;
}
// 반복 시작 조건
status = HAL_I2C_Start(hi2c);
if (status != HAL_OK) return status;
// 슬레이브 주소 전송 (읽기)
status = HAL_I2C_Master_TransmitByte(hi2c, (dev_addr << 1) | 1);
if (status != HAL_OK) {
HAL_I2C_Stop(hi2c);
return status;
}
// 데이터 수신
while (size--) {
status = HAL_I2C_Master_ReceiveByte(hi2c, pData++, (size > 0) ? 1 : 0);
if (status != HAL_OK) {
HAL_I2C_Stop(hi2c);
return status;
Facet
}
}
// 정지 조건
return HAL_I2C_Stop(hi2c);
}
// 메인 함수
void main(void) {
I2C_HandleTypeDef hi2c;
unsigned char data_write = 0xAA;
unsigned char data_read = 0;
// I2C 초기화
HAL_I2C_Init(&hi2c);
// 예제: EEPROM (24C02) 쓰기 및 읽기
HAL_I2C_Mem_Write(&hi2c, 0x50, 0x10, &data_write, 1); // 주소 0x10에 0xAA 쓰기
HAL_I2C_Mem_Read(&hi2c, 0x50, 0x10, &data_read, 1); // 주소 0x10에서 데이터 읽기
while (1); // 무한 루프
}
코드 설명
- HAL 스타일 구조:
- HAL_StatusTypeDef: STM32 HAL처럼 HAL_OK, HAL_ERROR 등을 반환값으로 사용.
- I2C_HandleTypeDef: I2C 설정을 위한 구조체. AT89C51에서는 핀 설정 등이 단순화됨.
- 함수 이름: HAL_I2C_Init, HAL_I2C_Mem_Write, HAL_I2C_Mem_Read 등 STM32 HAL 네이밍 컨벤션 준수.
- 핀 및 지연:
- SCL(P2.0), SDA(P2.1) 사용.
- I2C_Delay()는 12MHz 클록 기준 약 5us 지연으로 100kHz I2C 속도 구현.
- 주요 함수:
- HAL_I2C_Init(): I2C 핀 초기화.
- HAL_I2C_Start(), HAL_I2C_Stop(): 시작/정지 조건 생성.
- HAL_I2C_Master_TransmitByte(), HAL_I2C_Master_ReceiveByte(): 바이트 단위 데이터 송수신.
- HAL_I2C_Mem_Write(), HAL_I2C_Mem_Read(): STM32 HAL 스타일의 메모리 쓰기/읽기 함수.
- 메인 함수:
- 24C02 EEPROM(주소 0x50)에 데이터 쓰기/읽기 예제 포함.
- 실제 장치 주소와 레지스터는 데이터시트에 맞게 수정 필요.
STM32 HAL API와의 차이점
- 하드웨어 제약: AT89C51은 하드웨어 I2C 모듈이 없으므로 비트뱅으로 구현.
- 타임아웃: timeout 필드는 STM32 스타일로 포함했으나, 예제 단순화를 위해 사용하지 않음.
- 인터럽트: STM32 HAL은 인터럽트/DMA 지원이 기본이나, 이 코드는 폴링 기반.
주의사항
- 타이밍 조정: I2C_Delay()는 시스템 클록에 맞게 조정 필요. 12MHz 외의 클록에서는 _nop_() 횟수 변경.
- 풀업 저항: SCL/SDA에 4.7kΩ 풀업 저항 필수.
- 슬레이브 주소: 7비트 주소 사용, LSB는 읽기(1)/쓰기(0)로 설정.
- 디버깅: 오실로스코프나 로직 애널라이저로 신호 확인 권장.
'MCU > 8051' 카테고리의 다른 글
8051 SPI 비트뱅 코드 구현 : 모드 선택 가능 예제 (3) | 2025.08.22 |
---|---|
8051 SPI 비트뱅(bit-bang)을 STM32 HAL API 스타일로 코드 구현 (0) | 2025.08.02 |
8051 I2C 비트뱅(bit-bang) 코드 구현 (0) | 2025.08.02 |