時間の表示
RTC 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の機能を表示するスケッチを描いてみました。
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
ArduinoのデータロガーシールドにRTCのDS1307が載っていますが時計の部分についてはライブラリ(インクルードファイル)を含めて全く同じプログラムで動きます。
DS1307を専門に使うためにインクルードファイルは,
#include <Wire.h>
#include <Time.h>
#include <TimeLib.h>
#include <DS1307RTC.h>
の4つ使用します。インスタンスはインクルードファイルに含まれているようです。
時間を知らせる
アラーム
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);
アラームのチェック
パソコンの時刻
パソコンの時刻の取得はVBで簡単に実現できます。Dim dtNow As DateTime = DateTime.NowでdtNowに日付と時刻が格納されます。
例えば"年"の情報はdtNow.Yearに1988少ない10進数で格納されています。
月日時分秒はそのまま数字で保管されています。
(dtNow.Month,dtNow.Day,dtNow.Hour,
dtNow.Minute,dtNow.Second)
月の名前や曜日も数字で記憶されています。
曜日と月名
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文で分かりやすい言葉に直します。
パソコンとマイコンの通信
パソコンとマイコンの間でコマンドという約束の記号を決めておきます。例えば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の引数で呼び出します。すると,時刻の時をパソコンから呼び出し,正時します。
以下同様に時分,年月日を合わせることができます。