LoginSignup
1
1

More than 5 years have passed since last update.

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

Last updated at Posted at 2018-08-26

はじめに

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

時計表示

日付と時刻を1桁離したかったため、月表示だけが16進表示になっています。
最低輝度でも夜中は明るすぎるため、黒いフィルムを貼っています。
image.png

気温気圧表示

24時間の推移表示をします。時計の時刻合せもこちらで行います。
こちらもフィルムを貼っています。
image.png

箱の内部

時刻合せタクトスイッチとI2C用のコネクタはProto Shield上の実装しましたが、その他はジャンパーケーブルでお手軽配線しています。RTCのDS1302も実装していますが使用していません。
これでも1年半問題無く動作しています。
image.png

用意するもの

Arduino Uno

互換を使用しました。
image.png

Proto Sheild

image.png

DS3231

I2Cで通信するRTCモジュールです。
image.png

TFT

ST7735を使用したSPI通信で動作する160x128TFTモジュールです。
image.png

LED

MAX7219を使用したSPI通信を行う8桁のLEDモジュールです。
image.png

温度、気圧センサ

BoschのBMP280を使用した温度気圧センサーです。I2Cで通信しています。
image.png

結線

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
//

プログラム

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

1
1
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
1
1