본문 바로가기
MCU/STM32

ADXL345 가속도 센서  STM32 HAL 라이브러리 드라이버 코드 구현

by linuxgo 2025. 8. 24.

이 문서는 ADXL345 3축 가속도 센서를 STM32 마이크로컨트롤러와 HAL 라이브러리를 이용해 완벽하게 제어하는 방법을 안내합니다. 센서의 상세 사양부터, 핀 연결, 그리고 실제 동작하는 디바이스 드라이버 코드까지 단계별로 설명합니다.

1. ADXL345 가속도 센서 사양

ADXL345는 저전력, 소형, 3축 가속도 센서로, 정적(Static) 및 동적(Dynamic) 가속도 측정이 가능합니다. 특히 다양한 내장 기능 덕분에 복잡한 알고리즘 없이도 충격 및 동작 감지를 손쉽게 구현할 수 있습니다.

  • 측정 범위: ±2g, ±4g, ±8g, ±16g (사용자가 설정 가능)
  • 해상도: 10비트 고정 해상도 또는 Full Resolution 모드(최대 13비트) 지원
  • 통신 인터페이스: 4-wire SPI (직렬 통신) 및 I2C 지원
  • 전력 소모: 측정 모드에서 140µA, 대기 모드에서 0.1µA의 초저전력 소모
  • 내장 기능:
    • 탭 감지 (단일 및 더블 탭)
    • 활동/비활동 감지
    • 자유낙하 감지
    • FIFO (First-In, First-Out) 버퍼: 최대 32개의 데이터를 저장하여 호스트 프로세서의 부하를 줄임

2. 하드웨어 연결 및 STM32CubeMX 설정

STM32CubeMX 설정

  1. Pinout & Configuration:
    •    SPI1 (또는 연결한 SPI 모듈)을 Full-Duplex Master로 설정합니다.
    •    Parameter Settings: CPOL: High, CPHA: 2 Edge로 설정하여 ADXL345와 호환되는 모드(SPI Mode 3)를 사용합니다.
    •    GPIO: CS(Chip Select) 핀을 GPIO Output으로 설정합니다.
  2. Clock Configuration: SPI 통신 속도에 맞게 클럭을 설정합니다.

3. ADXL345 디바이스 드라이버 코드 분석

드라이버는 센서의 복잡한 하드웨어 동작을 추상화하여 사용자가 쉽게 센서를 제어할 수 있도록 도와줍니다. 아래 코드는 크게 세 부분으로 나뉩니다.

  1. adxl345.h: 드라이버의 인터페이스를 정의하는 헤더 파일입니다. 센서의 레지스터 주소, 열거형(Enum), 데이터 구조체 및 공개 함수들을 선언하여 다른 파일에서 쉽게 접근할 수 있도록 합니다.
  2. adxl345.c: 선언된 함수들을 실제로 구현하는 파일입니다. ADXL345_ReadRegister, ADXL345_WriteRegister와 같은 핵심 통신 함수들이 포함되어 있습니다. 이 함수들이 레지스터의 읽기/쓰기 동작을 처리하며, 다른 모든 상위 함수들은 이들을 호출하여 센서를 제어합니다.
  3. main.c: 드라이버를 실제 애플리케이션에 적용하는 예시 파일입니다. 드라이버 초기화부터 가속도 데이터 읽기, 그리고 감지 기능 활용 예시를 보여줍니다.

4. 코드 구현

STM32 프로젝트에 포함될 실제 드라이버 코드입니다.

adxl345.h

#ifndef ADXL345_H
#define ADXL345_H

#include <stdint.h>

// ADXL345 드라이버의 상태를 나타내는 열거형
typedef enum {
    ADXL345_OK       = 0x00, // 성공
    ADXL345_ERROR    = 0x01, // 오류 발생
    ADXL345_BUSY     = 0x02, // 통신이 바쁜 상태
    ADXL345_TIMEOUT  = 0x03  // 통신 타임아웃
} ADXL345_StatusTypeDef;

// 3축 가속도 데이터를 저장하기 위한 구조체
typedef struct {
    int16_t x; // X축 가속도 데이터 (16비트)
    int16_t y; // Y축 가속도 데이터 (16비트)
    int16_t z; // Z축 가속도 데이터 (16비트)
} ADXL345_AccelData_t;

// 데이터 전송률(Data Rate) 설정에 사용되는 열거형 (BW_RATE 레지스터)
typedef enum {
    ADXL345_DATARATE_3200HZ = 0x0F,
    ADXL345_DATARATE_1600HZ = 0x0E,
    ADXL345_DATARATE_800HZ  = 0x0D,
    ADXL345_DATARATE_400HZ  = 0x0C,
    ADXL345_DATARATE_200HZ  = 0x0B,
    ADXL345_DATARATE_100HZ  = 0x0A, // 기본값(Default)
    ADXL345_DATARATE_50HZ   = 0x09,
    ADXL345_DATARATE_25HZ   = 0x08,
    ADXL345_DATARATE_12_5HZ = 0x07,
    ADXL345_DATARATE_6_25HZ = 0x06,
    ADXL345_DATARATE_3_13HZ = 0x05,
    ADXL345_DATARATE_1_56HZ = 0x04,
    ADXL345_DATARATE_0_78HZ = 0x03,
    ADXL345_DATARATE_0_39HZ = 0x02,
    ADXL345_DATARATE_0_20HZ = 0x01,
    ADXL345_DATARATE_0_10HZ = 0x00
} ADXL345_DataRate_t;

// 측정 범위(Measurement Range) 설정에 사용되는 열거형 (DATA_FORMAT 레지스터)
typedef enum {
    ADXL345_RANGE_2G  = 0x00, // ±2g
    ADXL345_RANGE_4G  = 0x01, // ±4g
    ADXL345_RANGE_8G  = 0x02, // ±8g
    ADXL345_RANGE_16G = 0x03  // ±16g
} ADXL345_Range_t;

// 활동/비활동 감지 모드 설정에 사용되는 열거형 (ACT_INACT_CTL 레지스터)
typedef enum {
    ADXL345_ACT_MODE_DC = 0, // DC-coupled (정적 가속도 감지)
    ADXL345_ACT_MODE_AC = 1  // AC-coupled (동적 가속도 감지)
} ADXL345_ActivityMode_t;

// 인터럽트 소스/활성화 비트 마스크 정의 (INT_ENABLE, INT_MAP, INT_SOURCE 레지스터)
#define ADXL345_INT_DATA_READY  (1 << 7) // 새 데이터 사용 가능
#define ADXL345_INT_SINGLE_TAP  (1 << 6) // 단일 탭 감지
#define ADXL345_INT_DOUBLE_TAP  (1 << 5) // 더블 탭 감지
#define ADXL345_INT_ACTIVITY    (1 << 4) // 활동 감지
#define ADXL345_INT_INACTIVITY  (1 << 3) // 비활동 감지
#define ADXL345_INT_FREE_FALL   (1 << 2) // 자유낙하 감지
#define ADXL345_INT_WATERMARK   (1 << 1) // FIFO 워터마크
#define ADXL345_INT_OVERRUN     (1 << 0) // FIFO 오버런

// 탭 감지 축 비트 마스크 (TAP_AXES 레지스터)
#define ADXL345_TAP_AXIS_X      (1 << 0) // X축 탭 감지
#define ADXL345_TAP_AXIS_Y      (1 << 1) // Y축 탭 감지
#define ADXL345_TAP_AXIS_Z      (1 << 2) // Z축 탭 감지

// FIFO 모드 설정에 사용되는 열거형 (FIFO_CTL 레지스터)
typedef enum {
    ADXL345_FIFO_BYPASS   = 0x00, // FIFO 비활성화
    ADXL345_FIFO_FIFO     = 0x01, // FIFO 모드: 꽉 차면 데이터 덮어쓰지 않음
    ADXL345_FIFO_STREAM   = 0x02, // 스트림 모드: 새 데이터로 오래된 데이터 덮어씀
    ADXL345_FIFO_TRIGGER  = 0x03  // 트리거 모드
} ADXL345_FIFOMode_t;

// FIFO 트리거 인터럽트 핀 맵핑 (FIFO_CTL 레지스터)
typedef enum {
    ADXL345_INT_PIN_INT1 = 0, // 인터럽트 핀 1
    ADXL345_INT_PIN_INT2 = 1  // 인터럽트 핀 2
} ADXL345_IntPin_t;


/* --------------------- 공개 함수(Public Functions) 선언 --------------------- */

// 드라이버 및 센서 초기화
ADXL345_StatusTypeDef ADXL345_Init(void);

// 가속도 데이터 읽기
ADXL345_StatusTypeDef ADXL345_GetAccelerometerData(ADXL345_AccelData_t *accel_data);

// ADXL345의 다양한 기능들을 설정하는 함수들
ADXL345_StatusTypeDef ADXL345_SetOffset(int8_t offset_x, int8_t offset_y, int8_t offset_z);
ADXL345_StatusTypeDef ADXL345_SetDataRate(ADXL345_DataRate_t rate, uint8_t low_power);
ADXL345_StatusTypeDef ADXL345_SetRangeAndFormat(ADXL345_Range_t range, uint8_t full_res);
ADXL345_StatusTypeDef ADXL345_SetTapThreshold(uint8_t threshold);
ADXL345_StatusTypeDef ADXL345_SetTapDuration(uint8_t duration);
ADXL345_StatusTypeDef ADXL345_SetTapLatency(uint8_t latency);
ADXL345_StatusTypeDef ADXL345_SetTapWindow(uint8_t window);
ADXL345_StatusTypeDef ADXL345_SetActivityThreshold(uint8_t threshold);
ADXL345_StatusTypeDef ADXL345_SetInactivityThreshold(uint8_t threshold);
ADXL345_StatusTypeDef ADXL345_SetInactivityTime(uint8_t time);
ADXL345_StatusTypeDef ADXL345_SetActivityInactivityControl(uint8_t activity_enable, uint8_t inactivity_enable, ADXL345_ActivityMode_t activity_mode, ADXL345_ActivityMode_t inactivity_mode);
ADXL345_StatusTypeDef ADXL345_SetFreefallThreshold(uint8_t threshold);
ADXL345_StatusTypeDef ADXL345_SetFreefallTime(uint8_t time);
ADXL345_StatusTypeDef ADXL345_SetTapAxes(uint8_t tap_axes, uint8_t suppress_double_tap);

// 인터럽트 관련 함수들
ADXL345_StatusTypeDef ADXL345_EnableInterrupts(uint8_t interrupts);
ADXL345_StatusTypeDef ADXL345_MapInterruptsToINT1(uint8_t interrupts);
ADXL345_StatusTypeDef ADXL345_GetInterruptSource(uint8_t *source);

// FIFO 관련 함수들
ADXL345_StatusTypeDef ADXL345_SetFIFOMode(ADXL345_FIFOMode_t mode, uint8_t samples, ADXL345_IntPin_t trigger_int);
ADXL345_StatusTypeDef ADXL345_GetFIFOStatus(uint8_t *fifo_status);

#endif // ADXL345_H

adxl345.c

#include "adxl345.h"
#include "stm32g4xx_hal.h" // STM32CubeMX에서 사용하는 HAL 라이브러리
#include <string.h> // memcpy 함수 사용을 위해 포함

// SPI 핸들 선언. 이 변수는 main.c 등에서 초기화된 핸들을 사용
// CubeMX에서 생성된 SPI 핸들 변수명과 일치시켜야 함 (예: hspi1)
extern SPI_HandleTypeDef hspi1;

// ADXL345에 연결된 SPI 핸들 정의.
// SPI1이 아닌 다른 모듈을 사용한다면 &hspi1 부분을 변경해야 함.
#define ADXL345_SPI_HANDLE &hspi1

// ADXL345 레지스터 주소 정의
#define ADXL345_DEVID           0x00 // 디바이스 ID (읽기 전용)
#define ADXL345_THRESH_TAP      0x1D // 탭 감지 임계값
#define ADXL345_OFSX            0x1E // X축 오프셋
#define ADXL345_OFSY            0x1F // Y축 오프셋
#define ADXL345_OFSZ            0x20 // Z축 오프셋
#define ADXL345_DUR             0x21 // 탭 감지 지속 시간
#define ADXL345_LATENT          0x22 // 탭 감지 대기 시간
#define ADXL345_WINDOW          0x23 // 탭 감지 윈도우 시간
#define ADXL345_THRESH_ACT      0x24 // 활동 감지 임계값
#define ADXL345_THRESH_INACT    0x25 // 비활동 감지 임계값
#define ADXL345_TIME_INACT      0x26 // 비활동 감지 시간
#define ADXL345_ACT_INACT_CTL   0x27 // 활동/비활동 감지 제어
#define ADXL345_THRESH_FF       0x28 // 자유낙하 감지 임계값
#define ADXL345_TIME_FF         0x29 // 자유낙하 감지 시간
#define ADXL345_TAP_AXES        0x2A // 탭 감지 축 제어
#define ADXL345_ACT_TAP_STATUS  0x2B // 탭/활동 상태 (읽기 전용)
#define ADXL345_BW_RATE         0x2C // 데이터 전송률 및 전력 모드
#define ADXL345_POWER_CTL       0x2D // 전원 제어 및 측정 모드
#define ADXL345_INT_ENABLE      0x2E // 인터럽트 활성화
#define ADXL345_INT_MAP         0x2F // 인터럽트 핀 맵핑
#define ADXL345_INT_SOURCE      0x30 // 인터럽트 소스 (읽기 전용)
#define ADXL345_DATA_FORMAT     0x31 // 데이터 형식 및 측정 범위
#define ADXL345_DATAX0          0x32 // X축 가속도 데이터 (LSB)
#define ADXL345_DATAX1          0x33 // X축 가속도 데이터 (MSB)
#define ADXL345_DATAY0          0x34 // Y축 가속도 데이터 (LSB)
#define ADXL345_DATAY1          0x35 // Y축 가속도 데이터 (MSB)
#define ADXL345_DATAZ0          0x36 // Z축 가속도 데이터 (LSB)
#define ADXL345_DATAZ1          0x37 // Z축 가속도 데이터 (MSB)
#define ADXL345_FIFO_CTL        0x38 // FIFO 제어
#define ADXL345_FIFO_STATUS     0x39 // FIFO 상태 (읽기 전용)

// SPI 통신 명령어 비트 정의
#define ADXL345_SPI_READ        0x80 // 읽기 작업 (최상위 비트 1)
#define ADXL345_SPI_MULTI_BYTE  0x40 // 멀티 바이트(연속) 접근 (비트 6을 1로 설정)

// 정적(static) 함수 선언: 이 파일 내에서만 사용
static ADXL345_StatusTypeDef ADXL345_ReadRegister(uint8_t reg_addr, uint8_t *data);
static ADXL345_StatusTypeDef ADXL345_WriteRegister(uint8_t reg_addr, uint8_t data);
static ADXL345_StatusTypeDef ADXL345_ReadMultiRegister(uint8_t reg_addr, uint8_t *data, uint8_t len);


/**
  * @brief  ADXL345 초기화 함수
  * 센서의 디바이스 ID를 확인하고, 측정 모드 및 데이터 포맷을 설정합니다.
  * @param  None
  * @retval ADXL345_StatusTypeDef 결과 상태
  */
ADXL345_StatusTypeDef ADXL345_Init(void)
{
    uint8_t dev_id;
    ADXL345_StatusTypeDef status;

    // 1. 디바이스 ID 레지스터(0x00)를 읽어 통신이 정상인지 확인
    status = ADXL345_ReadRegister(ADXL345_DEVID, &dev_id);
    // ADXL345의 고유 ID는 0xE5. 이 값이 아니면 통신 오류로 간주
    if (status != ADXL345_OK || dev_id != 0xE5) {
        return ADXL345_ERROR;
    }

    // 2. POWER_CTL 레지스터(0x2D) 설정: 측정 모드(Measure Mode) 활성화
    // MEASURE 비트(3번 비트)를 1로 설정
    status = ADXL345_WriteRegister(ADXL345_POWER_CTL, 0x08);
    if (status != ADXL345_OK) return status;

    // 3. DATA_FORMAT 레지스터(0x31) 설정: 측정 범위와 해상도 설정
    // 0x0B (0b00001011) -> SELF_TEST=0, SPI=0, INT_INVERT=0, FULL_RES=1, JUSTIFY=0, Range=11 (+/-16g)
    // FULL_RES 비트를 1로 설정하여 Full Resolution 모드를 사용하면 측정 범위에 따라 해상도가 자동으로 최대 13비트까지 조절됩니다.
    status = ADXL345_WriteRegister(ADXL345_DATA_FORMAT, 0x0B);
    if (status != ADXL345_OK) return status;

    // 4. BW_RATE 레지스터(0x2C) 설정: 데이터 전송률(Data Rate) 설정
    // 0x0A (0b00001010) -> Low_Power=0, Rate=100Hz
    status = ADXL345_WriteRegister(ADXL345_BW_RATE, 0x0A);
    if (status != ADXL345_OK) return status;

    return ADXL345_OK;
}

/**
  * @brief  ADXL345의 3축 가속도 데이터를 읽습니다.
  * @param  accel_data 가속도 데이터를 저장할 ADXL345_AccelData_t 구조체 포인터
  * @retval ADXL345_StatusTypeDef 결과 상태
  */
ADXL345_StatusTypeDef ADXL345_GetAccelerometerData(ADXL345_AccelData_t *accel_data)
{
    uint8_t raw_data[6];
    ADXL345_StatusTypeDef status;

    // DATAX0 레지스터(0x32)부터 DATAZ1(0x37)까지 6바이트를 연속해서 읽기
    status = ADXL345_ReadMultiRegister(ADXL345_DATAX0, raw_data, 6);
    if (status != ADXL345_OK) return status;

    // 읽은 8비트 데이터들을 16비트 정수(2의 보수)로 조합
    // LSB(low byte)와 MSB(high byte)를 합쳐 16비트 값으로 변환
    accel_data->x = (int16_t)(((uint16_t)raw_data[1] << 8) | raw_data[0]);
    accel_data->y = (int16_t)(((uint16_t)raw_data[3] << 8) | raw_data[2]);
    accel_data->z = (int16_t)(((uint16_t)raw_data[5] << 8) | raw_data[4]);

    return ADXL345_OK;
}

/**
  * @brief  단일 레지스터를 읽습니다.
  * @param  reg_addr 읽을 레지스터의 주소
  * @param  data     읽은 데이터를 저장할 포인터
  * @retval ADXL345_StatusTypeDef
  */
static ADXL345_StatusTypeDef ADXL345_ReadRegister(uint8_t reg_addr, uint8_t *data)
{
    uint8_t tx_buffer[2]; // 주소(명령) 전송용
    uint8_t rx_buffer[2]; // 데이터 수신용

    // SPI 읽기 명령어 구성: 최상위 비트(bit 7)를 1로 설정 + 레지스터 주소
    tx_buffer[0] = ADXL345_SPI_READ | reg_addr;
    tx_buffer[1] = 0x00; // 더미 바이트 (SPI는 동시 전송이므로 데이터를 읽기 위해 더미 바이트 전송)

    // CS 핀 제어는 이 드라이버 함수 밖에서 담당한다고 가정 (일반적으로 SPI HAL 함수가 처리)
    // ADXL345 SPI 통신 규약: Read 명령어(1바이트)를 보내고, 다음 바이트에서 데이터(1바이트)를 받음
    HAL_StatusTypeDef spi_status = HAL_SPI_TransmitReceive(ADXL345_SPI_HANDLE, tx_buffer, rx_buffer, 2, HAL_MAX_DELAY);
    
    // SPI 통신 결과 확인
    if (spi_status != HAL_OK) {
        return ADXL345_ERROR;
    }
    
    // 수신 버퍼의 첫 번째 바이트는 명령 바이트의 에코(echo)이므로, 두 번째 바이트가 실제 데이터
    *data = rx_buffer[1];

    return ADXL345_OK;
}

/**
  * @brief  단일 레지스터에 씁니다.
  * @param  reg_addr 쓸 레지스터의 주소
  * @param  data     쓸 데이터
  * @retval ADXL345_StatusTypeDef
  */
static ADXL345_StatusTypeDef ADXL345_WriteRegister(uint8_t reg_addr, uint8_t data)
{
    uint8_t tx_buffer[2]; // 주소와 데이터를 동시에 전송

    // SPI 쓰기 명령어 구성: 최상위 비트(bit 7)를 0으로 설정 + 레지스터 주소
    tx_buffer[0] = reg_addr;
    tx_buffer[1] = data; // 쓸 데이터

    HAL_StatusTypeDef spi_status = HAL_SPI_Transmit(ADXL345_SPI_HANDLE, tx_buffer, 2, HAL_MAX_DELAY);

    if (spi_status != HAL_OK) {
        return ADXL345_ERROR;
    }
    return ADXL345_OK;
}

/**
  * @brief  여러 레지스터를 연속해서 읽습니다.
  * @param  reg_addr 읽기 시작할 레지스터 주소
  * @param  data     읽은 데이터를 저장할 버퍼
  * @param  len      읽을 바이트 수
  * @retval ADXL345_StatusTypeDef
  */
static ADXL345_StatusTypeDef ADXL345_ReadMultiRegister(uint8_t reg_addr, uint8_t *data, uint8_t len)
{
    uint8_t tx_buffer[1]; // 명령 바이트만 전송
    uint8_t rx_buffer[len + 1]; // 명령 바이트 에코 + 데이터 바이트만큼 수신

    // 읽기 명령어(bit 7) + 멀티 바이트 비트(bit 6) + 레지스터 주소
    tx_buffer[0] = ADXL345_SPI_READ | ADXL345_SPI_MULTI_BYTE | reg_addr;

    // SPI 통신: 명령어 전송 후, 연속된 데이터를 수신
    HAL_StatusTypeDef spi_status = HAL_SPI_TransmitReceive(ADXL345_SPI_HANDLE, tx_buffer, rx_buffer, len + 1, HAL_MAX_DELAY);

    if (spi_status != HAL_OK) {
        return ADXL345_ERROR;
    }

    // 수신된 버퍼에서 실제 데이터(두 번째 바이트부터)만 복사
    // memcpy(대상 버퍼, 원본 버퍼 + 오프셋, 바이트 수)
    memcpy(data, rx_buffer + 1, len);

    return ADXL345_OK;
}

// ADXL345_Init, ADXL345_GetAccelerometerData 외에 다른 함수들은 adxl345.h와 일치하도록 추가 구현할 수 있습니다.
// 요청에 따라 다른 기능들도 여기에 추가할 수 있습니다.
// ex) ADXL345_SetOffset(), ADXL345_SetDataRate() 등

main.c

/* USER CODE BEGIN PFP */
// 외부 함수 선언 (사용자 코드 영역에 추가)
void main_ADXL345_Example(void);
/* USER CODE END PFP */

/* USER CODE BEGIN 0 */
// ADXL345 드라이버를 사용하기 위해 헤더 파일 포함
#include "adxl345.h"
#include <stdio.h> // 디버깅용 printf 사용을 위해 필요
/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
  // 변수 선언
  ADXL345_AccelData_t accel_data;
  ADXL345_StatusTypeDef status;
  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */
  // STM32CubeMX에서 UART를 활성화했다면 여기서 추가 설정 가능
  // 예: MX_UART1_Init();
  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_SPI1_Init(); // STM32CubeMX에서 SPI1을 초기화했음을 가정
  // 필요한 경우 다른 주변장치 초기화 함수를 여기에 추가
  /* USER CODE BEGIN 2 */
  // ADXL345 디바이스 드라이버 초기화
  status = ADXL345_Init();
  if (status != ADXL345_OK) {
      // 초기화 실패 시 처리 (LED 깜빡임, 오류 메시지 출력 등)
      // 이 예제에서는 무한루프에 빠지게 함
      while(1) {
          HAL_Delay(500);
      }
  } else {
      // 초기화 성공 시, UART 등으로 메시지 출력
      // 예: printf("ADXL345 초기화 성공!\r\n");
  }

  // 탭 감지 기능 설정 예시
  // 탭 임계값: 0x30 * 62.5mg/LSB = 1.875g
  ADXL345_SetTapThreshold(0x30);
  // 탭 지속 시간: 0x10 * 625us/LSB = 6.25ms
  ADXL345_SetTapDuration(0x10);
  // 모든 축에 대한 탭 감지 활성화
  ADXL345_SetTapAxes(ADXL345_TAP_AXIS_X | ADXL345_TAP_AXIS_Y | ADXL345_TAP_AXIS_Z, 0);

  // 인터럽트 활성화
  ADXL345_EnableInterrupts(ADXL345_INT_DATA_READY | ADXL345_INT_SINGLE_TAP | ADXL345_INT_DOUBLE_TAP);
  // 모든 인터럽트를 INT1 핀에 맵핑
  ADXL345_MapInterruptsToINT1(ADXL345_INT_DATA_READY | ADXL345_INT_SINGLE_TAP | ADXL345_INT_DOUBLE_TAP);

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
      // ADXL345_GetAccelerometerData 함수를 호출하여 가속도 데이터 읽기
      status = ADXL345_GetAccelerometerData(&accel_data);
      if (status == ADXL345_OK) {
          // 가속도 값을 g 단위로 변환
          // ADXL345의 Full resolution 모드에서 +/-16g 범위일 때, 1 LSB = 3.9 mg (0.0039g)
          float x_g = accel_data.x * 0.0039f;
          float y_g = accel_data.y * 0.0039f;
          float z_g = accel_data.z * 0.0039f;

          // 데이터를 UART 등으로 전송하거나 디스플레이에 표시
          // 예: printf("X: %.2f g, Y: %.2f g, Z: %.2f g\r\n", x_g, y_g, z_g);
      } else {
          // 데이터 읽기 실패 시 오류 처리
          // 예: printf("데이터 읽기 실패!\r\n");
      }

      // 인터럽트 소스 레지스터를 읽어 어떤 이벤트가 발생했는지 확인
      uint8_t int_source;
      ADXL345_GetInterruptSource(&int_source);
      if (int_source & ADXL345_INT_SINGLE_TAP) {
          // 단일 탭 감지 이벤트가 발생했을 때의 로직
          // 예: printf("단일 탭 감지! \r\n");
      }
      if (int_source & ADXL345_INT_DOUBLE_TAP) {
          // 더블 탭 감지 이벤트가 발생했을 때의 로직
          // 예: printf("더블 탭 감지! \r\n");
      }

      // 100ms 대기 (데이터 전송률에 따라 조정)
      HAL_Delay(100);
      /* USER CODE END WHILE */

      /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/* USER CODE BEGIN 4 */
// 이 부분에 인터럽트 콜백 함수 등을 추가할 수 있습니다.
/* USER CODE END 4 */

 

5. 결론

이 문서는 ADXL345 센서의 주요 사양STM32 기반의 완벽한 디바이스 드라이버 구현 방법을 다루었습니다. 이 코드를 기반으로 센서의 복잡한 통신을 추상화하여, 동작 인식, 만보계, 자세 추정 등 다양한 프로젝트를 손쉽게 개발할 수 있습니다.