見出し画像

[ M5 ATOM Lite ] RTC DS3231を組み込む。


<開発環境>
VScode + platformIO

<使用ライブラリ>

・M5ATOM by M5Stack
・FastLED by Daniel Garcia
・LovyanGFX by lovyan03
・M5Unit-ENV byM5Stack
・RTClib by Adafruit(エイダフルーツ)


<Adafuit RTClibライブラリー>

DS3231初期化関数

/**************************************************************************/
/*!
    @brief  Start I2C for the DS3231 and test succesful connection
    @param  wireInstance pointer to the I2C bus
    @return True if Wire can find DS3231 or false otherwise.
*/
/**************************************************************************/
bool RTC_DS3231::begin(TwoWire *wireInstance) {
  if (i2c_dev)
    delete i2c_dev;
  i2c_dev = new Adafruit_I2CDevice(DS3231_ADDRESS, wireInstance);
  if (!i2c_dev->begin())
    return false;
  return true;
}

Twowireクラス ESP32ライブラリ Wire.h

#ifndef TwoWire_h
#define TwoWire_h

#include <esp32-hal.h>
#if !CONFIG_DISABLE_HAL_LOCKS
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#endif
#include "Stream.h"

// WIRE_HAS_BUFFER_SIZE means Wire has setBufferSize()
#define WIRE_HAS_BUFFER_SIZE    1
// WIRE_HAS_END means Wire has end() 
#define WIRE_HAS_END 1

#ifndef I2C_BUFFER_LENGTH
    #define I2C_BUFFER_LENGTH 128  // Default size, if none is set using Wire::setBuffersize(size_t)
#endif
typedef void(*user_onRequest)(void);
typedef void(*user_onReceive)(uint8_t*, int);

class TwoWire: public Stream
{
protected:
    uint8_t num;
    int8_t sda;
    int8_t scl;

    size_t bufferSize;
    uint8_t *rxBuffer;
    size_t rxIndex;
    size_t rxLength;

<略>
      void onReceive( void (*)(int) );
    void onRequest( void (*)(void) );
    size_t slaveWrite(const uint8_t *, size_t);
};

extern TwoWire Wire;
extern TwoWire Wire1;

#endif

初期化例

//DS3231初期化-------------------------------------------------------
  if (! rtc.begin(&Wire1)) {
    Serial.println("Couldn't find RTC");
    Serial.flush();
    while (1) delay(10);
  }

時刻の取得、フォーマット化

今回のコードの解説

if(Ticker3.flag)//割り込み許可フラグでIN
  {
    Ticker3.flag = false;
    //RTC時間表示------------------------------------------------
    DateTime now = rtc.now();
    timeFormat.getBytes(dateByteText,30);
    Serial.printf("timeFormat.getBytes %s\r", dateByteText);
    now.toString((char*)dateByteText);
    Serial.printf("now.toString        %s\r", dateByteText);
    dateString = String((char*)dateByteText);
    dateString = dateString.substring(0,8);
    weekString = String((char*)dateByteText);
    weekString = weekString.substring(9,12);
    timeString = String((char*)dateByteText);
    timeString = timeString.substring(13,21);

    //SSD1306 時刻表示------------------------------------------
    canvas1.beginTransaction();
    canvas1.setTextSize(0.5);
    canvas1.fillRect(0,0,128,20,TFT_BLACK);
    canvas1.drawString(dateString,0,0);
    canvas1.drawString(weekString,60,0);
    canvas1.drawString(timeString,0,10);
    canvas1.pushSprite(0,0);
    canvas1.endTransaction();

    //Serial.printf("%s %s %s\r",dateString,weekString,timeString);
  }

時刻読み出し関数 now()

DateTime now = rtc.now();
DS3231から時刻データをI2C経由で受信したのち、
DataTimeクラスコンストラクタで、インスタンス化します。

/**************************************************************************/
/*!
    @brief  Get the current date/time
    @return DateTime object with the current date/time
*/
/**************************************************************************/
DateTime RTC_DS3231::now() {
  uint8_t buffer[7];
  buffer[0] = 0;
  i2c_dev->write_then_read(buffer, 1, buffer, 7);

  return DateTime(bcd2bin(buffer[6]) + 2000U, bcd2bin(buffer[5] & 0x7F),
                  bcd2bin(buffer[4]), bcd2bin(buffer[2]), bcd2bin(buffer[1]),
                  bcd2bin(buffer[0] & 0x7F));
}
//DateTimeクラスコンストラクタ
DateTime(uint16_t year, uint8_t month, uint8_t day, uint8_t hour = 0,
           uint8_t min = 0, uint8_t sec = 0);

時刻フォーマット化

表示文字列のフォーマット指定子 RTClib.cpp

  | specifier | output                                                 |
    |-----------|--------------------------------------------------------|
    | YYYY      | the year as a 4-digit number (2000--2099)              |
    | YY        | the year as a 2-digit number (00--99)                  |
    | MM        | the month as a 2-digit number (01--12)                 |
    | MMM       | the abbreviated English month name ("Jan"--"Dec")      |
    | DD        | the day as a 2-digit number (01--31)                   |
    | DDD       | the abbreviated English day of the week ("Mon"--"Sun") |
    | AP        | either "AM" or "PM"                                    |
    | ap        | either "am" or "pm"                                    |
    | hh        | the hour as a 2-digit number (00--23 or 01--12)        |
    | mm        | the minute as a 2-digit number (00--59)                |
    | ss        | the second as a 2-digit number (00--59)                |

上記フォーマットに従った文字列を下記のようにヘッダーファイルに定義しておきます。
それと、フォーマットしたデータを格納するchar型配列を用意します。

const String timeFormat="YY/MM/DD DDD hh:mm:ss"; //表示したいフォーマット指定子の文字列
unsigned char dateByteText[30]; //フォーマットデータを格納するバイト配列

次に、now関数で生成したdataTimeクラスインスタンスのデータを、バイト配列に表示フォーマット化して、格納します。

  DateTime now = rtc.now();
    timeFormat.getBytes(dateByteText,30);
    Serial.printf("timeFormat.getBytes %s\r", dateByteText);
    now.toString((char*)dateByteText);
    Serial.printf("now.toString        %s\r", dateByteText);
    dateString = String((char*)dateByteText);
    dateString = dateString.substring(0,8);
    weekString = String((char*)dateByteText);
    weekString = weekString.substring(9,12);
    timeString = String((char*)dateByteText);
    timeString = timeString.substring(13,21);

・Arduino の String クラスの getBytes メソッドは、文字列を byte 型の配列にコピーします。
・コピーしたフォーマット指示文字列をDataTimeクラス
    char *toString(char *buffer) const;に引数*bufferに読み込ませます。
これで、バイト配列dataByteTextに時刻データがフォーマット化されて、格納されます。たとえば、
”YY/MM/DD DDD hh:mm:ss”とフォーマット指定文字列を定義した場合、24/01/05 fri  13:15:00 とバイト配列に格納されます。
このバイト配列をから日時を取り出して、表示しています。

<コード>

DS3231用ヘッダーファイル

#ifndef __MYDS3231_H_
#define __MYDS3231_H_

#include <M5Atom.h>
#include "RTClib.h"

//RTC DS3231****************************
RTC_DS3231 rtc;
char daysOfTheWeek[7][4] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
const String timeFormat="YY/MM/DD DDD hh:mm:ss";
unsigned char dateByteText[30];
String  dateString;
String  timeString;
String  weekString;


#endif

main.cpp

#include <M5ATOM.h>
#include "myLovyanGFX.h"
#include "myENV3.h"
#include "myInterrupt.h"
#include "myDS3231.h"

//グローバル変数********************************************************
uint ledColorNum=0;//RGBLEDの色配列指定
int ledColor[4]={0x000000,0xFF0000,0x008000, 0x0000FF};//RGBLED Red(8),Green(8),Blue(8)

myENV3* env3;

//LovyanGFXインスタンス*************************************************
static LGFX_SSD1306 lcd; 
static LGFX_Sprite canvas(&lcd);  //スプライトバッファ
static LGFX_Sprite canvas1(&lcd);
/***************************************************************
 * setup
**************************************************************/
void setup()
{
  int i;
  //ATOM初期化---------------------------------------------------------
  M5.begin(true,false, true);  //初期化(UART, I2C wire0 , LED)
  //割り込み処理-------------------------------------------------------
  myInterrupt();//割り込み初期化
  //SSD1306初期化 LovyanGFX--------------------------------------------
  lcd.init();
  canvas.createSprite(lcd.width(), lcd.height()-28);
  canvas.setTextWrap(false);       //自動折返し:無し
  canvas1.createSprite(lcd.width(),28);
  canvas1.setTextWrap(false);  
  //ENV3初期化---------------------------------------------------------
  Wire.begin(26,32,400000U);
  env3 = new myENV3();
  //DS3231初期化-------------------------------------------------------
  if (! rtc.begin(&Wire1)) {
    Serial.println("Couldn't find RTC");
    Serial.flush();
    while (1) delay(10);
  }
  //SSD1306初期描画-----------------------------------------------------
  canvas1.beginTransaction();/// 通信トランザクションを開始する。(ペリフェラルを占有する);
  canvas1.fillScreen(TFT_BLACK);    //背景塗り潰し
  canvas1.setTextColor(TFT_WHITE);  //文字色
  canvas1.setFont(&fonts::Font4);
  canvas1.setTextSize(0.8);
  canvas1.drawString("EVN3",5,0);
  canvas1.pushSprite(0,0);
  canvas1.endTransaction();/// 通信トランザクションを終了する。(ペリフェラルの占有を終了する);
  
  //RGBLED点灯
  M5.dis.drawpix(0,ledColor[2]);//blue点灯
  ledColorNum=0;
  delay(500);
}

/**************************************************************
 * メインループ
****************************************************************/
void loop() 
{
  

  if(Ticker2.flag)
  {
    Ticker2.flag=false;
    M5.dis.drawpix(0,ledColor[1]);//red点灯
    if(env3->sht30.get()==0)
    {
      env3->tmp = env3->sht30.cTemp;
      env3->humi = env3->sht30.humidity;
      Serial.printf(
          "Temp: %2.1f  \r\nHumi: %2.0f%%  \r\nPressure:%2.0fPa\r\n---\n",
          env3->tmp,env3->humi,env3->pressure);

      canvas.beginTransaction();
      canvas.setFont(&fonts::Font4);
      canvas.setTextSize(0.8);
      canvas.fillScreen(TFT_BLACK);    //背景塗り潰し
      
      canvas.setCursor(0,3);
      canvas.printf("%2.1fC",env3->tmp);
      canvas.setCursor(60,3);
      canvas.printf("%2.1f%%",env3->humi);

      env3->pressure = env3->qmp6988.calcPressure()/100;
      canvas.setCursor(3,20);
      canvas.printf("%4.1fhPa",env3->pressure);
      canvas.pushSprite(0,28);
      canvas.endTransaction();
    }else
    {
      env3->tmp=0;
      env3->humi=0;
    }
    M5.dis.drawpix(0,ledColor[3]);//blue点灯
  }

  if(Ticker3.flag)
  {
    Ticker3.flag = false;
    //RTC時間表示------------------------------------------------
    DateTime now = rtc.now();
    timeFormat.getBytes(dateByteText,30);
    Serial.printf("timeFormat.getBytes %s\r", dateByteText);
    now.toString((char*)dateByteText);
    Serial.printf("now.toString        %s\r", dateByteText);
    dateString = String((char*)dateByteText);
    dateString = dateString.substring(0,8);
    weekString = String((char*)dateByteText);
    weekString = weekString.substring(9,12);
    timeString = String((char*)dateByteText);
    timeString = timeString.substring(13,21);

    //SSD1306 時刻表示------------------------------------------
    canvas1.beginTransaction();
    canvas1.setTextSize(0.7);
    canvas1.fillRect(0,0,128,28,TFT_BLACK);
    canvas1.drawString(dateString,0,0);
    canvas1.drawString(weekString,70,0);
    canvas1.drawString(timeString,0,14);
    canvas1.pushSprite(0,0);
    canvas1.endTransaction();

    //Serial.printf("%s %s %s\r",dateString,weekString,timeString);
  }

  delay(10);

  
}

捕捉 C++ constメンバ関数

char *DateTime::toString(char *buffer) const

メンバー関数の後ろにconstをつけると、メンバー変数を関数内で変更できなくなります。

この記事が気に入ったらサポートをしてみませんか?