Arduino で気圧をSDカードに保存して、Webからグラフを閲覧する

Arduino で気圧をSDカードに保存して、Webからグラフを閲覧します。

まだ書きかけ中ですが。
たぶん、ESP32で書いたほうがいいかもです。

````c:pressureGraph.ino
/*
  Web Server

 A simple web server that shows the value of the analog input pins.
 using an Arduino Wiznet Ethernet shield.

 Circuit:
 * Ethernet shield attached to pins 10, 11, 12, 13
 * Analog inputs attached to pins A0 through A5 (optional)

 created 18 Dec 2009
 by David A. Mellis
 modified 9 Apr 2012
 by Tom Igoe
 modified 02 Sept 2015
 by Arturo Guadalupi
 
 */
#include <Wire.h>

// setting bmp180 ( pressure sensor )
#include <SFE_BMP180.h>
SFE_BMP180 bmp180; // SDA:A4 SDL:A5

// setting sd
#include <SD.h>
File myFile;

// setting date pin
#define CLK_PIN 8  // CLK:8番ピン
#define DAT_PIN 9  // DAT:9番ピン
#define RST_PIN 10 // RST:10番ピン

// setting date format
struct DateTime{

  boolean CH; //1でClockHalt(停止)だが、0を入れてこの機能使わない前提
  boolean Mode12; //1で12時間表示だが、0を入れて24時間表示で使う前提
  boolean WP; //1でWriteProtectだが0を入れてこの機能使わない前提

  int Date;
  int Month;
  int Week;
  int Year;
  int Seconds;
  int Minutes;
  int Hour;

};

// setting ethernet
#include <SPI.h>
#include <Ethernet.h>
byte mac[] = {
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};
IPAddress ip(192, 168, 0, 177);
EthernetServer server(80);
IPAddress myDns(192, 168, 0, 1);                        

void setup() {

  // setting serial band
  Serial.begin(9600);

  while (!Serial) {
  }
  //Serial.println("Serial init success");

  // setting ethernet
  Ethernet.begin(mac, ip , myDns );
  if (Ethernet.hardwareStatus() == EthernetNoHardware) {
    Serial.println("Ethernet shield was not found.  Sorry, can't run without hardware. :(");
    while (true) {
      delay(1); // do nothing, no point running without Ethernet hardware
    }
  }
  if (Ethernet.linkStatus() == LinkOFF) {
    //Serial.println("Ethernet cable is not connected.");
  }
  Serial.println("Ethernet init success");

  // start the server
  server.begin();
  //Serial.println(Ethernet.localIP());

  // setting bmp180 ( pressure sensor )
  bool success = bmp180.begin();
  if (success) {
    //Serial.println("BMP180 init success");
  }

  // setting sd card
  if (!SD.begin(4)) {
    while (1);
  }
  //Serial.println("SD init success");

}

void loop() {

  Serial.println("loop init success");

  // web server
  EthernetClient client = server.available();
  if (client) {

    Serial.println("client init success");

    boolean currentLineIsBlank = true;

    while (client.connected()) {
      if (client.available()) {

        char c = client.read();
        Serial.write(c);

        if (c == '\n' && currentLineIsBlank) {

          Serial.println("html init success");
          
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");
          client.println("Refresh: 5");
          client.println();
          client.println("<!DOCTYPE HTML>");
          client.println("<html>");

          //
          myFile = SD.open("test.txt");
          if (myFile) {
            while (myFile.available()) {
              client.print(myFile.read());
              client.println("<br/>");
            }
            // ここにグラフを書く
            //client.println("<td><img src=\"https://chart.googleapis.com/chart?chs=100x60&amp;cht=gom&amp;chd=t:"+ String( int(  digitalRead(i) * 100 ) ) +"&amp;chco=FFFFFF,000000\"></td>");
            myFile.close();
          }

          client.println("</html>");
          break;

        }

        if (c == '\n') {
          // you're starting a new line
          currentLineIsBlank = true;
        } else if (c != '\r') {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }

      }

    }

    // give the web browser time to receive the data
    delay(1);

    // close the connection:
    client.stop();

  }

  // time  
  byte RTC_clock_image[8];
  DateTime myDateTime;
  read_rtc_byte(RTC_clock_image);
  extract_datetime(RTC_clock_image,myDateTime);
  //yyyy-mm-dd hh:ss:ii week
  /*
  Serial.print(myDateTime.Year);    Serial.print("-");
  Serial.print(myDateTime.Month);   Serial.print("-");
  Serial.print(myDateTime.Date);    Serial.print(" ");
  Serial.print(myDateTime.Hour);    Serial.print(":");
  Serial.print(myDateTime.Minutes); Serial.print(":");
  Serial.print(myDateTime.Seconds); Serial.print("(");
  Serial.print(myDateTime.Week);    Serial.println(")");
  */

  // pressure
  char status;
  double T, P;
  bool success = false;
  status = bmp180.startTemperature();
  //Serial.println("bmp189 init");
  if (status != 0) {

    //Serial.println("bmp189 init success");
    delay(1000);

    status = bmp180.getTemperature(T);

    if (status != 0) {
      status = bmp180.startPressure(3);
      //Serial.println("bmp189 startPressure init");

      if (status != 0) {
        delay(status);
        status = bmp180.getPressure(P, T);

        if (status != 0) {

          //Serial.println("bmp189 startPressure get success");
          /*
          Serial.print("Pressure: ");
          Serial.print(P);
          Serial.println(" hPa");

          Serial.print("Temperature: ");
          Serial.print(T);
          Serial.println(" C");
          */

          // sd card write
          
          myFile = SD.open("test.txt", FILE_WRITE);
          if (myFile) {

            Serial.println("sd open success");

            myFile.print(myDateTime.Year);    myFile.print("-");
            myFile.print(myDateTime.Month);   myFile.print("-");
            myFile.print(myDateTime.Date);    myFile.print(" ");
            myFile.print(myDateTime.Hour);    myFile.print(":");
            myFile.print(myDateTime.Minutes); myFile.print(":");
            //myFile.print(myDateTime.Seconds); myFile.print("(");
            //myFile.print(myDateTime.Week);    myFile.print(")");

            myFile.print(" ");
            myFile.print(P);
            myFile.print(" ");
            myFile.println(T);

            myFile.close();
          
          }


        }

      }

    }

  }
  
}

// ========================================================================
// set read date functions 
// ========================================================================

//RTCからクロックデータをまるごと読みだし、
byte read_rtc_byte(byte image[]){

  pinMode(DAT_PIN, OUTPUT);//DAT_PINのpinmodeをまず送信用で準備
  digitalWrite(RST_PIN, LOW);wait();//最初はRST_PIN下げた状態
  digitalWrite(RST_PIN, HIGH);wait();//開始（RST_PIN 上げ）
  write_1byte(0xbf);//バーストモードのコマンド0xbf送信

  //読み出しに移るのでDAT_PINのピンモード切り替える。CLK_PIN上げのまま
  pinMode(DAT_PIN, INPUT);

  //8byte分続けて読みbyte配列のimageに入れる
  for (int i=0; i<=7; i++){
  read_1byte(image[i]);

  }

  //RST_PIN下げる
  digitalWrite(RST_PIN, LOW); wait(); 

}
void write_1byte(byte data){

  //コマンド等送信　1ビットずつ繰り返し8ビット（1バイト）分送る
  for (int i=0; i <= 7; i++){

    digitalWrite(CLK_PIN, LOW);wait();  //LOW確認
    digitalWrite( DAT_PIN, bitRead(data, i));wait();
    digitalWrite(CLK_PIN, HIGH);wait();  //クロック（LOWからHIGH）で書き込む
    //クロック上げたままで関数を抜ける。

  }  

}
void read_1byte(byte &data){

  //データ受信　1ビットずつ繰り返し8ビット（1バイト）分読みだす
  data = 0;
  for (int i=0; i<=7; i++){ 
    digitalWrite(CLK_PIN, HIGH);wait();//clock上げ。（上げたまま引き継いだ時はそのまま）
    digitalWrite(CLK_PIN, LOW);wait();//clock下げて、
    bitWrite( data,i, digitalRead(DAT_PIN));//読む

    //クロック下げた状態で関数を抜ける
  }  

}
void setImage(byte command, byte image){ //コマンド、書き込みデータ

  pinMode(DAT_PIN, OUTPUT);//DAT_PINのpinmodeを送信用で準備
  digitalWrite(RST_PIN, LOW);wait();//最初はRST_PIN下げた状態
  digitalWrite(RST_PIN, HIGH);wait();//開始（RST_PIN 上げ）
  write_1byte(command);
  write_1byte(image); 
  digitalWrite(CLK_PIN, LOW);wait();//clock下げて、 
  digitalWrite(RST_PIN, LOW);wait();//最後はRST_PIN下げる

}
void getImage(byte command, byte &image){

  pinMode(DAT_PIN, OUTPUT);//DAT_PINのpinmodeを送信用で準備
  digitalWrite(RST_PIN, LOW);wait();//最初はRST_PIN下げた状態
  digitalWrite(RST_PIN, HIGH);wait();//開始（RST_PIN 上げ）
  write_1byte(command);
  pinMode(DAT_PIN, INPUT);//DAT_PINのpinmodeを受信用に切り替え
  read_1byte(image); 
  digitalWrite(RST_PIN, LOW);wait();//最後はRST_PIN下げる  

}
void wait(){

  //Vcc5Vなのでデータシート11ページから待ち時間は1μ秒分とっておけばよい。
  delayMicroseconds(1);

}

//byte配列からの情報抽出
void extract_datetime(byte image[], DateTime &TempDateTime){

  int data10, data1;

  //秒
  data10 = (image[0]>>4)&7; //上位4ビットを0111でマスクする。
  data1 = image[0] & 15; //下位4ビットを1111でマスクする。
  TempDateTime.Seconds =  (data10 * 10) + data1;
  TempDateTime.CH = image[0]>>7;

  //分
  data10 = (image[1]>>4)&7; //上位4ビットを0111でマスクする。
  data1 = image[1] & 15; //下位4ビットを1111でマスクする。
  TempDateTime.Minutes =  (data10 * 10) + data1; 

  //時
  data10 = (image[2]>>4)&3; //上位4ビットを0011でマスクする。
  data1 = image[2] & 15; //下位4ビットを1111でマスクする。
  TempDateTime.Hour =  (data10 * 10) + data1; 
  TempDateTime.Mode12 = image[2]>>7; //12時間表示モード。0にして使わない。

  //日
  data10 = (image[3]>>4)&3; //上位4ビットを0011でマスクする。
  data1 = image[3] & 15; //下位4ビットを1111でマスクする。
  TempDateTime.Date =  (data10 * 10) + data1; 

  //月
  data10 = (image[4]>>4)&1; //上位4ビットを0001でマスクする。
  data1 = image[4] & 15; //下位4ビットを1111でマスクする。
  TempDateTime.Month =  (data10 * 10) + data1; 

  //曜日
  TempDateTime.Week =image[5];

  //年
  data10 = (image[6]>>4) & 15; //上位4ビットを1111でマスクする。
  data1 = image[6] & 15; //下位4ビットを1111でマスクする。
  TempDateTime.Year =  (data10 * 10) + data1 + 2000; 

  //WP
  TempDateTime.WP =image[7]>>7; 

}

// ========================================================================
// set yyyy m d h s i
// ========================================================================

void setYear(int year){ // (ex. 2020
  setImage(0x8C, (((year - 2000)/10)<<4)+(year % 10));
}
void setWeek(byte Week){ // 1:月 2:火 3:水 4:木 5:金 6:土 7:日
  setImage(0x8A, Week);
}
void setMonth(int month){ // 1 - 12
  setImage(0x88,((month/10)<<4)+(month % 10));
}
void setDate(int date){
  setImage(0x86,((date/10)<<4)+(date % 10));
}
void setHour(int hour){ // 0 - 23
  setImage(0x84,((hour/10)<<4)+(hour % 10));
}
void setMinutes(int minutes){
  setImage(0x82,((minutes/10)<<4)+(minutes % 10));  
}
void setSeconds(int seconds){
  setImage(0x80,((seconds/10)<<4)+(seconds % 10));  
}
~~~~