PIC[2] PICでADXL345 3軸デジタル加速GY-291重力傾斜モジュール

振動を検知したら一定時間LEDを点灯(リレーオン)

回路図

プログラム

// pic12f1822_adxl345_vib_led_hold_nowarn.c
// PIC12F1822 / XC8 v3.x / I2C addr=0x53 固定
// RA0=LED, RA1=SCL, RA2=SDA
// 起動平均→振動検知→保持点灯(警告なし版)

#include <xc.h>
#include <stdint.h>
#include <stdbool.h>

#pragma config FOSC=INTOSC, WDTE=OFF, PWRTE=OFF, MCLRE=ON
#pragma config CP=OFF, CPD=OFF, BOREN=ON, CLKOUTEN=OFF
#pragma config IESO=OFF, FCMEN=OFF
#pragma config WRT=OFF, PLLEN=OFF, STVREN=ON, BORV=LO
#pragma config LVP=ON
#define _XTAL_FREQ 8000000UL

// ---- 調整値 ----
#define THRESH_LSB  (50)   // |dx|+|dy|+|dz|
#define HOLD_MS     (800)   // 振動保持時間 [ms]
#define LOOP_MS     (50)    // ループ周期 [ms]

// ---- ピン ----
#define LED_LAT   LATAbits.LATA0
#define LED_TRIS  TRISAbits.TRISA0
#define SCL_TRIS  TRISAbits.TRISA1
#define SDA_TRIS  TRISAbits.TRISA2
#define SDA_IN    PORTAbits.RA2

// ---- ADXL345 ----
#define ADXL_ADDR        ((uint8_t)0x53)
#define REG_DEVID        ((uint8_t)0x00)
#define REG_POWER_CTL    ((uint8_t)0x2D)
#define REG_DATA_FORMAT  ((uint8_t)0x31)
#define REG_BW_RATE      ((uint8_t)0x2C)
#define REG_DATAX0       ((uint8_t)0x32)
#define DEVID_EXPECT     ((uint8_t)0xE5)

// ---- I2C (ソフト, open-drain風) ----
static inline void scl_lo(void){ SCL_TRIS=0; }
static inline void scl_hi(void){ SCL_TRIS=1; }
static inline void sda_lo(void){ SDA_TRIS=0; }
static inline void sda_hi(void){ SDA_TRIS=1; }
static void t(void){ __delay_us(12); }

static void i2c_start(void){ sda_hi(); scl_hi(); t(); sda_lo(); t(); scl_lo(); t(); }
static void i2c_stop(void){ sda_lo(); t(); scl_hi(); t(); sda_hi(); t(); }

static void i2c_wbit(uint8_t b){
    if(b) sda_hi(); else sda_lo();
    t(); scl_hi(); t(); scl_lo(); t();
}
static uint8_t i2c_rbit(void){
    uint8_t v;
    sda_hi(); t();
    scl_hi(); t();
    v = (uint8_t)(SDA_IN ? 1u : 0u);
    scl_lo(); t();
    return v;
}
static bool i2c_wbyte(uint8_t v){
    for(int8_t i=7; i>=0; i--) i2c_wbit((uint8_t)((v>>i)&1u));
    return (i2c_rbit()==0u); // ACK=0
}
static uint8_t i2c_rbyte(bool ack){
    uint8_t v=0u;
    for(int8_t i=7; i>=0; i--){ v=(uint8_t)((v<<1) | i2c_rbit()); }
    i2c_wbit( ack ? 0u : 1u );    // ACK=0 / NACK=1
    return v;
}

static bool i2c_write_reg(uint8_t a7, uint8_t reg, uint8_t val){
    i2c_start();
    if(!i2c_wbyte((uint8_t)(((uint16_t)a7<<1) | 0u))){ i2c_stop(); return false; }  // SLA+W
    if(!i2c_wbyte(reg)){ i2c_stop(); return false; }
    if(!i2c_wbyte(val)){ i2c_stop(); return false; }
    i2c_stop();
    return true;
}
static bool i2c_read_multi(uint8_t a7, uint8_t reg, uint8_t *buf, uint8_t n){
    i2c_start();
    if(!i2c_wbyte((uint8_t)(((uint16_t)a7<<1) | 0u))){ i2c_stop(); return false; }  // SLA+W
    if(!i2c_wbyte(reg)){ i2c_stop(); return false; }
    i2c_start();
    if(!i2c_wbyte((uint8_t)(((uint16_t)a7<<1) | 1u))){ i2c_stop(); return false; }  // SLA+R
    for(uint8_t i=0u; i<n; i++) buf[i]=i2c_rbyte((bool)(i<(uint8_t)(n-1u)));
    i2c_stop();
    return true;
}

static inline int16_t iabs16(int16_t v){ return (v<0) ? (int16_t)(-v) : v; }

void main(void){
    // 8MHz OSC
    OSCCONbits.IRCF=0b1110; OSCCONbits.SCS=0b10;

    // GPIO
    ANSELA=0x00;
    LED_TRIS=0; LED_LAT=0;
    LATAbits.LATA1=0; LATAbits.LATA2=0;
    scl_hi(); sda_hi();
    OPTION_REGbits.nWPUEN=0; WPUAbits.WPUA1=1; WPUAbits.WPUA2=1;
    __delay_ms(10);

    // ==== ADXL345 init ====
    uint8_t id=0u; (void)i2c_read_multi(ADXL_ADDR, REG_DEVID, &id, 1u);
    (void)i2c_write_reg(ADXL_ADDR, REG_BW_RATE, 0x0Au);      // 100Hz
    (void)i2c_write_reg(ADXL_ADDR, REG_DATA_FORMAT, 0x08u);  // FULL_RES, ±2g
    (void)i2c_write_reg(ADXL_ADDR, REG_POWER_CTL, 0x08u);    // Measure=1
    __delay_ms(10);

    // ==== 起動時に基準取得(20サンプル平均)====
    int32_t accX=0, accY=0, accZ=0;
    uint8_t buf[6];
    for(uint8_t n=0u; n<20u; n++){
        if(i2c_read_multi(ADXL_ADDR, REG_DATAX0, buf, 6u)){
            int16_t x = (int16_t)((uint16_t)buf[1]<<8 | buf[0]);
            int16_t y = (int16_t)((uint16_t)buf[3]<<8 | buf[2]);
            int16_t z = (int16_t)((uint16_t)buf[5]<<8 | buf[4]);
            accX += (int32_t)x; accY += (int32_t)y; accZ += (int32_t)z;
        }
        __delay_ms(10);
    }
    int16_t baseX = (int16_t)(accX / 20L);
    int16_t baseY = (int16_t)(accY / 20L);
    int16_t baseZ = (int16_t)(accZ / 20L);

    // ==== メインループ ====
    int16_t hold_counter = 0;
    while(1){
        if(i2c_read_multi(ADXL_ADDR, REG_DATAX0, buf, 6u)){
            int16_t x=(int16_t)((uint16_t)buf[1]<<8 | buf[0]);
            int16_t y=(int16_t)((uint16_t)buf[3]<<8 | buf[2]);
            int16_t z=(int16_t)((uint16_t)buf[5]<<8 | buf[4]);

            int16_t dx = (int16_t)(x - baseX);
            int16_t dy = (int16_t)(y - baseY);
            int16_t dz = (int16_t)(z - baseZ);

            int32_t diff = (int32_t)iabs16(dx) + (int32_t)iabs16(dy) + (int32_t)iabs16(dz);
            if(diff > (int32_t)THRESH_LSB){
                hold_counter = (int16_t)(HOLD_MS / LOOP_MS); // 保持時間リセット
            }
        }

        if(hold_counter > 0){
            LED_LAT = 1;
            hold_counter--;
        }else{
            LED_LAT = 0;
        }

        __delay_ms(LOOP_MS);
    }
}