【C-First】RTCモジュール(DS1307)で時刻を計時する

ワンボードマイコン

目的

C-FirstとRTCモジュール(DS1307)をI2C接続し、時刻を計時します。また、時刻情報をOLEDディスプレイに表示し毎秒更新します。

※当該RTCモジュールにはEEPROMも実装されています。EEPROMの制御は別の機会に。

情報

C-First

C-Firstボード及びサンプルプログラムや開発環境が収録されたDVDがセットになった解説書籍です。

https://www.amazon.co.jp/gp/product/4789845273/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=icankot-22&creative=1211&linkCode=as2&creativeASIN=4789845273&linkId=9132882d7f4d1d03b45d353e75b2fd12

C-Firstについては以下の記事を参照ください。

センサ&マイコン搭載実習基板 『C-First』
概要・特徴 C-Firstは、ルネサスエレクトロニクス社の16ビット汎用マイクロコントローラRL78/G14を搭載した学習用マイコン・ボードです。加速度センサや照度センサ、温度センサに加えてArduino互換拡張用コネクタ(アナログ用とデジ...

OLEDディスプレイについて

OLEDディスプレイ(SSD1306)については以下の記事を参照ください。

【C-First】OLEDディスプレイ(SSD1306)に文字を表示する
目的 C-FirstとOELDディスプレイ(コントローラIC SSD1306搭載)をI2C接続し、画面に文字を表示させます。文字データとしては美咲フォントを利用します。 情報 C-First C-Firstボード及びサンプルプログラムや開発...

使用するRTC部品

似たような商品が複数見つかりましたが、今回は5個入りでコスパの高いこちらを購入しました。

ご迷惑をおかけしています!

搭載ICは以下の通りです。

  • RTC:DS1307
  • EEPROM:AT24C32(32Kb)

ピンヘッダは実装されていません。使い勝手を考えてピンヘッダを実装しました。左右に端子がありますが、私はとりあえずP2側にのみピンヘッダを付けました。

https://www.amazon.co.jp/gp/product/B008QUVM4E/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=icankot-22&creative=1211&linkCode=as2&creativeASIN=B008QUVM4E&linkId=7153165506a69c17ba16bab3cc672a70

また、バックアップ用の電池も購入しました。指定のLIR2032です。この電池は二次電池で本モジュールに5V給電中は充電されます。

Amazon.co.jp

容量が少ないからなのか、出荷時満充電になっていないのか、最初は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ディスプレイモジュールは以下のように接続します。

ブレッドボードとジャンパーワイヤーを使用して接続した実際の様子は以下の通りです。

今回使用したブレッドボードとジャンパーワイヤーは以下のものになります。

https://www.amazon.co.jp/gp/product/B00DSKCS68/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=icankot-22&creative=1211&linkCode=as2&creativeASIN=B00DSKCS68&linkId=30278f5234f53dadcedda411ec9e2c8f
https://www.amazon.co.jp/gp/product/B083LT3759/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=icankot-22&creative=1211&linkCode=as2&creativeASIN=B083LT3759&linkId=2be05508b56a70afa72a4078702db692

DS1307制御

インターネット上を検索すれば有志の方による解説をすぐに見つけられると思いますが、今回のRTCは制御が簡単なので、まずは自力で対応してみることをお勧めします。データシートの内容(特にレジスタ)をしっかり確認しましょう。

作業

環境

「OLEDディスプレイ(SSD1306)に文字を表示させる」ソフトをベースとします。

【C-First】OLEDディスプレイ(SSD1306)に文字を表示する
目的 C-FirstとOELDディスプレイ(コントローラIC SSD1306搭載)をI2C接続し、画面に文字を表示させます。文字データとしては美咲フォントを利用します。 情報 C-First C-Firstボード及びサンプルプログラムや開発...

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が初期化されてしまうと読み出し処理に失敗するため時計が表示されなくなるので、初期化処理のコメントを外してプログラムを実行し現在時刻を書き込み&計時開始する必要があります。

最終プログラム

RTC_DS1307.zip

コメント

タイトルとURLをコピーしました