ESP32-WROOM-32EとSDカードで加速度の履歴を保存

組み込みエンジニア

こんにちは、ENGかぴです。

ESP32-WROOM-32EのWire(SPI)を使用すると加速度センサー(ADXL345)のデータを取得することができます。加速度センサーのイベントを発生させイベント発生前後の様子をSDカードに履歴として保存する方法をまとめました。

ESP32-WROOM-32Eの開発環境はArduino IDEを使用しています。またESP32-WROOM-32E開発ボード(秋月電子)及びADXL345モジュール(秋月電子)を使用しています。

SDカードモジュールはmicroSDカードスロットレベルシフタ付きブレークアウト基板キット:AE-microSD-LLCNV(秋月電子)を使用しています。

下記記事で動作確認したADXL345のフォールイベントのデータをSDカードに保存します。

ESP32-WROOM-32Eで加速度の変化をグラフ表示する

WiFi通信を使って最新のデータを表示してSDカードに保存した履歴データと一致するか確認を行います。

ESP32-WROOM-32Eで動作確認したことについてリンクをまとめています。

ESP32-WROOM-32Eで学べるソフト開発と標準ライブラリの使い方

SDカードに加速度のイベント履歴を保存

Arduino環境ではSDカードを操作する標準ライブラリが実装されています。SDカードモジュールの配線とライブラリの使用方法を説明します。

ESP32-WROOM-32EとSDカードモジュールの構成

動作確認用の回路図
動作確認用の回路図

ADXL345はWire(I2C)通信を使用します。Wireを使用する場合はプルアップ抵抗が必要ですがADXL345モジュールに実装されているため必要ありません。ADXL345のイベント発生をDIで検出するため17ピンをRISING(立ち上がり)として使用します。

SDカードモジュールの電源は5VなのでESP32-WROOM-32Eの5Vを供給しています。

SDカードの操作はSPI通信を使用します。ESP32-WROOM-32EはVSPIとHSPIがありますが、特に指定しない場合VSPIピンが有効になります。HSPIを使用する場合は下記記事に使用例をまとめていますので参考にしてください。

ESP32-WROOM-32EのSPIでBME280の情報を取得

すき間時間で資格をゲット【STUDYing(スタディング)】

ライブラリの準備と初期化

#include <SPI.h>
#include <SD.h>

File myfile; //SDカードの状態を格納

void setup() {

  if(!SD.begin()){
    //初期化失敗の処理
  }
}

SDカードの操作はSPI通信を使用するためSD.hとSPI.hの2つのライブラリをインクルードする必要があります。SPIのスレーブ選択のDOを指定する必要がありますがデフォルトで5ピンが指定されています。

SDカードのファイルに関する情報等を管理するにFile型のクラス変数を変数を宣言します。例ではmyfileの宣言しています。

SDライブラリのbegin()関数を使用してSDカードに関する情報を初期化します。引数にはSDカードを選択するためのスレーブセレクト(SS)のピン番号を指定します。指定しない場合はデフォルトの5ピンで初期化が行われます。

SDカードが挿入されていない場合など失敗した場合は戻り値がfalseになるので必要があれば失敗したときの処理を入れます。

Code Camp完全オンラインのプログラミング個人レッスン【無料体験】

データの書き込み(動作履歴の保存)

myfile = SD.open(filepath,FILE_WRITE);

  if(myfile){
    myfile.println(" ,x,y,z");

    for(uint16_t i = 0; i< CHART_SZ; i++ ){
      myfile.print(i);
      myfile.print(",");
      myfile.print(wave[0][i]);
      myfile.print(",");
      myfile.print(wave[1][i]);
      myfile.print(",");
      myfile.println(wave[2][i]); 
    }
    myfile.close(); //ファイルを閉じる
      
  }else{
    Serial.println("SD-ERR");
}

open()関数でファイルを書き込みモードで開きます。open()関数の第1引数にはファイルのパスを指定し、第2引数に書き込みを示すFILE_WRITEを指定します。ファイルが開けたらprint()関数を使用してデータを書き込みます。

print()関数でデータの番号とX,Y,Z軸の加速度情報を書き込みます。データの間に”,”を入れているのはテキストデータをCSVファイルに変換したときにセルを分けるためです。書き込みデータの最後は改行コードを入れるためprintln()で書き込みを行います。

データを書き込んだ後はファイルを閉じるためclose()関数を使用します。

データの読み込み(参考)

本記事ではデータの読み込みは使用しませんが参考の為データの読み込みについてまとめています。

//ファイル名を指定して読み込む場合の例
String filepath = "sample.txt"; //SDカード内に保存するファイル名

 if (SD.exists(filepath)) { //ファイルが存在するか
    Serial.println("sample.txt exists.");
    myfile = SD.open(filepath,FILE_READ); //ファイルを開く

    if(myfile){ //ファイルが開けた場合
      while(myfile.available()){
        str ="";
        str = myfile.readStringUntil('\n'); //読み込み
      }
      myfile.close(); //ファイルを閉じる
    }
  } else {
    Serial.println("sample.txt doesn't exist.");
  }

SDカードからデータを読み出す場合にファイルが存在しているかをexists()関数で確認します。引数には開くファイル名を含めたパスを指定します。

ファイルが存在するかを確認せずにopen()関数で読み込みを行っても読み込み失敗になるためexists()関数で確認してからファイルを開くかは好みになります。

ファイルが存在する場合はopen()関数でファイルを読み込み専用で開きます。第1引数にはファイルのパスを指定し、第2引数に読み込みを示すFILE_READを指定します。

ファイルのopenに成功するとFileオブジェクト(myfileで宣言した変数)に戻り値として状態が引き継がれるためmyfileを使ってデータの読み込みを行います。

Fileオブジェクトのavailable()関数を使って読み込むデータが存在するかを確認します。データが存在する場合は0より大きな値になるためRead()関数を使ってデータを読み込みます。例ではReadStringUntil()関数を使って改行コードが見つかるまでデータを読み込んでいます。

データを読み込んだ後はファイルを閉じるためclose()関数を使用します。

//ディレクトリのファイル名を表示
File root = SD.open("/");
File file = root.openNextFile();

while(file){
  Serial.println(file.name());
  file = root.openNextFile();
}

SDカード内のファイルを表示する例を示しています。open()関数に”/”を指定することで直下のディレクトリが開きます。openNextFile()でファイルを指定しながらname()関数でファイル名を取得しています。

while()で繰り返すことで存在するファイル名をすべて表示することができます。対象のファイルがない場合はfalseになるためwhile()から抜けます。

すき間時間で資格をゲット【STUDYing(スタディング)】

加速度データをグラフで表示する

ADXL345の加速度情報をWiFiでブラウザー上にグラフ表示する方法は下記記事にまとめています。本記事ではグラフ用のデータの準備のポイントのみを説明します。

ESP32-WROOM-32Eで加速度の変化をグラフ表示する

グラフ表示はChart.jsを使っています。Chart.jsを使ってブラウザー上にグラフ表示する方法を下記記事まとめています。

Chart.jsを使ってデータをブラウザー上でグラフ表示する

加速度データをグラフ表示するためのデータを準備します。グラフ表示する目安としてADXL345のイベントを使います。今回はFREE FALLがイベントを検出した前後250msの加速度情報を保存して表示します。

加速度情報の保存の考え方
加速度情報の保存の考え方

加速度情報を保管するバッファはリング構成にすることでxyzdata[]配列のサイズをオーバーしないようにデータを更新することができます。wpはxyzdata[]配列におけるデータの格納場所を示すポインタです。

FREE FALLイベントが発生すると250ms分の加速度情報を取得してからwave[]配列にイベント発生時の加速度情報を格納します。

  adxl.getAcceleration(xyz); //XYZの加速度の取得
  ax = xyz[0];
  getdata.xyz[0][getdata.wp] = ax;

  if(++getdata.wp >= CHART_SZ ){
    getdata.wp = 0;
  }

  if( timEventWait > TIME_UP ){ //イベントが発生したらスタート
    if( ++evescnt >= CHART_HALF_SZ ){ //イベント発生から250ms経過
      int16_t rp;
      uint16_t i;

      rp = getdata.wp;
      for( i = 0; i < CHART_SZ; i++){
        wave[0][i] = getdata.xyz[0][rp];
        if( ++rp >= CHART_SZ ){
          rp = 0;
        }
      }
      timEventWait = TIME_UP;
      evescnt = 0;
    }
  }

getdata.xyz[]配列に格納している加速度情報を時系列でグラフで表示するために並び替えしながら格納します。wpはgetdata[]において次にデータを格納する場所を示すポインタなのでwp+1のデータが時系列でみた時getdata[]内の最古のデータになります。

最古のデータの位置をrpの初期値としてgetdata[]配列のサイズ分順に取得して格納することで時系列で整理したデータになります。

FREE FALLイベント発生直後からデータを取得するのではなくイベント発生以前のデータを含めて取得することでイベント発生の様子を確認することができます。

動作確認

WiFi通信を使用して加速度センサーの情報をグラフで表示します。同時にフォールイベントが発生したタイミングのシリアルプロッタの様子と比較します。SDカードに保存している履歴のデータについてもデータが一致することを確認します。

加速度情報のグラフ表示(FREE FALL発生時)
加速度情報のグラフ表示(FREE FALL発生時)

スマホ(Android)のGoogle ChromeでIPアドレス「192.168.11.2」を入力しリクエストを送るとESP32-WROOM-32Eからスマホに返信しFREE FALLが発生した時のデータの様子を示すグラフ表示されました。

シリアルプロッタでのグラフ表示を行ってFREE FALL発生時のデータと一致するかを確かめました。

シリアルプロッタでの確認
シリアルプロッタでの確認

シリアルプロッタのグラフとスマホのグラフを比較すると波形の形がほぼ一致していることが分かりました。位置がずれているのはシリアルプロッタをスクリーンショットするタイミングによるものです。SDカードに履歴が保存されているかを確認しました。

SDカードに保存した履歴ファイル
SDカードに保存した履歴ファイル

SDカード内に履歴が2つ保存されていました。グラフ表示しているのは最新のイベントなので「logData-2.text」のデータを確認して上記2つのデータと一致するかを確認しました。テキストデータをCSVデータに変換してエクセルデータで保存してグラフ表示しました。

SDカードに保存した履歴のデータをエクセルでグラフ表示した結果
SDカードに保存した履歴のデータをエクセルでグラフ表示した結果

エクセルで表示したグラフを確認するとスマホで確認したグラフ及びシリアルプロッタで確認したデータのグラフと一致していることが分かりました。SDカードに履歴が保存されていることが確認できました。

SDカードに履歴を保存できたことでブラウザ上でSDカードのファイルを選択してグラフ表示するなど応用例が広がりそうです。

スポンサーリンク

ソースコード全体

以下のソースコードはコンパイルして動作確認をしております。コメントなど細かな部分で間違っていたりやライブラリの更新などにより動作しなくなったりする可能性があります。参考としてお使いいただければと思います。

#include <Wire.h>
#include <WiFi.h>
#include <WebServer.h>
#include <SPIFFS.h>
#include <ADXL345.h>
#include <SPI.h>
#include <SD.h>

#define SPI_SS 5
#define SLAVE_ADRS 0x45
#define POLYNOMIAL 0x31
#define CHART_SZ 500
#define CHART_HALF_SZ (CHART_SZ/2)
#define TIME_OFF -1 //タイマーを使用しない場合
#define TIME_UP 0 //タイムアップ
#define BASE_CNT 10 //ベースタイマカウント値
#define TIME_ADXL_MAX 1
#define TIME_EVENT_WAIT_MAX 600

#define INT_DATA_READY_BIT_MASK 0x80
#define INT_SINGLE_TAP_BIT_MASK 0x40
#define INT_DOUBLE_TAP_BIT_MASK 0x20
#define INT_ACTIVITY_BIT_MASK   0x10
#define INT_INACTIVITY_BIT_MASK 0x08
#define INT_FREE_FALL_BIT_MASK  0x04
#define INT_WATERMARK_BIT_MASK  0x02
#define INT_OVERRUNY_BIT_MASK   0x01

#define ACT_TAP_ACT_X 0x40
#define ACT_TAP_ACT_Y 0x20
#define ACT_TAP_ACT_Z 0x10
#define ACT_TAP_TAP_X 0x04
#define ACT_TAP_TAP_Y 0x02
#define ACT_TAP_TAP_Z 0x01

#define PIN_DI1 17
//#define MONITER_USE

typedef struct{
  uint16_t wp;
  uint16_t rp;
  double xyz[3][CHART_SZ];
}DATA_RING;

const char *ssid = "EngKapi1"; //SSID
const char *pass = "22223333"; //password
const IPAddress ip(192,168,11,2); //IPアドレス
const IPAddress subnet(255,255,255,0); //サブネットマスク
  
/* 変数宣言 */
WebServer Wserver(80);
uint32_t beforetimCnt = millis();
ADXL345 adxl;
byte intsrc;    //割り込みイベント
byte intsrc2;   //アクティブまたはタップイベントの内容
byte int2src;
int16_t  timAdxl345get;
int16_t  timEventWait = TIME_OFF;
volatile bool intboo1 = false;
double wave[3][CHART_SZ];
double xyzdata[3][CHART_SZ];
DATA_RING getdata;
uint16_t evescnt;
File myfile;
uint16_t logcnt = 1;
//String filepath ="logData-";

/* プロトタイプ宣言 */
void mainApp(void);
void HtmlSet(void);
void handleNotFound(void);
void charDataSet(void);
void InitAdxl345();
void Adxl345Rcv();
void IRAM_ATTR irt1(void);
void SdSave(void);

void setup() {

  Serial.begin(115200);

  if(!SD.begin()){
    Serial.println("initialization failed!");
    while (1);
  }
  //Wire.begin();
  InitAdxl345();

  WiFi.softAP(ssid, pass); //WiFiのアクセスポイントの設定
  WiFi.softAPConfig(ip, ip, subnet); //アクセスポイントのIP及びサブネットマス
  SPIFFS.begin();
  Wserver.serveStatic("/myfavicon.ico",SPIFFS,"/myfavicon.ico");
  Wserver.serveStatic("/chart.min.js",SPIFFS, "/chart.min.js");
  
  Wserver.on("/", HTTP_GET, HtmlSet); //URLを指定して処理する関数を指定
  Wserver.onNotFound(handleNotFound); //URLが存在しない場合の処理する関数を指定
  Wserver.begin(); //Webサーバーの開始

  pinMode(PIN_DI1,INPUT_PULLDOWN);
  attachInterrupt(PIN_DI1,irt1,RISING);
}

void loop() {

  mainTimer();
  mainApp();
  Wserver.handleClient();
}
/* タイマ管理 */
void mainTimer(void){

  if ( millis() - beforetimCnt >= BASE_CNT ){
    beforetimCnt = millis();

    if( timAdxl345get > TIME_UP ){
      --timAdxl345get;
    }
    if( timEventWait > TIME_UP ){
      --timEventWait;
    }
  }
}
/* DIがRISINGして割込み処理 */
void IRAM_ATTR irt1(void){
    intboo1 = true;
}
/* メイン処理関数 */
void mainApp(void){
    
  if( intboo1 ){ //INT1
    intboo1 = false;
    intsrc = adxl.getInterruptSource();
    #ifdef MONITER_USE
        if( intsrc & INT_SINGLE_TAP_BIT_MASK){
            Serial.println("SINGLE_TAP");
        }
        if( intsrc & INT_DOUBLE_TAP_BIT_MASK){
            Serial.println("DOUBLE_TAP");
        }
        if( intsrc & INT_ACTIVITY_BIT_MASK){
            Serial.println("Activity");
        }
        if( intsrc & INT_INACTIVITY_BIT_MASK){
            Serial.println("inactivity");
        }
        if( intsrc & INT_FREE_FALL_BIT_MASK){
            Serial.println("FREE_FALL");
        }
        if( adxl.isActivitySourceOnX()){
            Serial.println("ACT X");
        }
        if( adxl.isActivitySourceOnY()){
            Serial.println("ACT Y");
        }
        if( adxl.isActivitySourceOnZ()){
            Serial.println("ACT Z");
        }
        if(adxl.isTapSourceOnX()){
            Serial.println("TAP X");
        }        
        if(adxl.isTapSourceOnY()){
            Serial.println("TAP Y");
        } 
        if(adxl.isTapSourceOnZ()){
            Serial.println("TAP Z");
        }
    #endif

    if( intsrc & INT_FREE_FALL_BIT_MASK){
      if( timEventWait == TIME_OFF ){
        timEventWait = TIME_EVENT_WAIT_MAX;
      }
    }
  }

  if( timAdxl345get == TIME_UP ){
    timAdxl345get = TIME_ADXL_MAX;
    Adxl345Rcv();
  }
  if( timEventWait == TIME_UP ){
    timEventWait = TIME_OFF;
  }
}
/* 加速度情報の取得 */
void Adxl345Rcv(){
  double xyz[3];
  double ax,ay,az;

  adxl.getAcceleration(xyz); //XYZの加速度の取得
  ax = xyz[0];
  ay = xyz[1];
  az = xyz[2];
  getdata.xyz[0][getdata.wp] = ax;
  getdata.xyz[1][getdata.wp] = ay;
  getdata.xyz[2][getdata.wp] = az;

  if(++getdata.wp >= CHART_SZ ){
     getdata.wp = 0;
  }

  if( timEventWait > TIME_UP ){
    if( ++evescnt >= CHART_HALF_SZ ){ //イベント発生から250ms経過
      int16_t rp;
      uint16_t i;
      
      rp = getdata.wp;
      for( i = 0; i < CHART_SZ; i++){
        wave[0][i] = getdata.xyz[0][rp];
        wave[1][i] = getdata.xyz[1][rp];
        wave[2][i] = getdata.xyz[2][rp];

        if( ++rp >= CHART_SZ ){
          rp = 0;
        }
      }
      timEventWait = TIME_UP;
      evescnt = 0;
      SdSave();
    }
  }
  #ifndef  MONITER_USE
    Serial.print("X:");
    Serial.print(ax);
    Serial.print(",");
    Serial.print("Y:");
    Serial.print(ay);
    Serial.print(",");
    Serial.print("Z:");
    Serial.print(az);
    Serial.println("");
  #endif
}
/* クライアントに返信するhtmlデータを生成 */
void HtmlSet(void){
  String str = "";

  str += "<html lang=\"ja\">";
  str += "<head>";
  //str += "<meta http-equiv=\"refresh\" content=\"5\">";
  str += "<meta charset=\"UTF-8\">";
  str += "<title>Sensor SHT35</title>";
  str += "<link rel='shortcut icon' href='/myfavicon.ico' />";
  str += "<script src = '/chart.min.js'></script>"; 
  str += "</head>";
  str += "<body>";
  str += "<h1>ESP32-ADXL345加速度センサ</h1>";
  str += "<h2>WebServerライブラリを使用</h2>";
  str += "<div style='height: 600px; width: 800px; margin: auto;'>";
  str += "<canvas id='ChartID'></canvas>";
  str += "</div>";
  str += "<script>";
  str += "var ctx = document.getElementById('ChartID').getContext('2d');";
  str += "var myChart = new Chart(ctx, {";
  str += "type: 'line',";
  str += "data: {";
  str += "labels: [ ";
    for(uint16_t i = 0; i< CHART_SZ; i++ ){
      str += i; 
      if(i != CHART_SZ-1 )str += ",";
    }   
  str += "],";
  str += "datasets: [{";
  str += "label: 'X',";
  str += "fill: false,";
  str += "borderColor: 'blue',";
  str += "borderWidth: 1,";
  str += "pointRadius: 0,";
  str += "pointHoverBorderWidth: 10,";
  str += "data: [";
    for(uint16_t i = 0; i< CHART_SZ; i++ ){
      str += wave[0][i]; 
      if(i != CHART_SZ-1 )str += ",";
    }
  str += "]";
  str += "}, {";
  str += "label: 'Y',";
  str += "fill: false,";
  str += "borderColor: 'red',";
  str += "borderWidth: 1,";
  str += "pointRadius: 0,";
  str += "pointHoverBorderWidth: 10,";
  str += "pointStyle: 'rect',";
  str += "data: [";
    for(uint16_t i = 0; i< CHART_SZ; i++ ){
      str += wave[1][i]; 
      if(i != CHART_SZ-1 )str += ",";
    }
  str += "]";
  str += "}, {";
  str += "label: 'Z',";
  str += "fill: false,";
  str += "borderColor: 'green',";
  str += "borderWidth: 1,";
  str += "pointRadius: 0,";
  str += "pointHoverBorderWidth: 10,";
  str += "pointStyle: 'triangle',";
  str += "yAxisID: 'y',";
  str += "data: [";
    for(uint16_t i = 0; i< CHART_SZ; i++ ){
      str += wave[2][i]; 
      if(i != CHART_SZ-1 )str += ",";
    }
  str += "]";
  str += "}]";
  str += "},";
  str += "options: {";
  str += "responsive: true,";
  str += "plugins: {";
  str += "title: {";
  str += "display: true,";
  str += "text: 'ADXL345から取得した加速度',";
  str += "font: {";
  str += "size: 18,";
  str += "},";
  str += "},";
  str += "},";
  str += "scales: {";
  str += "x: {";
  str += "display: true,";
  str += "stacked: false,";
  str += "title: {";
  str += "display: true,";
  str += "text: 'サンプル数',";
  str += "font: {";
  str += "size: 16,";
  str += "},";      
  str += "},";
  str += "},";
  str += "y: {";
  str += "min: -4,";
  str += "max: 4,";
  str += "title: {";
  str += "display: true,";
  str += "text: '加速度[g]',";
  str += "color: 'black',";
  str += "font: {";
  str += "size: 16,";
  str += "},";
  str += "},";
  str += "ticks:{";
  str += "display: true,";          
  str += "color: 'black',";
  str += "},";
  str += "},";
  str += "},";
  str += "},";
  str += "})";
  str += "</script>";
  str += "</body>";
  str += "</html>";
  detachInterrupt(PIN_DI1);//htmlデータ送信時に割り込み禁止
  Wserver.send(200,"text/html", str); 
  //HTTPレスポンス200でhtmlデータとして送信
  attachInterrupt(PIN_DI1,irt1,RISING); //割り込み復帰
}
/* URLが存在しない場合の処理 */
void handleNotFound(void) {

  String message = "File Not Found\n\n";
  message += "URI: ";
  message += Wserver.uri();
  message += "\nMethod: ";
  message += (Wserver.method() == HTTP_GET) ? "GET" : "POST";
  message += "\nArguments: ";
  message += Wserver.args();
  message += "\n";

  for (uint8_t i = 0; i < Wserver.args(); i++) {
    message += " " + Wserver.argName(i) + ": " + Wserver.arg(i) + "\n";
  }
  Wserver.send(404, "text/plain", message); //テキストファイルであることを示している。
}
/* 加速度センサーの初期化 */
void InitAdxl345(){
    byte dmy;

    adxl.powerOn();
    //set activity/ inactivity thresholds (0-255)
    adxl.setActivityThreshold(75); //62.5mg per increment 75
    adxl.setInactivityThreshold(75); //62.5mg per increment
    adxl.setTimeInactivity(10); // how many seconds of no activity is inactive?
    //look of activity movement on this axes - 1 == on; 0 == off 
    adxl.setActivityX(1);
    adxl.setActivityY(1);
    adxl.setActivityZ(1);
    //look of inactivity movement on this axes - 1 == on; 0 == off
    adxl.setInactivityX(1);
    adxl.setInactivityY(1);
    adxl.setInactivityZ(1);
    //look of tap movement on this axes - 1 == on; 0 == off
    adxl.setTapDetectionOnX(0);//0
    adxl.setTapDetectionOnY(0);//0
    adxl.setTapDetectionOnZ(1);//1
    //set values for what is a tap, and what is a double tap (0-255)
    adxl.setTapThreshold(50); //62.5mg per increment
    adxl.setTapDuration(15); //625us per increment
    adxl.setDoubleTapLatency(80); //1.25ms per increment
    adxl.setDoubleTapWindow(200); //1.25ms per increment
    //set values for what is considered freefall (0-255)
    adxl.setFreeFallThreshold(5); //(5 - 9) recommended - 62.5mg per increment 7
    adxl.setFreeFallDuration(20); //(20 - 70) recommended - 5ms per increment 45
    
    adxl.setFullResBit(1);
    adxl.setRangeSetting(4); //4g Range
  
    adxl.setInterruptMapping( ADXL345_INT_SINGLE_TAP_BIT,   ADXL345_INT1_PIN );
    adxl.setInterruptMapping( ADXL345_INT_DOUBLE_TAP_BIT,   ADXL345_INT1_PIN );
    adxl.setInterruptMapping( ADXL345_INT_FREE_FALL_BIT,    ADXL345_INT1_PIN );
    adxl.setInterruptMapping( ADXL345_INT_ACTIVITY_BIT,     ADXL345_INT1_PIN );
    adxl.setInterruptMapping( ADXL345_INT_INACTIVITY_BIT,   ADXL345_INT1_PIN );
 
    adxl.setInterrupt( ADXL345_INT_SINGLE_TAP_BIT, 1);
    adxl.setInterrupt( ADXL345_INT_DOUBLE_TAP_BIT, 1);
    adxl.setInterrupt( ADXL345_INT_FREE_FALL_BIT,  1);
    adxl.setInterrupt( ADXL345_INT_ACTIVITY_BIT,   1);
    adxl.setInterrupt( ADXL345_INT_INACTIVITY_BIT, 1);

    dmy = adxl.getInterruptSource(); //ダミーで割り込みビットをクリア
}

/* SDカードに履歴を保存*/
void SdSave(void){
  String filepath ="/logData-";

  filepath.concat(logcnt);
  filepath.concat(".txt");

  if (SD.exists(filepath)) {
    ++logcnt;
  }
  else{
    myfile = SD.open(filepath,FILE_WRITE);

    if(myfile){
      myfile.println(" ,x,y,z");

      for(uint16_t i = 0; i< CHART_SZ; i++ ){
        myfile.print(i);
        myfile.print(",");
        myfile.print(wave[0][i]);
        myfile.print(",");
        myfile.print(wave[1][i]);
        myfile.print(",");
        myfile.println(wave[2][i]); 
      }

      myfile.close(); //ファイルを閉じる
      ++logcnt;
    }else{
        Serial.println("SD-ERR");
    }
  }
}

本ソースコードでグラフ表示するためにChart.jsライブラリをESP32 Sketch Data Uploadを使ってフラッシュ領域に書き込んでおく必要があります。

関連リンク

Arduinoのライブラリを使って動作確認を行ったことを下記リンクにまとめています。

Arduinoで学べるマイコンのソフト開発と標準ライブラリの使い方

Seeeduino XIAOで学べるソフト開発と標準ライブラリの使い方

ESP32-WROOM-32Eで学べるソフト開発と標準ライブラリの使い方

テックジム|ゼロからはじめるPython入門講座の申込

最後まで、読んでいただきありがとうございました。

タイトルとURLをコピーしました