STM32

STM32 I2C 설정 및 센서 통신 예제

임베디드 친구 2024. 11. 24. 18:33
반응형

안녕하세요, 소프트웨어 공장입니다. 오늘은 STM32F429ZI 보드에서 I2C를 설정하고 이를 활용하여 센서와 통신하는 방법에 대해 다뤄보겠습니다. I2C는 다양한 센서와 모듈을 연결하기에 매우 유용한 통신 방식입니다. 이번 글에서는 I2C의 기본 개념을 설명한 후, STM32CubeIDE를 사용하여 STM32F429ZI 보드의 IO를 설정하고, 실제 센서와 통신하는 예제를 작성해 보겠습니다.

1. I2C란 무엇인가?

I2C(Inter-Integrated Circuit)는 Philips에서 개발한 직렬 통신 프로토콜로, 여러 개의 슬레이브 장치를 하나의 마스터와 연결하여 사용할 수 있는 간단하고 유연한 통신 방식입니다. I2C는 두 개의 선(SCL: Serial Clock Line, SDA: Serial Data Line)으로 데이터 전송을 수행하며, 마스터-슬레이브 구조를 통해 통신을 진행합니다.

I2C의 주요 특징은 다음과 같습니다:

  • 양방향 데이터 전송: SDA 핀을 통해 데이터를 주고받으며, 양방향 통신을 지원합니다.
  • 클럭 신호 동기화: SCL 핀을 통해 마스터가 슬레이브에 클럭 신호를 제공하여 통신이 이루어집니다.
  • 다중 슬레이브: 하나의 마스터에 여러 슬레이브 장치를 연결하여 통신이 가능합니다.

2. STM32CubeIDE를 사용한 I2C 설정 방법

이제 STM32F429ZI 보드에서 I2C 통신을 설정하는 방법을 알아보겠습니다. 우리는 STM32CubeIDE를 사용하여 I2C를 설정할 것이며, 다음의 단계를 통해 진행됩니다.

2.1 프로젝트 생성

  1. STM32CubeIDE를 실행하여 새 프로젝트를 생성합니다.
  2. STM32F429ZI 칩을 선택하고 프로젝트 이름을 지정한 후 프로젝트를 생성합니다.
  3. 프로젝트가 생성되면 Pinout & Configuration 창이 열립니다.

2.2 I2C 핀 설정

  1. Pinout 탭에서, 보드의 I2C 기능을 활성화하기 위해 I2C1을 사용하도록 설정합니다. STM32F429ZI에서는 PB6 (SCL)PB7 (SDA) 핀을 I2C1로 사용할 수 있습니다.
  2. Pinout에서 I2C1을 선택하면 자동으로 PB6PB7 핀이 활성화됩니다. 이 두 핀은 각각 SCL과 SDA 역할을 하게 됩니다.
  3. GPIO 설정: 각 핀을 선택하면 좌측의 GPIO Mode and Configuration 섹션에서 설정이 가능합니다. I2C의 경우, SCL과 SDA 모두 기본값인 Alternate Function Open Drain 모드로 설정되어야 합니다.

2.3 I2C 설정

  1. Configuration 탭으로 이동합니다.
  2. 좌측 메뉴에서 I2C1을 선택합니다.
  3. I2C ModeI2C로 설정하고, Clock Speed는 연결할 장치의 요구사항에 맞게 설정합니다. 일반적으로 많이 사용하는 속도는 100kHz와 400kHz입니다.
  4. Addressing Mode는 대부분의 센서가 사용하는 7-bit Address를 설정합니다.
  5. 필요에 따라 DMA를 사용할 수도 있지만, 이번 예제에서는 DMA 설정은 생략하겠습니다.

2.4 코드 생성 및 빌드

  1. 설정이 완료되면 Project > Generate Code를 클릭하여 코드를 생성합니다.
  2. STM32CubeIDE가 자동으로 초기화 코드를 생성하며, 이제 우리는 이 코드를 기반으로 I2C를 이용한 센서 통신을 구현할 수 있습니다.

3. I2C를 이용한 센서 통신 예제

이번 예제에서는 BME280 환경 센서를 사용하여 온도, 습도, 압력을 측정해 보겠습니다. BME280은 I2C를 통해 쉽게 연결할 수 있는 대표적인 센서입니다.

3.1 센서 연결

  • PB6 (SCL)PB7 (SDA) 핀을 각각 BME280의 SCL 및 SDA 핀에 연결합니다.
  • 전원(VCC)과 GND를 적절히 연결하여 회로를 완성합니다.

3.2 코드 작성

아래는 I2C 초기화 코드와 BME280 센서 데이터를 읽는 예제 코드입니다.

#include "main.h"
#include "i2c.h"
#include "usart.h"
#include "gpio.h"

#define BME280_ADDRESS 0x76 << 1  // BME280의 I2C 주소 (7-bit 주소를 왼쪽으로 1 비트 shift하여 사용)

uint8_t BME280_Init(void);
uint8_t BME280_Read_Temperature(void);

int main(void)
{
  HAL_Init();
  SystemClock_Config();

  MX_GPIO_Init();
  MX_I2C1_Init();
  MX_USART2_UART_Init();

  if (BME280_Init() == HAL_OK)
  {
    printf("BME280 초기화 성공\n");
  }
  else
  {
    printf("BME280 초기화 실패\n");
  }

  while (1)
  {
    uint8_t temperature = BME280_Read_Temperature();
    printf("온도: %d°C\n", temperature);
    HAL_Delay(1000);
  }
}

uint8_t BME280_Init(void)
{
  uint8_t settings = 0xF4; // 초기화 설정 레지스터 값
  return HAL_I2C_Master_Transmit(&hi2c1, BME280_ADDRESS, &settings, 1, HAL_MAX_DELAY);
}

uint8_t BME280_Read_Temperature(void)
{
  uint8_t reg = 0xFA; // 온도 데이터를 읽기 위한 레지스터 주소
  uint8_t temp[3] = {0};

  HAL_I2C_Master_Transmit(&hi2c1, BME280_ADDRESS, &reg, 1, HAL_MAX_DELAY);
  HAL_I2C_Master_Receive(&hi2c1, BME280_ADDRESS, temp, 3, HAL_MAX_DELAY);

  // BME280의 온도는 20-bit 데이터로 제공되며, 이를 변환하여 사용해야 합니다.
  uint32_t temp_raw = (temp[0] << 12) | (temp[1] << 4) | (temp[2] >> 4);
  return (uint8_t)(temp_raw / 100);  // 섭씨로 변환하여 반환
}

3.3 코드 설명

  1. BME280_Init(): 센서를 초기화하기 위해 설정 레지스터에 초기화 값을 전달합니다. 이 과정에서 HAL_I2C_Master_Transmit() 함수를 사용하여 I2C 통신을 수행합니다.
  2. BME280_Read_Temperature(): 온도 레지스터 주소를 전송한 후, 센서로부터 3바이트 데이터를 읽어와 온도를 계산합니다. 데이터 변환은 BME280 데이터 시트에 명시된 계산 방식을 따릅니다.
  3. HAL_I2C_Master_Transmit() 및 HAL_I2C_Master_Receive(): 각각 I2C 마스터가 데이터를 전송하고 수신하는 역할을 합니다. HAL_MAX_DELAY는 무한 대기 시간을 의미하며, 데이터가 올 때까지 기다립니다.

3.4 I2C 및 GPIO 설정 확인

STM32CubeIDE로 생성된 i2c.c 파일에는 다음과 같이 I2C 설정 코드가 자동으로 생성됩니다:

void MX_I2C1_Init(void)
{
  hi2c1.Instance = I2C1;
  hi2c1.Init.ClockSpeed = 100000;
  hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
  hi2c1.Init.OwnAddress1 = 0;
  hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  hi2c1.Init.OwnAddress2 = 0;
  hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
  if (HAL_I2C_Init(&hi2c1) != HAL_OK)
  {
    Error_Handler();
  }
}

위 코드는 I2C의 초기화 설정을 담당하며, 보드와 센서 간의 통신 속도와 모드를 설정합니다. 기본 설정은 100kHz의 클럭 속도와 7비트 주소 모드로 되어 있으며, 이는 대부분의 센서와의 통신에 적합합니다.


다음은 I2C핀 설정 부분입니다.

void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOB_CLK_ENABLE();

  /*Configure GPIO pin : PB6 (I2C1_SCL) */
  GPIO_InitStruct.Pin = GPIO_PIN_6;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_InitStruct.Alternate = GPIO_AF4_I2C1;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /*Configure GPIO pin : PB7 (I2C1_SDA) */
  GPIO_InitStruct.Pin = GPIO_PIN_7;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_InitStruct.Alternate = GPIO_AF4_I2C1;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}

4. 마무리

이번 포스팅에서는 STM32F429ZI 보드에서 I2C 통신을 설정하고 이를 활용하여 BME280 센서로부터 온도 데이터를 읽어오는 방법에 대해 알아보았습니다. STM32CubeIDE를 사용하여 I2C를 간편하게 설정하고 HAL 라이브러리를 이용하여 코드 작성이 가능하다는 점에서, 많은 장치와 센서를 손쉽게 다룰 수 있다는 장점이 있습니다.

I2C는 간단하면서도 강력한 통신 프로토콜이므로, 다양한 센서와의 인터페이스를 구현할 때 매우 유용합니다.

반응형