top of page

 時間の表示 

 RTC DS3231 

DS3231

​ I2C接続で時間と時刻が測定できる6PINモジュールの時計です。バッテリバックアップで電源切断後も時刻を保持することができます。電池ホルダーが付いていてリチウム充電池LIR2032を使います。充電用の回路があるのでCR2032を使うと膨らんでしまうようです。短時間であればCR2032でも一応動きます。I2Cアドレスは&H68です。

 おまけにEEPROMが付いています。​I2Cアドレスは0x57ですがA0,A1,A2をハンダジャンパすることで変更することができます。

     0x57 0x56 0x55 0x54 0x53 0x52 0x51 0x50

A0 OFF  ON  OFF  ON  OFF  ON  OFF  ON

A1 OFF OFF  ON   ON  OFF OFF  ON   ON

A2 OFF OFF OFF OFF  ON   ON   ON   ON

​A0,A1,A2

 ArduinoとはI2C接続ですのでSCLをA5,SDAをA4に配線します。プルアップ抵抗は内蔵されていますので付け加える必要はありません。10K​Ωを付けると5KΩになります。大きな被害はないと思いますが付けない方がいいと思います。

 ライブラリを取得登録しましょう。

ライブラリ登録

 https://github.com/simonkuang/DS3231

​のページにclone or downloadが有りますのでクリックしてフォルダーを指定します。DS3231​のフォルダに入れておきます。DS3231のライブラリです。

​ zipファイルの場所をスケッチ→ライブラリをインクルード→zip形式のライブラリをインストールと手続きします。

​ ZIPファイルの作成はファイルwp複数選択した後,右クリック(整理)→送る→圧縮(zip形式)フォルダー

 簡単でRTCの機能を表示するスケッチを描いてみました。

zipファイル作成

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

#include <DS3231.h>
#include <Wire.h>

 

//宣言(公表)部
DS3231 RTC;//RTCを作る

//変数の宣言
byte year, month, date, DoW, hour, minute, second,prevSecond;

void setup() {//初期設定部
Serial.begin(9600);//serial初期化
Wire.begin();      //wire初期化
Serial.println("Test of DS3231");
}//RTCに初期化はない

void loop() {//繰り返し部
  //時刻の取得
    RTC.getTime(year, month, date, DoW, hour, minute, second);
    if (prevSecond != second) {//以前の秒と違ったとき
      Serial.print(hour);//時間表示
      Serial.print(":");
      Serial.print(minute);//分表示
      Serial.print(":");
      Serial.println(second);//秒表示,改行
      prevSecond=second;//以前の秒を現在の秒に変更
    }
}

​//関数・補助部

 宣言部

 1行目から8行目

 1行目:RTC用のinclude文です。

 2行目:I2C用のincude文です。

 5行目:RTCのオブジェを作ります。

​ 8行目:byte形式の変数を確保します。

プログラム説明

 初期設定部

 10行目から14行目

 11行目:シリアル通信の初期化です。

 12行目:I2Cの初期化です。

 13行目:パソコンに送ります。

​ 14行目:RTCに初期化はありません。

 繰り返し部

 16行目から26行目

 18行目:年,月,日,時,分,秒を取得します。

 19行目:秒の更新されたか判断。

 20行目から24行目:パソコンに送ります。

​ 25行目:秒を更新します。

 関数・補助部

 このスケッチにはありません。

コマンド一覧

 RTCの関数・補助(サブルーチン) 

  RTCのライブラリを使うと以下のように時間に関するDATAを読み書きできる様になります。単語の集まりですので意味はわかります。DoWはDay of Week(曜日)です。

  void getTime(byte& year, byte& month, byte& date, byte& DoW, byte& hour, byte& minute, byte& second);

 

  byte getSecond();
  byte getMinute();
  byte getHour(bool& h12, bool& PM);

  byte getDoW();
 byte getDate();
 byte getMonth(bool& Century);
 byte getYear();


  void setSecond(byte Second);

 void setMinute(byte Minute);

 void setHour(byte Hour);

 void setDow(byte DoW);

​ void setDate(byte Date);

  void setMonth(byte Month);

  void setYear(byte Year);

  void setClockMode(bool h12);

 

  float getTemperature();

​                   DS3231.h参照

​まだ続きます。詳しくはDS3231.hやDS3231.cppを見るとわかります。

 DS3231.hにはどのようなサブルーチンや関数が有り,どのように引数を使うかを示しています。DS3231.cppにはサブルーチンや関数の動作の手続きがかかれています。

​ 液晶に表示できる自立型(パソコンに継がなくても動く)にしてみました。

時計プログラム

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

//宣言部
#include <Wire.h>//I2Cを使用
#include <LiquidCrystal.h>//液晶を使用
#include <DS3231.h>//RTCを使用

LiquidCrystal lcd(8,9,4,5,6,7);//液晶を具現
DS3231 RTC;//RTCを作る

//変数を作る
byte year, month, date, DoW, hour, minute, second,prevSecond;

 

void setup() {//初期設定部
  Serial.begin(9600);//serial初期化
  Wire.begin();      //wire初期化
  lcd.begin(16, 2);  //液晶の設定
//  RTC.setSecond(37);
}

void loop() {//繰り返し部
  //時刻の取得
    RTC.getTime(year, month, date, DoW, hour, minute, second);
    if (prevSecond != second) {//以前の秒と違ったとき
    //時刻の表示
      lcd.setCursor(0, 1);
      if(hour<10){lcd.print(" ");}
      lcd.print(hour);lcd.print(":");
      if(minute<10){lcd.print("0");}
      lcd.print(minute);lcd.print(":");
      if(second<10){lcd.print("0");}
      lcd.print(second);
      prevSecond=second;//以前の秒を現在の秒に変更

    //年表示
      lcd.setCursor(0, 0);//年
      lcd.print("20");
      lcd.print(year);
    //日付表示
      lcd.setCursor(5, 0);//日付
      if(month<10){lcd.print(" ");}
      lcd.print(month);lcd.print("/");
      if(date<10){lcd.print(" ");}
      lcd.print(date);
  }
}
//関数・補助部

 

 16行目にRTCの設定が有ります。Secondのところを年月日時分秒に変えると全て設定できます。//は取らないといけません。

​ 37秒にしてあるのは30秒ちょうどでコンパイルすると正時できます?正確ではありません。

 時刻合わせ 

時刻合わせ

データ消失中,しばらくお待ちください2022/10/18

DS1307

​ ArduinoのデータロガーシールドにRTCのDS1307が載っていますが時計の部分についてはライブラリ(インクルードファイル)を含めて全く同じプログラムで動きます。

 DS1307を専門に使うためにインクルードファイルは,

#include <Wire.h>
#include <Time.h>
#include <TimeLib.h>
#include <DS1307RTC.h>
​の4つ使用します。インスタンスはインクルードファイルに含まれているようです。

DS1302

 時間を知らせる

アラーム

 アラーム 

​ DS3132にはアラームは2回路あります。

​ アラーム関係の命令は8個です。

 

  void getA1Time(byte& A1Day, byte& A1Hour, byte& A1Minute, byte& A1Second, byte& AlarmBits, bool& A1Dy, bool& A1h12, bool& A1PM);

 アラーム1の時刻を取得します。AlarmBitsは15 毎秒,14 秒,12 分秒,8 時分秒

     void getA2Time(byte& A2Day, byte& A2Hour, byte& A2Minute, byte& AlarmBits, bool& A2Dy, bool& A2h12, bool& A2PM);
​ アラーム2に時刻を取得します。(アラーム2は秒の設定はできません。)

    void setA1Time(byte A1Day, byte A1Hour, byte A1Minute, byte A1Second, byte AlarmBits, bool A1Dy, bool A1h12, bool A1PM);
 アラーム1に時刻をセットします。AlarmBitsは0で日時分秒の指定

   void setA2Time(byte A2Day, byte A2Hour, byte A2Minute, byte AlarmBits, bool A2Dy, bool A2h12, bool A2PM);
 アラーム2に時刻をセットします。AlarmBitsは112,96,64,0 Dowで曜日日付指定

 

   * byte AlarmBits sets the behavior of the alarms:
     *    Dy    A1M4    A1M3    A1M2    A1M1    Rate
     *    X    1    1    1    1    Once per second (15)
     *    X    1    1    1    0    Alarm when seconds match (14)
     *    X    1    1    0    0    Alarm when min, sec match (12)
     *    X    1    0    0    0    Alarm when hour, min, sec match (8)
     *    0    0    0    0    0    Alarm when date, h, m, s match (0)
     *    1    0    0    0    0    Alarm when DoW, h, m, s match (0)
     *
     *    Dy    A2M4    A2M3    A2M2    Rate
     *    X    1    1    1    Once per minute (at seconds = 00) (112)
     *    X    1    1    0    Alarm when minutes match (96)
     *    X    1    0    0    Alarm when hours and minutes match (64)
     *    0    0    0    0    Alarm when date, hour, min match (0)
     *    1    0    0    0    Alarm when DoW, hour, min match (0)
                             *DS3231.hより抜粋

    void turnOnAlarm(byte Alarm);
    void turnOffAlarm(byte Alarm);

 アラームのON,OFF

    bool checkAlarmEnabled(byte Alarm);
    bool checkIfAlarm(byte Alarm);

 アラームのチェック

 パソコンの時刻 

アンカー 1

 パソコンの時刻の取得はVBで簡単に実現できます。Dim dtNow As DateTime = DateTime.NowでdtNowに日付と時刻が格納されます。

 例えば"年"の情報はdtNow.Yearに1988少ない10進数で格納されています。

 月日時分秒はそのまま数字で保管されています。

(dtNow.Month,dtNow.Day,dtNow.Hour,

 dtNow.Minute,dtNow.Second)

 月の名前や曜日も数字で記憶されています。

アンカー 1

 曜日と月名 

        Select Case dtNow.DayOfWeek
            Case 0 : csW = "Sunday   日曜日"
            Case 1 : csW = "Monday   月曜日"
            Case 2 : csW = "Tuesday  火曜日"
            Case 3 : csW = "Wednesday水曜日"
            Case 4 : csW = "Thursday 木曜日"
            Case 5 : csW = "Friday   金曜日"
            Case 6 : csW = "Saturday 土曜日"
        End Select
        TextBox27.Text = csW
        Select Case dtNow.Month
            Case 1 : csW = "睦月(むつき) January Jan"
            Case 2 : csW = "如月(きさらぎ) February Feb"
            Case 3 : csW = "弥生(やよい)     March     Mar"
            Case 4 : csW = "卯月(うづき) April Apr"
            Case 5 : csW = "皐月(さつき) May May"
            Case 6 : csW = "水無月(みなづき) June Jun"
            Case 7 : csW = "文月(ふみつき) July Jul"
            Case 8 : csW = "葉月(はづき) August Aug"
            Case 9 : csW = "長月(ながつき) September Sep"
            Case 10 : csW = "神無月(かんなづき) October Oct"
            Case 11 : csW = "霜月(しもつき) November Nov"
            Case 12 : csW = "師走(しわす) December Dec"
        End Select

です。ここをクリックして「テキストを編集」を選択して編集してください。

 月名や曜日は数字で表されています。Case文で分かりやすい言葉に直します。

アンカー 1

 パソコンとマイコンの通信

​​ パソコンとマイコンの間でコマンドという約束の記号を決めておきます。例えばFFFFh(16進数はヒトにも機械にも優し記号です)。FFFFhを「時刻を送信してください」という記号と決めておきます。

 FFFFhのコマンドをマイコンに送ります。

マイコンはコマンドを受け取ったことを返します。

 FFFFhを送信します。

続けて時刻の  時

          分

          秒を送信します。

パソコンは時刻を送信してくることをFFFFhで理解します。データ(時分秒)は2桁であるとわかっているので5文字目(04h)から2桁づつ(時分秒)を読み込みます。

 パソコン

 マイコン

データ消失中,しばらくお待ちください2022/10/18

 FFFFhを受信したマイコンはFFFF123456hを送信します。シリアル通信は10桁の文字をバッファに蓄えます。

​ 最初の4文字がFFFFhであることが分かると次の5文字目から2桁づつ時分秒を読み込みます。

 パソコンとマイコンの約束 

 RTCの刻む時刻は正確ですが限界はあります。長時間経つと誤差が生じます。パソコンはインターネットで時刻を合わせているので正確さが増しています。ほぼ数秒単位の誤差です。

 パソコンを使ってRTCの時刻を合わせることができればより正確な時刻を扱うことができます。

 左の表?のように各コマンドを設定しました。

データ消失中,しばらくお待ちください2022/10/18

 パソコンとマイコンの通信はUSBシリアル通信をします。無線が理想ですが,先ず実現させることを優先させました。パソコンとマイコンの間に8bitの約束の記号を作り,やり取りができるようにします。

​ VBでのシリアル通信 

 VBでシリアル通信をする時は受信と表示はクラスが違うのでデリゲードという手法を使います。

230

231

232

233

234

235

236

    '受信 DelegateSub
    Delegate Sub AddDataDelegate(ByVal str As String)
    '受信 Sub
    Private Sub AddData(ByVal str As String)
        TextBox14.Text = TextBox14.Text + str
        TextBox14.SelectionStart = TextBox14.Text.Length
    End Sub

AddDataというサブルーチンを用意しておきます。

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

    '受信
    Private Sub SerialPort_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
        If SerialPort1.IsOpen = False Then
            Return
        End If
        Try
            '受信データを読み込む.
            Dim data As String
            'data = SerialPort1.ReadByte()
            data = SerialPort1.ReadExisting()
            Invoke(New AddDataDelegate(AddressOf AddData), data)
        Catch ex As Exception
            MsgBox(ex.Message)
        End Try
    End Sub

Invoke(New AddDataDelegate(AddressOf AddData), data)のコマンドでデータを格納します。

Invokeと言うのは「神・霊などの助け」とか[祈る」という意味だそうです。VBでは[呼び出す」という使い方です。

 データをパソコンに送る 

Meteorology_LCD_MPL115A2_0

502

503

504

505

506

507

508

509

510

511

512

513

514

515

516

517

518

519

520

521

522

523

524

525

526

527

528

529

530

531

void SerialSend(unsigned long a){//コマンドに合わせて時計データ送信
  if(a== 0xFFFF){//時刻
    Serial.print("FFFF");
    SerialSend2keta(hour);
    SerialSend2keta(minute);
    SerialSend2keta(second);
  }

 

  if(a== 0xFFFB){//年
    Serial.print("FFFB");
    Serial.print(year);
    SerialSend2keta(month);
    SerialSend2keta(date);
}
  if(a== 0xFFFA){//月
    Serial.print("FFFA");
    SerialSend2keta(month);
  }
  if(a== 0xFFF9){//日
    Serial.print("FFF9");
    SerialSend2keta(date);
  }
  if(a== 0xFFF8){//温度
    Serial.print("FFF8");
    SerialSend2keta(int(Temp2));
    SerialSend2keta(int());//照度
    SerialSend2keta(int());//電圧
    SerialSend2keta(int(Humid));//湿度
     SerialSend4keta(Press);//気圧
}

 

void SerialSend(unsigned long a)

というサブルーチンです。

 (a) という変数は0~FFFFhなのでunsigned long型の変数とします。

 SerialSend(x)で呼び出すと(x)に合わせた処理をします。

 例えばSerialSend(FFFFh);とすれば

​503行目から508行目までの処理をします。

 以下同様に年月日やセンシングしたデータを送信することができます。

 時刻を合わせるマイコンプログラム 

Meteorology_LCD_MPL115A2_0

548

549

550

551

552

553

554

555

556

557

558

559

560

561

562

563

564

565

566

567

568

569

570

571

572

573

574

575

​576

​577578579580581582

  if (a== 0x8FFF){//時設定
    Serial.print("8FFF");
    hour=SerialReadDec();
    RTC.setHour(hour);
  }
  if(a== 0x8FFE){//分設定
    Serial.print("8FFE");
    minute=SerialReadDec();
    RTC.setMinute(minute);
  }
 
  if(a== 0x8FFB){//年設定
    Serial.print("8FFB");
    year=SerialReadDec();
    RTC.setYear(year);
  }
 
  if(a== 0x8FFA){//月設定
    Serial.print("8FFA");
    month=SerialReadDec();
    RTC.setMonth(month);
  }
 
  if(a== 0x8FF9){//日設定
    Serial.print("8FF9");
    date=SerialReadDec();
    RTC.setDate(date);
  }

  if(a== 0x8FF0){//秒設定
    Serial.print("8FF0");
    second=SerialReadDec()+1;delay(500);
    prevSecond=second;
    delay(500);
    RTC.setSecond(second);
    delay(500);
  }

 

void SerialSend(unsigned long a)

というサブルーチンを0FFFhの引数で呼び出します。すると,時刻の時をパソコンから呼び出し,正時します。

​ 以下同様に時分,年月日を合わせることができます。

bottom of page