ベッドサイドLED時計 TFT表示温度気圧計付き

#はじめに
MAX7219を使用したLEDモジュールを使ってベッドサイド用時計を作りました。余ったプログラム領域を利用して温度気圧センサーBME280にて測定したデータを24時間推移表示してみました。気圧はローソク表示にしています。

##時計表示
日付と時刻を1桁離したかったため、月表示だけが16進表示になっています。
最低輝度でも夜中は明るすぎるため、黒いフィルムを貼っています。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/211703/5fc4c9fc-a83f-1b84-5a46-aac57095fa4c.png)

##気温気圧表示
24時間の推移表示をします。時計の時刻合せもこちらで行います。
こちらもフィルムを貼っています。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/211703/e5fd7c96-cd0f-b9e1-a44e-030fad801149.png)

##箱の内部
時刻合せタクトスイッチとI2C用のコネクタはProto Shield上の実装しましたが、その他はジャンパーケーブルでお手軽配線しています。RTCのDS1302も実装していますが使用していません。
これでも1年半問題無く動作しています。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/211703/eff1a679-1b76-4ae1-ad60-9d1969bef319.png)

#用意するもの
##Arduino Uno
互換を使用しました。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/211703/30f2e382-286f-2f6d-3842-3e15245ed6e2.png)

##Proto Sheild
![image.png](https://qiita-image-store.s3.amazonaws.com/0/211703/7c086869-9d6f-d6b4-98aa-136e97e60420.png)

##DS3231
I2Cで通信するRTCモジュールです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/211703/1980734b-6e0f-e1ef-4a14-6980db8deb90.png)

##TFT
ST7735を使用したSPI通信で動作する160x128TFTモジュールです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/211703/23922ec6-8a1d-8981-804f-9131b7cb1d67.png)

##LED
MAX7219を使用したSPI通信を行う8桁のLEDモジュールです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/211703/0349a829-d4e2-83eb-c219-4af394e86483.png)

##温度、気圧センサ
BoschのBMP280を使用した温度気圧センサーです。I2Cで通信しています。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/211703/cf7fe005-4b58-8c24-8561-d63c00362449.png)

#結線

```C:Connect
///////////////////////////////////////////////////////////////////////
// TFT Module 160x128
// 信号インターフェース：シリアル、内蔵コントローラチップST7735R
//
// 1  VCC  --  5V
// 2  GND  --  GND
// 3  GND
// 4  NC
// 5  NC
// 6  NC
// 7  CLK  -- Pin 13
// 8  SDA  -- Pin 11
// 9  RS   -- Pin 09
// 10 RST  -- Pin 08
// 11 CS   -- Pin 10
//
///////////////////////////////////////////////////////////////////////
// RTC Module DS3231
//
// 1  32K
// 2  SQW
// 3  SCL  -- Pin A5
// 4  SDA  -- Pin A4
// 5  VCC
// 6  GND
///////////////////////////////////////////////////////////////////////
// LED Module MAX7219
//
// 1  VCC
// 2  GND
// 3  DIN  -- Pin 7
// 4  LOAD -- Pin 6
// 5  CLK  -- Pin 5
///////////////////////////////////////////////////////////////////////
// SWITCH
//
//   SET  -- Pin 0
//   +SW  -- Pin 1
//   -SW  -- Pin 2
///////////////////////////////////////////////////////
// BMP280 - I2C
//
// VCC : 3.3V
// GND : GND
// SDA : A4
// SCL : A5
//
```

#プログラム

```C:Clock.cpp
#include <stdint.h>
#include "Wire.h"

#include <LiquidCrystal.h>
#include <Time.h>         //http://www.arduino.cc/playground/Code/Time  
#include <TimeLib.h>
#include <DS3232RTC.h>    //http://github.com/JChristensen/DS3232RTC

// 20170609 時計合わせ時の消去処理を修正

///////////////////////////////////////////////////////////////////////
// TFT Module 160x128
// 信号インターフェース：シリアル、内蔵コントローラチップST7735R
//
// 1  VCC  --  5V
// 2  GND  --  GND
// 3  GND
// 4  NC
// 5  NC
// 6  NC
// 7  CLK  -- Pin 13
// 8  SDA  -- Pin 11
// 9  RS   -- Pin 09
// 10 RST  -- Pin 08
// 11 CS   -- Pin 10

#include <TFT.h>
#include <SPI.h>

#define cs   10
#define dc   9
#define rst  8
//13  scl
//11 to sda
TFT TFTscreen = TFT(cs, dc, rst);


// initialize the library with the numbers of the interface pins
//LiquidCrystal  (RS, EN, D4, D5, D6, D7);
//LiquidCrystal lcd(11, 10, 9, 8, 7, 6);

///////////////////////////////////////////////////////
// BMP280 - I2C
//
// VCC : 3.3V
// GND : GND
// SDA : A4
// SCL : A5
//
///////////////////////////////////////////////////////////////////////
// LED Module MAX7219
//
// 1  VCC
// 2  GND
// 3  DIN  -- Pin 7
// 4  LOAD -- Pin 6
// 5  CLK  -- Pin 5
///////////////////////////////////////////////////////////////////////
#include "LedControl.h"     // 8 digit
LedControl lc = LedControl(7, 5, 6, 1);

///////////////////////////////////////////////////////////////////////
// SWITCH
//
//   SET  -- Pin 0
//   +SW  -- Pin 1
//   -SW  -- Pin 2
///////////////////////////////////////////////////////////////////////
#include "MsTimer2.h"          // For switch reading

volatile boolean b_sw0_stat = HIGH;
volatile boolean b_sw1_stat = HIGH;
volatile boolean b_sw2_stat = HIGH;
int setup_stat = 0;   // 0: Normal mode, 1: hour 2: min, 3, year, 4, mon, 5, day
int setup_stat_old = 0;   // 0: Normal mode, 1: hour 2: min, 3, year, 4, mon, 5, day


char old_timetext[6];
char old_daytext[20];
int old_min = -1;
int old_hor = -1;
int old_day = -1;
int old_min_led = -1;
int old_hor_led = -1;
int old_day_led = -1;
volatile int selsts = 0;  // SEL key status 0:normal 1:hour 2:min 3:Day 4 Mon, 5 Year

int old_PrehPa = -1;
int now_PrehPa = -1;
int PrehPa[24];  // Pressure strage
int PrehPaST[24];  // Pressure strage
int PrehPaED[24];  // Pressure strage
int PrehPaH[24];  // Pressure strage
int PrehPaL[24];  // Pressure strage
//// Dummy data
//int  PrehPa[24] = {1020, 1021, 1013, 1004, 1002, 1009, 1018, 1021, 1016, 1006, 1002, 1006, 1016, 1021, 1018, 1009, 1002, 1004, 1013, 1021, 1020, 1011, 1003, 1002 };
//int  PrehPaST[24] = { 1020, 1021, 1015, 1009, 1008, 1013, 1019, 1021, 1017, 1011, 1008, 1011, 1017, 1021, 1019, 1012, 1008, 1009, 1016, 1021, 1020, 1014, 1009, 1008 };
//int  PrehPaED[24] = { 1019, 1020, 1010, 999, 996, 1005, 1017, 1021, 1014, 1001, 996, 1002, 1014, 1021, 1017, 1005, 996, 999, 1010, 1020, 1019, 1008, 997, 997 };
//int  PrehPaH[24] = { 1021, 1021, 1017, 1013, 1012, 1015, 1020, 1021, 1019, 1014, 1012, 1014, 1019, 1021, 1020, 1015, 1012, 1013, 1017, 1021, 1021, 1016, 1012, 1012 };
//int  PrehPaL[24] = { 1019, 1020, 1009, 995, 992, 1002, 1016, 1021, 1013, 998, 992, 998, 1013, 1021, 1016, 1002, 992, 995, 1009, 1020, 1019, 1006, 994, 993 };


int now_TempTrend = -1;  // Pressure strage
int old_TempTrend = -1;  // Pressure strage
int TempTrend[24];  // Pressure strage
int TempTrendST[24];  // Pressure strage
int TempTrendED[24];  // Pressure strage
int TempTrendH[24];  // Pressure strage
int TempTrendL[24];  // Pressure strage
// Dummy data
//int  TempTrend[24] = {332, 335, 297, 252, 242, 276, 322, 339, 310, 262, 240, 263, 311, 339, 322, 275, 241, 252, 297, 335, 331, 289, 247, 244 };
//int  TempTrendST[24] = {335, 337, 314, 287, 281, 301, 329, 339, 322, 293, 280, 293, 322, 339, 329, 301, 281, 287, 314, 337, 335, 309, 284, 282 };
//int  TempTrendED[24] = {328, 333, 279, 217, 202, 250, 315, 339, 298, 231, 200, 232, 299, 339, 315, 249, 202, 217, 280, 333, 328, 269, 210, 206 };
//int  TempTrendH[24] = {336, 338, 322, 304, 300, 314, 333, 339, 328, 309, 300, 309, 328, 339, 333, 314, 300, 304, 322, 338, 336, 319, 303, 301 };
//int  TempTrendL[24] = {327, 332, 271, 199, 183, 237, 312, 339, 292, 216, 180, 217, 293, 339, 312, 236, 183, 199, 271, 333, 326, 259, 192, 187 };

class i2c_support
{
  private:
    byte i2c_address;
  public:
    i2c_support(byte address) {
      i2c_address = address;
      Wire.begin();
    }
    // read 8bit data from pointer.
    uint8_t i2c_read8(byte pointer) {
      Wire.beginTransmission(i2c_address);
      Wire.write(pointer);
      Wire.endTransmission();
      Wire.requestFrom(i2c_address,  (byte)1);
      return (uint8_t)Wire.read();
    }
    // read 16bit data from addr/pointer. 1st MSB, 2nd LSB.
    uint16_t i2c_read16(byte pointer) {
      Wire.beginTransmission(i2c_address);
      Wire.write(pointer);
      Wire.endTransmission();
      Wire.requestFrom(i2c_address,  (byte)2);
      unsigned short data = Wire.read();
      data <<= 8;
      data |= Wire.read();
      return data;
    }
    // read 16bit data from addr/pointer. 1st LSB, 2ns MSB.
    uint16_t i2c_read16_swab(byte pointer) {
      Wire.beginTransmission(i2c_address);
      Wire.write(pointer);
      Wire.endTransmission();
      Wire.requestFrom(i2c_address,  (byte)2);
      uint16_t lsb = (uint16_t)Wire.read();
      uint16_t msb = (uint16_t)(Wire.read() << 8);
      return msb | lsb;
    }

    // for HDC1000
    uint32_t i2c_read32(byte pointer, int delay_ms = 0) {
      Wire.beginTransmission(i2c_address);
      Wire.write(pointer);  // このタイミングでA/D変換が開始する。
      Wire.endTransmission();
      delay(delay_ms);
      Wire.requestFrom(i2c_address,  (byte)4);
      unsigned int data = Wire.read();
      data <<= 8;
      data |= Wire.read();
      data <<= 8;
      data |= Wire.read();
      data <<= 8;
      data |= Wire.read();
      return data;
    }

    void i2c_read_burst(byte pointer, int byte_count, byte* p) {
      Wire.beginTransmission(i2c_address);
      Wire.write(pointer);
      Wire.endTransmission();
      Wire.requestFrom(i2c_address,  (byte)byte_count);
      while (Wire.available() && byte_count > 0) {
        *p++ = (byte)Wire.read();
        byte_count--;
      }
    }

    void i2c_write_reg(byte reg, byte data) {
      Wire.beginTransmission(i2c_address);
      Wire.write(reg);
      Wire.write(data);
      Wire.endTransmission();
    }
};

class hdc1000 : public i2c_support
{
  public:
    hdc1000() : i2c_support(0x40) {
      temp = 0.0;
      humi = 0.0;
    }
    enum { reg_measure = 0, reg_config = 2, reg_id = 0xff };

    bool init() {
      i2c_write_reg(reg_config, 0x90);  // 10000001B = RESET, 32bit MODE(temp << 16 + humi)
      return (i2c_read16(reg_id) == 0x1000); // check device id.
    }
    void measure() {
      uint32_t data = i2c_read32(reg_measure, 15);
      temp = (float)((data >> 16) / 65536.0) * 165.0 - 40.0;
      humi = (float)((data & 0xffff) / 65536.0) * 100.0;
    }
    float temp;
    float humi;
};

#ifndef BME280_S32_t
#define BME280_S32_t  int32_t
#endif
#ifndef BME280_U32_t
#define BME280_U32_t  uint32_t
#endif
#ifndef BME280_S64_t
#define BME280_S64_t  int64_t
#endif

class bme280 : public i2c_support
{
    bool bme280_flag;  // true : bme280, false: bmp280
  public:
    bme280(int address) : i2c_support(address) {
      temp = 0.0;
      humi = 0.0;
      press = 0.0;
    }
    // results.
    float temp;
    float humi;
    float press;
    enum { Tmeasure = 10 };  // oversamplinkg, x1 x1 x1
    /// registers.
    enum { reg_id = 0xd0, reg_reset = 0xe0, reg_ctrl_hum = 0xf2, reg_ctrl_meas = 0xf4, reg_config = 0xf5 };
    enum { reg_p_result = 0xf7, reg_t_result = 0xfa, reg_h_result = 0xfd };

    // IIR Filter disable.
    bool init() {
      uint8_t id = i2c_read8(reg_id); // check device-id.
      if (id == 0x60)
        bme280_flag = true;
      else if (id == 0x58)
        bme280_flag = false;
      else
        return false;

      load_bme280_compensation_params();
      i2c_write_reg(reg_config, 0); //  no stand-by, no IIR filter, no SPI.
      return true;
    }

    //  TEMP resolution = 16 + (osrs_t ? 1) bit, HUM resolution = 16 + (osrs_h ? 1) bit,
    //  select forced mode.
    void measure()  {
      if (bme280_flag)
        i2c_write_reg(reg_ctrl_hum, 1);   // humi measurement control register.00000011  (osrs_h = 1);
      i2c_write_reg(reg_ctrl_meas, 0x25); // measurement control register. 00100101 (osrs_p = 1, osrs_t = 1, Forced mode);
      delay(Tmeasure);
      byte buffer[10];
      memset(buffer, 0, sizeof(buffer));
      i2c_read_burst(reg_p_result, 8, buffer);
      uint32_t raw_press = ((uint32_t)buffer[0] << 12) | ((uint32_t)buffer[1] << 4) | (((uint32_t)buffer[2] >> 4) & 0xf);
      uint32_t raw_temp = ((uint32_t)buffer[3] << 12) | ((uint32_t)buffer[4] << 4) | (((uint32_t)buffer[5] >> 4) & 0xf);
      uint16_t raw_humi = ((uint16_t)buffer[6] << 8) | (uint16_t)buffer[7];
      // uint16_t raw_humi = i2c_read16(reg_h_result);
#if 0
      Serial.print("raw_press = ");
      Serial.println(raw_press, HEX);
      Serial.print("raw_temp = ");
      Serial.println(raw_temp, HEX);
      Serial.print("raw_humi = ");
      Serial.println(raw_humi, HEX);
#endif
      temp = BME280_compensate_T_int32(raw_temp) / 100.0;
      press = BME280_compensate_P_int64(raw_press) / 25600.0;
      if (bme280_flag)
        humi = bme280_compensate_H_int32(raw_humi) / 1024.0;
      // reset.
      //  i2c_write_reg(reg_reset, 0xb6);
    }

    // from BST-BME280_DS001-10.pdf Chapter4.2.3 (rev.1.1)
  private:
    BME280_S32_t t_fine;

    // Returns temperature in DegC, resolution is 0.01 DegC. Output value of “5123” equals 51.23 DegC.
    // t_fine carries fine temperature as global value
    BME280_S32_t BME280_compensate_T_int32(BME280_S32_t adc_T) {
      BME280_S32_t var1, var2, T;
      var1 = ((((adc_T >> 3) - ((BME280_S32_t)dig_T1 << 1))) * ((BME280_S32_t)dig_T2)) >> 11;
      var2 = (((((adc_T >> 4) - ((BME280_S32_t)dig_T1)) * ((adc_T >> 4) - ((BME280_S32_t)dig_T1))) >> 12) * ((BME280_S32_t)dig_T3)) >> 14;
      t_fine = var1 + var2;
      T = (t_fine * 5 + 128) >> 8;
      return T;
    }

    // Returns pressure in Pa as unsigned 32 bit integer in Q24.8 format (24 integer bits and 8 fractional bits).
    // Output value of “24674867” represents 24674867/256 = 96386.2 Pa = 963.862 hPa
    BME280_U32_t BME280_compensate_P_int64(BME280_S32_t adc_P)  {
      BME280_S64_t var1, var2, p;
      var1 = ((BME280_S64_t)t_fine) - 128000;
      var2 = var1 * var1 * (BME280_S64_t)dig_P6;
      var2 = var2 + ((var1 * (BME280_S64_t)dig_P5) << 17);
      var2 = var2 + (((BME280_S64_t)dig_P4) << 35);
      var1 = ((var1 * var1 * (BME280_S64_t)dig_P3) >> 8) + ((var1 * (BME280_S64_t)dig_P2) << 12);
      var1 = (((((BME280_S64_t)1) << 47) + var1)) * ((BME280_S64_t)dig_P1) >> 33;
      if (var1 == 0) {
        return 0; // avoid exception caused by division by zero
      }
      p = 1048576 - adc_P;
      p = (((p << 31) - var2) * 3125) / var1;
      var1 = (((BME280_S64_t)dig_P9) * (p >> 13) * (p >> 13)) >> 25;
      var2 = (((BME280_S64_t)dig_P8) * p) >> 19;
      p = ((p + var1 + var2) >> 8) + (((BME280_S64_t)dig_P7) << 4);
      return (BME280_U32_t)p;
    }

    // Returns humidity in %RH as unsigned 32 bit integer in Q22.10 format (22 integer and 10 fractional bits).
    // Output value of “47445” represents 47445/1024 = 46.333 %RH
    BME280_U32_t bme280_compensate_H_int32(BME280_S32_t adc_H)  {
      BME280_S32_t v_x1_u32r;

      v_x1_u32r = (t_fine - ((BME280_S32_t)76800));
      v_x1_u32r = (((((adc_H << 14) - (((BME280_S32_t)dig_H4) << 20) - (((BME280_S32_t)dig_H5) * v_x1_u32r)) +
                     ((BME280_S32_t)16384)) >> 15) * (((((((v_x1_u32r * ((BME280_S32_t)dig_H6)) >> 10) * (((v_x1_u32r *
                         ((BME280_S32_t)dig_H3)) >> 11) + ((BME280_S32_t)32768))) >> 10) + ((BME280_S32_t)2097152)) *
                         ((BME280_S32_t)dig_H2) + 8192) >> 14));
      v_x1_u32r = (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) * ((BME280_S32_t)dig_H1)) >> 4));
      v_x1_u32r = (v_x1_u32r < 0 ? 0 : v_x1_u32r);
      v_x1_u32r = (v_x1_u32r > 419430400 ? 419430400 : v_x1_u32r);
      return (BME280_U32_t)(v_x1_u32r >> 12);
    }

    // Chapter4.2.2. Trimming parameters.
    uint16_t  dig_T1;
    int16_t dig_T2;
    int16_t dig_T3;

    uint16_t  dig_P1;
    int16_t dig_P2;
    int16_t dig_P3;
    int16_t dig_P4;
    int16_t dig_P5;
    int16_t dig_P6;
    int16_t dig_P7;
    int16_t dig_P8;
    int16_t dig_P9;

    uint8_t dig_H1;
    int16_t dig_H2;
    uint8_t dig_H3;
    int16_t dig_H4;
    int16_t dig_H5;
    uint8_t dig_H6;

    void load_bme280_compensation_params() {
      dig_T1 = i2c_read16_swab(0x88);
      dig_T2 = (int16_t)i2c_read16_swab( 0x8a);
      dig_T3 = (int16_t)i2c_read16_swab(0x8c);

      dig_P1 = i2c_read16_swab(0x8e);
      dig_P2 = (int16_t)i2c_read16_swab(0x90);
      dig_P3 = (int16_t)i2c_read16_swab(0x92);
      dig_P4 = (int16_t)i2c_read16_swab(0x94);
      dig_P5 = (int16_t)i2c_read16_swab(0x96);
      dig_P6 = (int16_t)i2c_read16_swab(0x98);
      dig_P7 = (int16_t)i2c_read16_swab(0x9a);
      dig_P8 = (int16_t)i2c_read16_swab(0x9c);
      dig_P9 = (int16_t)i2c_read16_swab(0x9e);

      if (bme280_flag) {
        dig_H1 = i2c_read8(0xa1);
        dig_H2 = (int16_t)i2c_read16_swab(0xe1);
        dig_H3 = i2c_read8(0xe3);
        uint16_t _e4 = (uint16_t)i2c_read8(0xe4);
        uint16_t _e5 = (uint16_t)i2c_read8(0xe5);
        uint16_t _e6 = (uint16_t)i2c_read8(0xe6);
        dig_H4 = (int16_t)((_e4 << 4) + (_e5 & 0xf));
        dig_H5 = (int16_t)((_e6 << 4) + ((_e5 >> 4) & 0xf));
        dig_H6 = (int16_t)i2c_read8(0xe7);
      }
    }
};

#define START_MSG "\n" + String(__FILE__) + " start."
#define LED1 15
#define MEASURE_INTERVAL_SECONDS  300

bme280 bmp280(0x76);



void die(int msec, const char* cp) {
  digitalWrite(LED1, 1);
  delay(1000);
  digitalWrite(LED1, 0);
  delay(1000);
}

void setup() {
  Serial.begin(115200);
  Serial.println(START_MSG);
  delay(50);
  // RTC
  setSyncProvider(RTC.get);   // the function to get the time from the RTC
  if (timeStatus() != timeSet)
    Serial.println("Unable to sync with the RTC");
  else
    Serial.println("RTC has set the system time");

  // Time set TEST
  //setTime(hr, min, sec, day, month, yr);
  //   setTime(12, 46, 00, 27, 05, 2017);
  //  RTC.set(now());

  // set up the LCD's number of columns and rows:
  //  lcd.begin(16, 2);
  //  // Print a message to the LCD.
  //  lcd.print("hello, world!");

  pinMode(0, INPUT_PULLUP);   // SETUP
  pinMode(1, INPUT_PULLUP);   // + SW
  pinMode(2, INPUT_PULLUP);   // - SW
  
  pinMode(LED1, OUTPUT);
  digitalWrite(LED1, 1);
  if (!bmp280.init())
    die(500, "FATAL: BMP280 init failed.");

  TFTscreen.begin();
  TFTscreen.background(0, 0, 0);

    //  // 変数初期化
    for (int i = 0; i < 24 ; i++)
    {
      PrehPa[i] = -1;  // Pressure storage (Current)
      PrehPaST[i] = -1;  // Pressure storage (Start point)
      PrehPaED[i] = -1;  // Pressure storage (End point)
      PrehPaH[i] = -1;  // Pressure storage (Highest value)
      PrehPaL[i] = 9999;  // Pressure storage (Lowest value)
      TempTrend[i] = -1;  // Temperature storage (Current)
      TempTrendST[i] = -1;  // Temperature storage (Start point)
      TempTrendED[i] = -1;  // Temperature storage (End point)
      TempTrendH[i] = -1;  // Temperature storage (Highest value)
      TempTrendL[i] = 9999;  // Temperature storage (Lowest value)
    }
  /*
    The MAX72XX is in power-saving mode on startup,
    we have to do a wakeup call
  */
  lc.shutdown(0, false);
  /* Set the brightness to a medium values */
  lc.setIntensity(0, 0);
  /* and clear the display */
  lc.clearDisplay(0);

  MsTimer2::set(100, SwitchCheck);     // 500ms毎にSwitchCheck( )割込み関数を呼び出す様に設定
  MsTimer2::start();             // タイマー割り込み開始

}

void loop() {
  String disp;
  static int looptime = 0;
//  bmp280.measure();
  // set the cursor to column 0, line 1
  // (note: line 1 is the second row, since counting begins with 0):
  //  lcd.setCursor(0, 0);
  //  disp = "Prs: ";
  //  disp += String(bmp280.press);
  //  disp += " hPa";
  //  lcd.print(disp);
  //  lcd.setCursor(0, 1);
  //  disp = "Tmp:   ";
  //  disp += String(bmp280.temp);
  //  disp += " ";
  //  disp += char(0xDF); // degC
  //  disp += "C";
  //  lcd.print(disp);


  looptime++;   //   delay(1000);
  if( looptime > 20 && !setup_stat )   // same as delay(1000) && 時計調整中じゃない
  {
      bmp280.measure();
        Serial.println("\nPa = " + String(bmp280.press) + ", Temp = " + String(bmp280.temp) );
      debug_output();
      //  storeData();
      UpdateLedDisp(false);     // LED 8digit
      UpdateTimeDateTftDisp();  // 時間表時
      UpdatePressChart();       // 気圧チャート
      UpdateTempChart();       // 気温チャート
      storeData();
      looptime = 0;
  }
  // SETUP
  if ( LOW == b_sw0_stat ) // SETUPがACTIVEなら
  {
    setup_stat_old = setup_stat ;
    setup_stat ++;
    if ( setup_stat >= 6 )
      setup_stat = 0;
      UpdateTimeDateTftDisp();  // 時間表時
  }
  // Adjust
  if ( setup_stat )
  {
    int inc = 0;
    if ( LOW == b_sw1_stat && LOW == b_sw2_stat ) //同時おし
      ;   // なにもしない
    else if ( LOW == b_sw1_stat )
      inc = 1;
    else if ( LOW == b_sw2_stat )
      inc = -1;
    // int setup_stat = 0;   // 0: Normal mode, 1: hour 2: min, 3, year, 4, mon, 5, day,
    int yr, mn, dy, hr, mi, se;
    yr = year();
    mn = month();
    dy = day();
    hr = hour();
    mi = minute();
    se = second();
    switch ( setup_stat )
    {
      case 1:   // Hour
        hr += inc ;
        if( hr >= 24 ) hr = 0;
        if( hr < 0 ) hr = 23;
        break;
      case 2:   // min
        mi += inc ;
        if( inc )se = 0;  // 秒をリセット　2018/02/04
        if( mi >= 60 ) mi = 0;
        if( mi < 0 ) mi = 59;
        break;
      case 3:   // year
        yr += inc ;
        if( yr >= 2070 ) yr = 1971;
        if( yr < 1971 ) yr = 2070;
        break;
      case 4:   // mon
        mn += inc ;
        if( mn >= 12 ) mn = 0;
        if( mn < 0 ) mn = 11;        break;
      case 5:   // day
        dy += inc ;
        if( dy >= 32 ) dy = 0;
        if( dy < 0 ) dy = 31;        break;
        break;
      default:
        break;
    }
    //Time set 
    //setTime(hr, min, sec, day, month, yr);
    setTime(hr, mi, se, dy, mn, yr);
    RTC.set(now());
      UpdateLedDisp(false);     // LED 8digit
      UpdateTimeDateTftDisp();  // 時間表時

//    rtc.time(g_t);
//     //UpdateOledDisp();
//     UpdateLedDisp(true); // LED for 8 digt
  }

  
  delay(50);

}

void debug_output()
{
#if 0
  int i;
  Serial.println("old_PrehPa:" + String(old_PrehPa) 
                + "now_PrehPa = " + String(now_PrehPa) );
  for(i = 0; i < 24 ; i++)
    Serial.print( String(PrehPa[i]) + ", ");
  Serial.println("");
  for(i = 0; i < 24 ; i++)
    Serial.print( String(PrehPaST[i]) + ", ");
  Serial.println("");
  for(i = 0; i < 24 ; i++)
    Serial.print( String(PrehPaED[i]) + ", ");
  Serial.println("");
  for(i = 0; i < 24 ; i++)
    Serial.print( String(PrehPaH[i]) + ", ");
  Serial.println("");
  for(i = 0; i < 24 ; i++)
    Serial.print( String(PrehPaL[i]) + ", ");
  Serial.println("");
  Serial.println("old_TempTrend:" + String(old_TempTrend) 
                + "now_TempTrend = " + String(now_TempTrend) );
  for(i = 0; i < 24 ; i++)
    Serial.print( String(TempTrend[i]) + ", ");
  Serial.println("");
  for(i = 0; i < 24 ; i++)
    Serial.print( String(TempTrendST[i]) + ", ");
  Serial.println("");
  for(i = 0; i < 24 ; i++)
    Serial.print( String(TempTrendED[i]) + ", ");
  Serial.println("");
  for(i = 0; i < 24 ; i++)
    Serial.print( String(TempTrendH[i]) + ", ");
  Serial.println("");
  for(i = 0; i < 24 ; i++)
    Serial.print( String(TempTrendL[i]) + ", ");
  Serial.println("");
#endif
}
void storeData(void)
{
  int i = hour();
  PrehPa[i] = (int)bmp280.press;  // Pressure strage
  if ( PrehPaH[i] < PrehPa[i] ) PrehPaH[i] = PrehPa[i]; // High
  if ( PrehPaL[i] > PrehPa[i] ) PrehPaL[i] = PrehPa[i]; // Low


  TempTrend[i] = (int)(bmp280.temp*10.);  // Pressure strage
  if ( TempTrendH[i] < TempTrend[i] ) TempTrendH[i] = TempTrend[i]; // High
  if ( TempTrendL[i] > TempTrend[i] ) TempTrendL[i] = TempTrend[i]; // Low

}


void UpdateTimeDateTftDisp(void)
{
  char text[20];

  if ( old_hor != hour() ) // 時間開始、終了値保存
  {
    int hournow = hour();
    PrehPaST[hournow] = (int)bmp280.press;
    TempTrendST[hournow] = (int)(bmp280.temp * 10.);
    if ( hournow == 0 ) hournow = 24;
    PrehPaED[hournow - 1] = (int)bmp280.press;
    TempTrendED[hournow - 1] = (int)(bmp280.temp * 10.);
    old_hor = hour();
    old_min -= 1;   // force update
    old_day -= 1;   // force update
    old_PrehPa -= 1; // force update
    old_TempTrend -= 1; // force update
    clearDisp();
  }
  // Hour: Min
  if (old_min != minute())
  {
    TFTscreen.setTextSize(1);
    // delete
    TFTscreen.stroke(0, 0, 0);
    TFTscreen.text(old_timetext, 3, 3);
    // display
    sprintf(text, "%02d:%02d", hour(), minute());
    TFTscreen.stroke(0, 128, 0);
    TFTscreen.text(text, 3, 3);
    strcpy(old_timetext, text);
    old_min = minute(); // update the time
  }
  // Date, year
  if ( old_day != day())
  {
    // delete
    TFTscreen.stroke(0, 0, 0);
    TFTscreen.text(old_daytext, 64, 3);
    // display
    TFTscreen.setTextSize(1);
    char str_mon[4];
    char str_day[4];
    strcpy( str_mon,  monthShortStr(month()));
    strcpy( str_day, dayShortStr( weekday()));
    sprintf(text, "%02d %s %04d %s", day(), str_mon, year(), str_day );
    TFTscreen.stroke(0, 128, 0);
    TFTscreen.text(text, 64, 3);
    strcpy(old_daytext, text);

    old_day = day(); // update the time

  }
  // 時刻合わせ
  if ( 0 != setup_stat)
  {
    TFTscreen.stroke(128, 0, 0);
    const char* setupstring[] = {"HOUR", "MIN.", "YEAR", "MON.", "DAY ", "WEEK"};
    sprintf(text, "SET: %s (%02d)", setupstring[ setup_stat - 1 ],second());  // 秒を表示　2018/02/04
    TFTscreen.text(text, 32, 32);
    TFTscreen.fillRect( 32, 32, 108, 10, 0 );
  }
  else if( setup_stat == 0 && setup_stat_old != 0 )
  {
    setup_stat_old = 0;
    TFTscreen.fillRect( 32, 32, 108, 10, 0 );
  }
}


//////////////////////////////////////////////////////////////////////////////
// 気圧表示
/////////////////////////////////////////////////////////////////////////////

void UpdatePressChart(void)
{
  drawPressChartFrame();  // DrawChart Frame
  //drawPrassChart();       // Draw graph
  drawPrassChartRosoku();       // Rosoku Draw graph
  drawPresentPress();     // Draw Circle to show present
}

#define gr_TOP   70   // 15
#define gr_BTM   120
#define gr_LFT   25
#define gr_RGT   150

void drawPresentPress()
{
  now_PrehPa = (int)bmp280.press;
  if ( old_PrehPa != now_PrehPa  )
  {
    // Clear Old plot
    uint16_t col = TFTscreen.newColor(0, 0, 0);
    TFTscreen.drawCircle( GetXpos(hour()), GetYpos(old_PrehPa), 3, col);
    char text[10];
    sprintf(text, "%d", old_PrehPa);
    TFTscreen.stroke(0, 0, 0);
    TFTscreen.text(text, GetXpos(hour()), GetYpos(old_PrehPa) );
    //DIsp new
    col = TFTscreen.newColor(255, 0, 0);
    TFTscreen.drawCircle( GetXpos(hour()), GetYpos(now_PrehPa), 3, col);
    sprintf(text, "%d", now_PrehPa);
    TFTscreen.stroke(128, 128, 255);
    TFTscreen.text(text, GetXpos(hour()), GetYpos(now_PrehPa) );
    old_PrehPa = now_PrehPa;
  }
}

void drawPrassChartRosoku()
{
  int i;
  for (i = 1; i < 24; i++)
  {
    if ( PrehPa[i] == -1 || PrehPaST[i] == -1 || PrehPaED[i] == -1 || PrehPaH[i] == -1 || PrehPaH[i] == 9999  ) // no data
      continue;

    drawPrassChartRosukuSub( i,  GetYpos(PrehPaST[i]), GetYpos(PrehPaED[i]), GetYpos(PrehPaH[i]), GetYpos(PrehPaL[i]), ( PrehPaED[i - 1] > PrehPa[i]) ? 1 : 0);

  }
}
void drawPrassChart()
{
  int i;
  for (i = 1; i < 24; i++)
  {
    if ( PrehPa[i] == -1 || PrehPa[i - 1] == -1 ) // no data
      continue;
    if ( i == hour() + 1 )
      continue;
    TFTscreen.drawLine( GetXpos(i - 1), GetYpos(PrehPa[i - 1])
                        , GetXpos(i), GetYpos(PrehPa[i])
                        , TFTscreen.newColor(128, 128, 128)
                      );

  }
}

void drawPressChartFrame()
{
  // 枠をカク X:0-159, Y:0-127
  uint16_t col = TFTscreen.newColor(128, 128, 128);
  TFTscreen.drawLine( gr_LFT, gr_TOP, gr_RGT, gr_TOP, col); // 上
  TFTscreen.drawLine( gr_RGT, gr_TOP, gr_RGT, gr_BTM, col); // 右
  TFTscreen.drawLine( gr_LFT, gr_BTM, gr_RGT, gr_BTM, col); // 下
  TFTscreen.drawLine( gr_LFT, gr_TOP, gr_LFT, gr_BTM, col); // 左
  // 縦軸表示 995 - 1020hPa
  TFTscreen.setTextSize(1);
  TFTscreen.stroke(128, 128, 128);
  //  TFTscreen.text(" 995", 0, GetYpos(995) );
  TFTscreen.text("1000", 0, GetYpos(1000) );
  //  TFTscreen.text("1005", 0, GetYpos(1005) );
  TFTscreen.text("1010", 0, GetYpos(1010) );
  //  TFTscreen.text("1015", 0, GetYpos(1015) );
  TFTscreen.text("1020", 0, GetYpos(1020) );
  // 横軸表示
  int Ypos = GetYpos(995) + 1;
  TFTscreen.text("0", GetXpos(0), Ypos );
  TFTscreen.text("3", GetXpos(3), Ypos );
  TFTscreen.text("6", GetXpos(6), Ypos );
  TFTscreen.text("9", GetXpos(9), Ypos );
  TFTscreen.text("12", GetXpos(12), Ypos );
  TFTscreen.text("15", GetXpos(15), Ypos );
  TFTscreen.text("18", GetXpos(18), Ypos );
  TFTscreen.text("21", GetXpos(21), Ypos );
}
int GetYpos(int Press)
{
  return gr_BTM - ( ( Press - 995 ) * (gr_BTM - gr_TOP)) / (1020 - 995) ;
}
int GetXpos(int Hour)
{
  return gr_LFT + ( ( Hour ) * 52) / 10 ; // 5.2 = (gr_RGT-gr_LFT)/24hour
}

//////////////////////////////////////////////////////////////////////////////
// 温度表示
/////////////////////////////////////////////////////////////////////////////

#define gr_TOP_T   15
#define gr_BTM_T   65
#define gr_LFT_T   25
#define gr_RGT_T   150
void UpdateTempChart(void)
{
  drawTempChartFrame();  // DrawChart Frame
  drawTempChart();       // Draw graph
  drawPresentTemp();     // Draw Circle to show present
}

void drawPresentTemp()
{
  now_TempTrend = (int)(bmp280.temp * 10.);
  if ( old_TempTrend != now_TempTrend )
  {
    // Clear Old plot
    uint16_t col = TFTscreen.newColor(0, 0, 0);
    TFTscreen.drawCircle( GetXpos(hour()), GetYpos_t(old_TempTrend), 3, col);
    char text[10];
    sprintf(text, "%d.%d", (old_TempTrend - (old_TempTrend % 10)) / 10, old_TempTrend % 10 );
    TFTscreen.stroke(0, 0, 0);
    TFTscreen.text(text, GetXpos(hour()), GetYpos_t(old_TempTrend) );
    //DIsp new
    col = TFTscreen.newColor(255, 0, 0);
    TFTscreen.drawCircle( GetXpos(hour()), GetYpos_t(now_TempTrend), 3, col);
    sprintf(text, "%d.%d", (now_TempTrend - (now_TempTrend % 10)) / 10, now_TempTrend % 10 );
    TFTscreen.stroke(128, 128, 255);
    TFTscreen.text(text, GetXpos(hour()), GetYpos_t(now_TempTrend) );
    old_TempTrend = now_TempTrend ;
  }
}


void drawTempChart()
{
  int i;
  for (i = 1; i < 24; i++)
  {
    if ( TempTrend[i] == -1 || TempTrend[i - 1] == -1 || TempTrend[i + 1] == -1 ) // no data
      continue;
    if (  i == hour() + 1 )
      continue;
    TFTscreen.drawLine( GetXpos(i - 1), GetYpos_t(TempTrend[i - 1])
                        , GetXpos(i), GetYpos_t(TempTrend[i])
                        , TFTscreen.newColor(128, 128, 128)
                      );

  }
}

void drawTempChartFrame()
{
  // 枠をカク X:0-159, Y:0-127
  uint16_t col = TFTscreen.newColor(128, 128, 128);
  TFTscreen.drawLine( gr_LFT_T, gr_TOP_T, gr_RGT_T, gr_TOP_T, col); // 上
  TFTscreen.drawLine( gr_RGT_T, gr_TOP_T, gr_RGT_T, gr_BTM_T, col); // 右
  TFTscreen.drawLine( gr_LFT_T, gr_BTM_T, gr_RGT_T, gr_BTM_T, col); // 下
  TFTscreen.drawLine( gr_LFT_T, gr_TOP_T, gr_LFT_T, gr_BTM_T, col); // 左
  // 縦軸表示 20 - 35degC
  TFTscreen.setTextSize(1);
  TFTscreen.stroke(128, 128, 128);
  //  TFTscreen.text(" 20", 0, GetYpos_t(995) );
  TFTscreen.text("  23", 0, GetYpos_t(230) );
  //  TFTscreen.text("26", 0, GetYpos_t(1005) );
  TFTscreen.text("  29", 0, GetYpos_t(290) );
  //  TFTscreen.text("32", 0, GetYpos_t(1015) );
  TFTscreen.text("  35", 0, GetYpos_t(350) );
  //  // 横軸表示
  //  int Ypos = GetYpos_t(20) + 1;
  //  TFTscreen.text("0", GetXpos(0), Ypos );
  //  TFTscreen.text("3", GetXpos(3), Ypos );
  //  TFTscreen.text("6", GetXpos(6), Ypos );
  //  TFTscreen.text("9", GetXpos(9), Ypos );
  //  TFTscreen.text("12", GetXpos(12), Ypos );
  //  TFTscreen.text("15", GetXpos(15), Ypos );
  //  TFTscreen.text("18", GetXpos(18), Ypos );
  //  TFTscreen.text("21", GetXpos(21), Ypos );
}
int GetYpos_t(int Temp)
{
  return gr_BTM_T - ( ( Temp - 200 ) * (gr_BTM_T - gr_TOP_T)) / (350 - 200) ;
}

/////////////////////////////////////////////////////////////////////
// ROSUKU chart drawer
/////////////////////////////////////////////////////////////////////

void drawPrassChartRosukuSub(int hour, int st, int ed, int high, int low, int up )
{
  int xPosOrig = GetXpos( hour );
  uint16_t col = (up) ? TFTscreen.newColor(0, 255, 0) : TFTscreen.newColor(0, 0, 255);
  for (int i = 1; i < 24; i++)
  {
    if ( PrehPa[i] == -1 ) // no data
      continue;
    drawBox( xPosOrig - 2, st, xPosOrig + 2, ed, col           );
    TFTscreen.drawLine( xPosOrig, st, xPosOrig, high, col );  // 上
    TFTscreen.drawLine( xPosOrig, ed, xPosOrig, low, col );  // 上

  }
}

void drawBox(int left, int top, int right, int btm, uint16_t col)
{
  TFTscreen.drawLine( left, top, right, top, col );  // 上
  TFTscreen.drawLine( right, top, right, btm, col );  // 右
  TFTscreen.drawLine( left, top, left, btm, col  );  // 左
  TFTscreen.drawLine( left, btm, right, btm, col  );  // 下

}
void clearDisp() {
  uint16_t col = TFTscreen.newColor(0, 0, 0);
  TFTscreen.fillScreen( col ); // 上

}

void UpdateLedDisp(boolean force)
{
#if 0   // mm.ddhh.mm表示
  // Mon
  if ( old_day_led != day() || force )
  {
    old_day_led = day();
    lc.setDigit(0, 7, (month() / 10), false);
    lc.setDigit(0, 6, (month() % 10), true);
    // Day
    lc.setDigit(0, 5, (day() / 10), false);
    lc.setDigit(0, 4, (day() % 10), false);
  }
#else   // m.dd_hh.mm表示
  if ( old_day_led != day() || force)
  {
    old_day_led = day();
    if ( month() < 9)
      lc.setDigit(0, 7, (month() % 10), true);
    else
    {
      const char month_char[] = "0123456789ond";
      lc.setChar(0, 7, month_char[month()], true);
    }
    // Day
    lc.setDigit(0, 6, (day() / 10), false);
    lc.setDigit(0, 5, (day() % 10), false);
  }
#endif
  // hour
  if (old_min_led != minute() || force)
  {
    old_min_led = minute();
    lc.setDigit(0, 3, (hour() / 10), false);
    lc.setDigit(0, 2, (hour() % 10), true);
    // minute
    lc.setDigit(0, 1, (minute() / 10), false);
    lc.setDigit(0, 0, (minute() % 10), false);
  }

}

// 割り込み時に処理される関数
void SwitchCheck() {
  static boolean sw0 = HIGH;
  static boolean sw1 = HIGH;
  static boolean sw2 = HIGH;
  b_sw0_stat = digitalRead( 0 );
  if ( sw0 == b_sw0_stat )    b_sw0_stat = sw0;
  sw0 = b_sw0_stat;

  b_sw1_stat = digitalRead( 1 );
  if ( sw1 == b_sw1_stat )    b_sw1_stat = sw1;
  sw1 = b_sw1_stat;

  b_sw2_stat = digitalRead( 2 );
  if ( sw2 == b_sw2_stat )    b_sw2_stat = sw2;
  sw2 = b_sw2_stat;

}
```

#ケース
100均で購入してきたバルサ材の箱におさめました。カッターで加工できるので便利です。

#おわりに
縦軸は23-35℃、1000-1020hPaで固定しています。お住いの地域に合せて変更してください。(ハードコーディングしていてごめんなさい)
気温、気圧データは電源OFFでリセットされます。

2018/08/26 Ikeda