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);
}
}