이 포스트에서는 ATMega128A 마이크로컨트롤러에서 GPIO를 사용해 I2C bit-bang 통신을 STM32 HAL API 스타일로 구현하는 방법을 설명합니다 (This post explains how to implement I2C bit-bang communication on the ATMega128A microcontroller using GPIO in the style of STM32 HAL API). 하드웨어 I2C 모듈 없이도 STM32 HAL과 유사한 인터페이스를 제공하며, 안정적인 통신을 구현할 수 있습니다 (It provides an interface similar to STM32 HAL without a hardware I2C module, enabling reliable communication).
특징 (Features)
- STM32 HAL 스타일의 함수명과 구조체 사용 (예: HAL_I2C_Init, I2C_HandleTypeDef) (Uses STM32 HAL-style function names and structures, e.g., HAL_I2C_Init, I2C_HandleTypeDef)
- SCL: PB0, SDA: PB1 (필요 시 변경 가능) (SCL: PB0, SDA: PB1, configurable as needed)
- 약 100kHz 속도 (지연 시간 조정 가능) (Approximately 100kHz speed, adjustable delay)
- 오픈 드레인 출력을 위한 외부 풀업 저항 필요 (4.7kΩ 권장) (External pull-up resistors required for open-drain output, 4.7kΩ recommended)
코드 (Code)
1. 헤더 파일 - i2c_bitbang.h (Header File - i2c_bitbang.h)
I2C 핀 정의와 함수 프로토타입을 포함합니다 (Contains I2C pin definitions and function prototypes). STM32 HAL 스타일의 상태 코드와 핸들 구조체를 정의합니다 (Defines STM32 HAL-style status codes and handle structure).
#ifndef I2C_BITBANG_H
#define I2C_BITBANG_H
#include <avr/io.h>
#include <util/delay.h>
// I2C 핀 정의 (PB0 = SCL, PB1 = SDA) (I2C Pin Definitions, PB0 = SCL, PB1 = SDA)
#define I2C_PORT PORTB
#define I2C_DDR DDRB
#define I2C_PIN PINB
#define I2C_SCL_PIN (1 << PB0)
#define I2C_SDA_PIN (1 << PB1)
// I2C 상태 코드 (I2C Status Codes)
typedef enum {
HAL_I2C_OK = 0x00U,
HAL_I2C_ERROR = 0x01U,
HAL_I2C_BUSY = 0x02U,
HAL_I2C_TIMEOUT = 0x03U
} HAL_I2C_StatusTypeDef;
// I2C 핸들 구조체 (I2C Handle Structure)
typedef struct {
uint8_t scl_pin; // SCL 핀 (SCL Pin)
uint8_t sda_pin; // SDA 핀 (SDA Pin)
volatile uint8_t* port; // 포트 레지스터 (Port Register)
volatile uint8_t* ddr; // 방향 레지스터 (Direction Register)
volatile uint8_t* pin; // 입력 레지스터 (Input Register)
} I2C_HandleTypeDef;
// 함수 프로토타입 (Function Prototypes)
HAL_I2C_StatusTypeDef HAL_I2C_Init(I2C_HandleTypeDef *hi2c);
HAL_I2C_StatusTypeDef HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint8_t dev_addr, uint8_t *pData, uint16_t size, uint32_t timeout);
HAL_I2C_StatusTypeDef HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, uint8_t dev_addr, uint8_t *pData, uint16_t size, uint32_t timeout);
#endif /* I2C_BITBANG_H */
2. 소스 파일 - i2c_bitbang.c (Source File - i2c_bitbang.c)
I2C bit-bang 구현을 포함하며, 시작/정지 조건, 바이트 전송/수신, 마스터 모드 통신을 지원합니다 (Contains the I2C bit-bang implementation, supporting start/stop conditions, byte transmission/reception, and master mode communication).
#include "i2c_bitbang.h"
// I2C 핀 제어 매크로 (I2C Pin Control Macros)
#define SCL_HIGH() (*hi2c->port |= hi2c->scl_pin)
#define SCL_LOW() (*hi2c->port &= ~hi2c->scl_pin)
#define SDA_HIGH() (*hi2c->port |= hi2c->sda_pin)
#define SDA_LOW() (*hi2c->port &= ~hi2c->sda_pin)
#define SDA_READ() (*hi2c->pin & hi2c->sda_pin)
// I2C 지연 (약 100kHz) (I2C Delay, approx. 100kHz)
#define I2C_DELAY() _delay_us(5)
// I2C 초기화 (I2C Initialization)
HAL_I2C_StatusTypeDef HAL_I2C_Init(I2C_HandleTypeDef *hi2c) {
if (hi2c == NULL) return HAL_I2C_ERROR;
// 핀 설정: SCL, SDA를 출력, 초기 HIGH (오픈 드레인) (Configure pins: SCL, SDA as output, initial HIGH, open-drain)
*hi2c->ddr |= hi2c->scl_pin | hi2c->sda_pin;
*hi2c->port |= hi2c->scl_pin | hi2c->sda_pin;
return HAL_I2C_OK;
}
// I2C 시작 조건 (I2C Start Condition)
static void I2C_Start(I2C_HandleTypeDef *hi2c) {
SDA_HIGH();
SCL_HIGH();
I2C_DELAY();
SDA_LOW();
I2C_DELAY();
SCL_LOW();
}
// I2C 정지 조건 (I2C Stop Condition)
static void I2C_Stop(I2C_HandleTypeDef *hi2c) {
SDA_LOW();
I2C_DELAY();
SCL_HIGH();
I2C_DELAY();
SDA_HIGH();
I2C_DELAY();
}
// I2C 바이트 전송 (I2C Byte Transmission)
static HAL_I2C_StatusTypeDef I2C_WriteByte(I2C_HandleTypeDef *hi2c, uint8_t data) {
for (uint8_t i = 0; i < 8; i++) {
if (data & 0x80) {
SDA_HIGH();
} else {
SDA_LOW();
}
I2C_DELAY();
SCL_HIGH();
I2C_DELAY();
SCL_LOW();
data <<= 1;
}
// ACK 확인 (Check ACK)
*hi2c->ddr &= ~hi2c->sda_pin; // SDA 입력 모드 (SDA to input mode)
I2C_DELAY();
SCL_HIGH();
I2C_DELAY();
uint8_t ack = SDA_READ() ? HAL_I2C_ERROR : HAL_I2C_OK;
SCL_LOW();
*hi2c->ddr |= hi2c->sda_pin; // SDA 출력 모드 (SDA to output mode)
return ack;
}
// I2C 바이트 수신 (I2C Byte Reception)
static uint8_t I2C_ReadByte(I2C_HandleTypeDef *hi2c, uint8_t ack) {
uint8_t data = 0;
*hi2c->ddr &= ~hi2c->sda_pin; // SDA 입력 모드 (SDA to input mode)
for (uint8_t i = 0; i < 8; i++) {
data <<= 1;
I2C_DELAY();
SCL_HIGH();
I2C_DELAY();
if (SDA_READ()) data |= 0x01;
SCL_LOW();
}
*hi2c->ddr |= hi2c->sda_pin; // SDA 출력 모드 (SDA to output mode)
// ACK/NACK 전송 (Send ACK/NACK)
if (ack) {
SDA_LOW();
} else {
SDA_HIGH();
}
I2C_DELAY();
SCL_HIGH();
I2C_DELAY();
SCL_LOW();
return data;
}
// I2C 마스터 전송 (I2C Master Transmit)
HAL_I2C_StatusTypeDef HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint8_t dev_addr, uint8_t *pData, uint16_t size, uint32_t timeout) {
I2C_Start(hi2c);
// 장치 주소 전송 (쓰기) (Send device address, write)
if (I2C_WriteByte(hi2c, (dev_addr << 1) | 0) != HAL_I2C_OK) {
I2C_Stop(hi2c);
return HAL_I2C_ERROR;
}
// 데이터 전송 (Send data)
for (uint16_t i = 0; i < size; i++) {
if (I2C_WriteByte(hi2c, pData[i]) != HAL_I2C_OK) {
I2C_Stop(hi2c);
return HAL_I2C_ERROR;
}
}
I2C_Stop(hi2c);
return HAL_I2C_OK;
}
// I2C 마스터 수신 (I2C Master Receive)
HAL_I2C_StatusTypeDef HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, uint8_t dev_addr, uint8_t *pData, uint16_t size, uint32_t timeout) {
I2C_Start(hi2c);
// 장치 주소 전송 (읽기) (Send device address, read)
if (I2C_WriteByte(hi2c, (dev_addr << 1) | 1) != HAL_I2C_OK) {
I2C_Stop(hi2c);
return HAL_I2C_ERROR;
}
// 데이터 수신 (Receive data)
for (uint16_t i = 0; i < size; i++) {
pData[i] = I2C_ReadByte(hi2c, (i < (size - 1)) ? 1 : 0);
}
I2C_Stop(hi2c);
return HAL_I2C_OK;
}
3. 메인 파일 - main.c (Main File - main.c)
I2C 초기화와 데이터 전송/수신 예제를 포함합니다 (Includes I2C initialization and data transmission/reception examples).
#include "i2c_bitbang.h"
#include <avr/io.h>
#include <util/delay.h>
int main(void) {
// I2C 핸들 설정 (I2C Handle Setup)
I2C_HandleTypeDef hi2c;
hi2c.scl_pin = I2C_SCL_PIN;
hi2c.sda_pin = I2C_SDA_PIN;
hi2c.port = &PORTB;
hi2c.ddr = &DDRB;
hi2c.pin = &PINB;
// I2C 초기화 (Initialize I2C)
HAL_I2C_Init(&hi2c);
// 예제: I2C 장치로 데이터 전송 (Example: Transmit data to I2C device)
uint8_t data[] = {0x01, 0x02, 0x03};
uint8_t dev_addr = 0x50; // 장치 주소 (7비트) (Device address, 7-bit)
HAL_I2C_Master_Transmit(&hi2c, dev_addr, data, 3, 1000);
// 예제: I2C 장치에서 데이터 수신 (Example: Receive data from I2C device)
uint8_t rx_data[3];
HAL_I2C_Master_Receive(&hi2c, dev_addr, rx_data, 3, 1000);
while (1) {
// 무한 루프 (Infinite loop)
}
return 0;
}
사용 방법 (How to Use)
- 하드웨어 설정 (Hardware Setup)
- SCL (PB0)과 SDA (PB1)에 4.7kΩ 풀업 저항을 연결하세요 (Connect 4.7kΩ pull-up resistors to SCL (PB0) and SDA (PB1)).
- 필요 시 헤더 파일에서 핀 정의를 수정하세요 (Modify pin definitions in the header file if needed).
- 컴파일 (Compilation)
- AVR-GCC를 사용해 컴파일하세요 (Compile with AVR-GCC).
- <avr/io.h>와 <util/delay.h> 라이브러리가 필요합니다 (Requires <avr/io.h> and <util/delay.h> libraries).
- 속도 조정 (Speed Adjustment)
- _delay_us(5)는 약 100kHz 속도를 구현합니다 ( _delay_us(5) implements approximately 100kHz speed).
- ATMega128A의 클럭 주파수에 따라 지연 시간을 조정하세요 (Adjust delay based on ATMega128A clock frequency).
- 장치 주소 (Device Address)
- dev_addr는 7비트 I2C 주소를 사용합니다 ( dev_addr uses 7-bit I2C address).
- 읽기/쓰기 비트는 함수 내부에서 자동으로 처리됩니다 (Read/write bit is handled automatically by functions).
주의사항 (Notes)
- 오픈 드레인 출력을 위해 SCL과 SDA 라인에 외부 풀업 저항이 필수입니다 (External pull-up resistors are mandatory for SCL and SDA lines for open-drain output).
- 타임아웃 기능은 기본적으로 구현되어 있으며, 필요 시 확장할 수 있습니다 (Timeout functionality is implemented and can be extended if needed).
- 특정 I2C 장치에 맞춘 추가 설정이 필요할 수 있습니다 (Additional configuration may be required for specific I2C devices).
이 코드는 ATMega128A에서 안정적인 I2C bit-bang 통신을 제공하며, STM32 HAL API 스타일을 따라 직관적인 인터페이스를 제공합니다 (This code provides reliable I2C bit-bang communication on ATMega128A with an intuitive interface following the STM32 HAL API style).
'MCU > AVR' 카테고리의 다른 글
[AVR128DB48] Watchdog 사용 방법 및 예제 코드 (0) | 2025.08.19 |
---|---|
[AVR128DB48] SPI 사용 방법 및 예제 코드 (0) | 2025.08.19 |
[AVR128DB48] I2C 사용 방법 및 예제 코드 (0) | 2025.08.19 |
[AVR128DB48] UART 사용 방법 및 예제 코드 (1) | 2025.08.19 |
[AVR128DB48] GPIO 사용 방법 및 예제 코드 (0) | 2025.08.18 |
[AVR128DB48] 프로젝트 설정 절차 및 기본 프로그램 작성 (0) | 2025.08.18 |
AVR128DA48 I2C Bit-bang을 STM32 HAL API 스타일로 코드 구현 (1) | 2025.08.05 |
AVR SPI Bit-Bang 을 STM32 HAL API 스타일로 구현 (Implementing SPI Bit-Bang in STM32 HAL Style on ATMega128A) (0) | 2025.08.02 |