LoginSignup
3
3

More than 1 year has passed since last update.

m5stackでセンサーデータをsdカードに保存してみた。

Posted at

初めに

I2Cを使って取得可能ないくつかのセンサーデータをsdカードへ保存してみました。

環境

OS: windows 10.0
Arduino IDE:2.0.0
M5stack core2
M5Stack用温湿度気圧センサユニット Ver.3(ENV Ⅲ)link
TVOC/eCO2 ガスセンサユニット(SGP30)link
M5Stack用環境光センサユニット(BH1750FVI-TR)link

#イメージ
M5stack core2から各種センサーに繋いでます。センサーごとにアドレスが違うので、別々に読み出すことができます。
スクリーンショット 2022-10-30 17.14.37.png

時間

一定時間置きに測定をする場合、ネット環境がなければ、RTCが必要ということが分かりました。RTCは、低消費電力なので別電源で時を刻むことができるため、ネットワークの環境がなくても時を刻んでくれます。そのため、RTCが実装されているM5stack core2を使うことにしました。

一定時間置きにデータをcsvに保存する。

RTCから時間情報を取得し、5分おききにデータ取得するようにしました。時間を5で割って、余りが0のときに、一度測定をして、4分後に測定するフラグを0にして5分おきに測定をできるようにしました。

test.cc
bool  meas_csv = false;
bool  write_csv = false;

RTC_TimeTypeDef RTC_TimeStruct; // Time

  if (RTC_TimeStruct.Minutes % 5 == 4 ) meas_csv = true; 
  
  // get the csv per 5min
  if(RTC_TimeStruct.Minutes % 5 == 0){
     if (meas_csv == true){ 
      //write data per 5min.
      meas_csv = false;
      write_csv = true ;
  }
}

日付のファイル名で保存する。

SDカードに保存するときの形式に合わせて、RTCのデータを変換するところが苦労しました。
下記のようにsnprintfを使うと、SDカードに保存するための形式に合うようになりました。

test.cc
char fname[26];
snprintf(fname, 26, "/sensor_data/%04d%02d%02d.csv", RTC_DateStruct.Year, RTC_DateStruct.Month, RTC_DateStruct.Date);

#プログラム
作成したプログラムは、下記のようになります。file.printは、取得したデータの形式が違い、合わせこむ方法が分からなかったので、べた書きしてデータを取得するようにしています。

test.cc
#include <M5Core2.h>
#include <WiFi.h>
#include "time.h"
#include "M5_ENV.h"
#include <M5_DLight.h>
#include "Adafruit_SGP30.h"

// sprite 
TFT_eSprite sprite = TFT_eSprite(&M5.Lcd);
extern uint8_t m5_logo[];

// csv file
File file;

// set up sensor 
SHT3X sht30;
QMP6988 qmp6988;
M5_DLight sensor;
uint16_t lux;
Adafruit_SGP30 sgp;
long last_millis = 0;

// for WiFi
char ssid[] = "xxxxxxx"; // your SSID
char pass[] = "xxxxxxx"; // your Pass word

float tmp      = 0.0;
float hum      = 0.0;
float pressure = 0.0;
int   meas_btm = 1; 
int   con_count = 0;
int   timer_reset = 0;
bool  meas_csv = false;
bool  write_csv = false;
char info[40];

// for Time
const char* ntpServer = "ntp.jst.mfeed.ad.jp"; // NTP server
const long  gmtOffset_sec = 9 * 3600;          // Time offset 9hr
const int   daylightOffset_sec = 0;            // No summer time
RTC_DateTypeDef RTC_DateStruct; // Data
RTC_TimeTypeDef RTC_TimeStruct; // Time
struct tm timeinfo;
String dateStr;
String timeStr;

void setup() {
  M5.begin();
  M5.Lcd.setBrightness(10);
  M5.Lcd.setRotation(1); 
  M5.Lcd.setTextSize(2);
  M5.Lcd.fillScreen(BLACK);

  // connect wifi  
  if (timer_reset == 1){
    WiFi.begin(ssid, pass);
    while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      M5.Lcd.print(".");
      con_count++;
      if(con_count >= 20){
        break;
      }
    }
    if(con_count < 20){
      M5.Lcd.print("\nWiFi connected.");
      setNTP2RTC();
    }else{
      M5.Lcd.print("\nWiFi did not connect.");
    }
    M5.Lcd.print("\nIP=");
    M5.Lcd.print(WiFi.localIP());  
    delay(2 * 1000);
  }

  // Output logo on the display.
  M5.Lcd.fillScreen(BLACK);    
  M5.Lcd.drawJpg(m5_logo,6374,60, 20);
  M5.update();// update button state  
  delay(2 * 1000);

  Wire.begin();               //  // Wire init, adding the I2C bus.
  qmp6988.init();
  if (!sgp.begin()) { 
    M5.Lcd.println("Sensor not found");
    while (1)
      ;
  }
  sensor.begin();
  sensor.setMode(CONTINUOUSLY_H_RESOLUTION_MODE);
  sprite.setColorDepth(8);
  sprite.setTextSize(2);
  sprite.fillScreen(BLACK);
  sprite.createSprite(M5.lcd.width(), M5.lcd.height());
  //make a directory
  if(!SD.exists("/sensor_data")){
    SD.mkdir("/sensor_data");
  }
}

void loop() {

  sprite.pushSprite( 0, 0);
  M5.update();// update button state

  if (RTC_TimeStruct.Minutes % 5 == 4 ) meas_csv = true; 
  
  // get the csv per 5min
  if(RTC_TimeStruct.Minutes % 5 == 0){
     if (meas_csv == true){ 
      //write data per 5min.
      meas_csv = false;
      write_csv = true ;

      M5.Rtc.GetDate(&RTC_DateStruct);
      M5.Rtc.GetTime(&RTC_TimeStruct);

      pressure = qmp6988.calcPressure()* 0.01;
      if (sht30.get() == 0) {  // Obtain the data of shT30.  
        tmp = sht30.cTemp;   // Store the temperature obtained from shT30.
        hum = sht30.humidity;  // Store the humidity obtained from the SHT30.
      } else {
        tmp = 0, hum = 0;
      }

      // for Touch
      TouchPoint_t pos= M5.Touch.getPressPoint();
      if(pos.y > 240){
        if(pos.x < 109)
          sprite.setTextColor(RED,BLACK);
        else if(pos.x > 218)
          sprite.setTextColor(BLUE,BLACK);
        else if(pos.x >= 109 && pos.x <= 218)
          sprite.setTextColor(GREEN,BLACK);
      }   
      lux = sensor.getLUX();
      if (!sgp.IAQmeasure()) {  //Commands the sensor to take a single eCO2/VOC 
        Serial.println("Measurement failed");
        return;
      }
      delay(1 * 1000);

      char fname[26];
      snprintf(fname, 26, "/sensor_data/%04d%02d%02d.csv", RTC_DateStruct.Year, RTC_DateStruct.Month, RTC_DateStruct.Date);

      // write data
      if(!SD.exists(fname)){
        file = SD.open(fname, FILE_APPEND);
        file.print("date,time,temperature,humidity,pressure,lux,TVOC,eCO2\n");
        file.close();
        delay(0.1 * 1000); 
      }
      file = SD.open(fname, FILE_APPEND);
      file.print(RTC_DateStruct.Month);
      file.print("/");
      file.print(RTC_DateStruct.Date);
      file.print(",");
      file.print(RTC_TimeStruct.Hours);
      file.print(":");
      if(RTC_TimeStruct.Minutes< 10) file.print("0");
      file.print(RTC_TimeStruct.Minutes);
      file.print(",");
      file.print(tmp);
      file.print(",");    
      file.print(hum);
      file.print(",");
      file.print(pressure);
      file.print(",");       
      file.print(lux);
      file.print(",");
      file.print(sgp.TVOC);
      file.print(",");       
      file.print(sgp.eCO2);
      file.print("\n");
      file.close();
    }
  }
}
3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3