目的
C-FirstとRTCモジュール(DS1307)をI2C接続し、時刻を計時します。また、時刻情報をOLEDディスプレイに表示し毎秒更新します。
※当該RTCモジュールにはEEPROMも実装されています。EEPROMの制御は別の機会に。
情報
C-First
C-Firstボード及びサンプルプログラムや開発環境が収録されたDVDがセットになった解説書籍です。
C-Firstについては以下の記事を参照ください。
![](https://osorkoma.net/kumikomi/wp-content/uploads/2021/10/C-First-e1634793858252-160x90.jpg)
OLEDディスプレイについて
OLEDディスプレイ(SSD1306)については以下の記事を参照ください。
![](https://osorkoma.net/kumikomi/wp-content/uploads/2021/10/SSD1306_02-e1634746077142-160x90.jpg)
使用するRTC部品
似たような商品が複数見つかりましたが、今回は5個入りでコスパの高いこちらを購入しました。
搭載ICは以下の通りです。
- RTC:DS1307
- EEPROM:AT24C32(32Kb)
ピンヘッダは実装されていません。使い勝手を考えてピンヘッダを実装しました。左右に端子がありますが、私はとりあえずP2側にのみピンヘッダを付けました。
![](https://m.media-amazon.com/images/I/41Tdti-8oYL..jpg)
また、バックアップ用の電池も購入しました。指定のLIR2032です。この電池は二次電池で本モジュールに5V給電中は充電されます。
容量が少ないからなのか、出荷時満充電になっていないのか、最初はRTCのバックアップが安定せず頼りない感じでしたが、使っているうちに充電されたのか安定していきました。
尚、同型・同電圧であってもCR2032等の一次電池は絶対に使用しないでください。最悪は発火など大きな事故となる可能性もあります。
※充電ラインをパターンカットすることで一次電池が使用可能になるとの情報も見かけましたが詳細は調べていません。
DS1307データシート
https://www.mouser.jp/datasheet/2/256/ds1307-1177772.pdf
AT24C32データシート
https://ww1.microchip.com/downloads/en/DeviceDoc/doc0336.pdf
C-Firstとの接続
C-FirstとRTCモジュール、及びOLEDディスプレイモジュールは以下のように接続します。
ブレッドボードとジャンパーワイヤーを使用して接続した実際の様子は以下の通りです。
今回使用したブレッドボードとジャンパーワイヤーは以下のものになります。
DS1307制御
インターネット上を検索すれば有志の方による解説をすぐに見つけられると思いますが、今回のRTCは制御が簡単なので、まずは自力で対応してみることをお勧めします。データシートの内容(特にレジスタ)をしっかり確認しましょう。
作業
環境
「OLEDディスプレイ(SSD1306)に文字を表示させる」ソフトをベースとします。
![](https://osorkoma.net/kumikomi/wp-content/uploads/2021/10/SSD1306_02-e1634746077142-160x90.jpg)
DS1307を制御するプログラムを実装する
OLED(SSD1306)に比べれば非常に簡単な制御です。
DS1307初期設定処理(時刻設定処理)
現在時刻を設定します。その値を起点にバッテリーバックアップが効いている間は電源OFF状態でも計時され続けます。スレーブアドレスはRTCが0x68、EEPROMが0x50です。
static void RTC_DS1307_init(void)
{
uint8_t buf[8];
buf[0] = 0x00; /* レジスタアドレス */
buf[1] = 0x00; /* 00h:秒 */
buf[2] = 0x05; /* 01h:分 */
buf[3] = 0x01; /* 02h:時 */
buf[4] = 0x00; /* 03h:曜日 */
buf[5] = 0x06; /* 04h:日 */
buf[6] = 0x08; /* 05h:月 */
buf[7] = 0x21; /* 06h:年 */
i2c_flag = 0;
R_IICA0_Master_Send(I2C_RTC_ADDR, buf, 8, 1); /* I2C送信実行 */
while (i2c_flag == 0) ; /* 送信完了待ち */
R_IICA0_StopCondition(); /* I2C通信終了 */
while (SPD0 == 0) ; /* ストップ・コンディション検出待ち */
return;
}
時刻読み出し処理
こちらも簡単な処理ですが、注意点がひとつ。本ICはアクセスすると同時にレジスタアクセスアドレスが自動インクリメントされます。よって読み出したいアドレスを最初に書き込む必要があります。そうしないと前回アクセスしたレジスタの次のアドレスから読み出されてしまいます。
static void RTC_DS1307_read(uint8_t *date)
{
uint8_t buf[7];
buf[0] = 0x00; /* レジスタアドレス */
i2c_flag = 0;
R_IICA0_Master_Send(I2C_RTC_ADDR, buf, 1, 1); /* I2C送信実行 */
while (i2c_flag == 0) ; /* 送信完了待ち */
R_IICA0_StopCondition(); /* I2C通信終了 */
while (SPD0 == 0) ; /* ストップ・コンディション検出待ち */
i2c_flag = 0;
R_IICA0_Master_Receive(I2C_RTC_ADDR, date, 7 , 1); /* I2C受信実行 */
while (i2c_flag == 0) ; /* 送信完了待ち */
R_IICA0_StopCondition(); /* I2C通信終了 */
while (SPD0 == 0) ; /* ストップ・コンディション検出待ち */
return;
}
OLEDディスプレイに日時を表示する
今回はメインループの中で秒レジスタの値を監視し、変化があったらディスプレイ表示を更新する方式としました。
int main(void)
{
uint8_t buf[7];
uint8_t data[2];
uint8_t last = 0xFF;
char *week[] = {"日","月","火","水","木","金","土"};
R_MAIN_UserInit();
/* Start user code. Do not edit comment generated here */
OLED_SSD1306_init();
OLED_SSD1306_clear();
// RTC_DS1307_init(); /* 時刻設定する際にのみコメントを外す */
buf[0] = 0XFF;
while (1U)
{
RTC_DS1307_read(buf);
if(buf[0] != last) {
g_y = 0;
g_x = 0;
last = buf[0];
data[1] = 0;
/* 年 */
OLED_SSD1306_println("20");
data[0] = (buf[6] >> 4) + 0x30;
OLED_SSD1306_println(data);
data[0] = (buf[6] & 0x0F) + 0x30;
OLED_SSD1306_println(data);
OLED_SSD1306_println("/");
/* 月 */
data[0] = (buf[5] >> 4) + 0x30;
OLED_SSD1306_println(data);
data[0] = (buf[5] & 0x0F) + 0x30;
OLED_SSD1306_println(data);
OLED_SSD1306_println("/");
/* 日 */
data[0] = (buf[4] >> 4) + 0x30;
OLED_SSD1306_println(data);
data[0] = (buf[4] & 0x0F) + 0x30;
OLED_SSD1306_println(data);
/* 曜日 */
OLED_SSD1306_println("(");
OLED_SSD1306_println(week[buf[3]]);
OLED_SSD1306_println(")\n");
/* 時 */
data[0] = ((buf[2] >> 4) & 0x03) + 0x30;
OLED_SSD1306_println(data);
data[0] = (buf[2] & 0x0F) + 0x30;
OLED_SSD1306_println(data);
OLED_SSD1306_println(":");
/* 分 */
data[0] = (buf[1] >> 4) + 0x30;
OLED_SSD1306_println(data);
data[0] = (buf[1] & 0x0F) + 0x30;
OLED_SSD1306_println(data);
OLED_SSD1306_println(":");
/* 秒 */
data[0] = (buf[0] >> 4) + 0x30;
OLED_SSD1306_println(data);
data[0] = (buf[0] & 0x0F) + 0x30;
OLED_SSD1306_println(data);
}
}
/* End user code. Do not edit comment generated here */
return 0;
}
できました!
バッテリーバックアップが効いている間は、USBを接続して(電源をONして)リセットボタンを押せば時計のディスプレイ表示が再開します(デバッガを接続しない場合はSW3/SW4をVCOM側に切り替えることを忘れないように)。バッテリーが切れてRTCが初期化されてしまうと読み出し処理に失敗するため時計が表示されなくなるので、初期化処理のコメントを外してプログラムを実行し現在時刻を書き込み&計時開始する必要があります。
コメント