【Raspberry Pi Pico】RTCモジュール(DS1307)で時刻を計時する

ワンボードマイコン

目的

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

実は以下の記事でC-Firstボードで同様の対応をしていますが、都合により初めて対応するていで進めていきます。

【C-First】RTCモジュール(DS1307)で時刻を計時する
目的 C-FirstとRTCモジュール(DS1307)をI2C接続し、時刻を計時します。また、時刻情報をOLEDディスプレイに表示し毎秒更新します。 ※当該RTCモジュールにはEEPROMも実装されています。EEPROMの制御は別の機会に。...

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

情報

Raspberry Pi Pico

Raspberry Pi Picoについては以下の記事を参照ください。

格安でマイコン学習可能『Raspberry Pi Pico』
概要・特徴 Raspberry Pi財団が独自に開発したARM Cortex M0+デュアルコアのRP2040マイコンを搭載した開発基板です。 別の記事で紹介したいと思っていますが、Picoは2個用意して1個をエミュレータとして接続すること...
【Raspberry Pi Pico】環境構築
目的 Windows 10/64bitのパソコン上にRaspberry Pi Picoの開発環境を構築します。また、Picoを2個用意して1個をエミュレータとして接続することでブレークポイント・ステップ実行ベースのデバッグが可能となる環境を...

OLEDディスプレイについて

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

【Raspberry Pi Pico】OLEDディスプレイ(SSD1306)に文字を表示する
目的 Raspberry Pi PicoとOELDディスプレイ(コントローラIC SSD1306搭載)をI2C接続し、画面に文字を表示させます。文字データとしては美咲フォントを利用します。 実は以下の記事で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等の一次電池は絶対に使用しないでください。最悪は発火など大きな事故となる可能性もあります。

※充電ラインをパターンカットすることで一次電池が使用可能になるとの情報も見かけましたが詳細は調べていません。

ロジックレベル変換基板

Raspberry Pi PicoのGPIOは3.3Vですが、DS1307は5Vです。Picoは5Vトレラントではないためレベル変換が必要になります[1]そのまま繋いでもたまたま動くことが多いと思われますがお勧めできません。。今回は以下のモジュールを使用しました。

Amazon.co.jp: HiLetgo 10個セット IIC I2C ロジック レベル 変換 双方向モジュール 5V Arduinoに対応 : 産業・研究開発用品
Amazon.co.jp: HiLetgo 10個セット IIC I2C ロジック レベル 変換 双方向モジュール 5V Arduinoに対応 : 産業・研究開発用品

DS1307データシート

https://www.mouser.jp/datasheet/2/256/ds1307-1177772.pdf

AT24C32データシート

https://ww1.microchip.com/downloads/en/DeviceDoc/doc0336.pdf

Raspberry Pi Picoとの接続

Raspberry Pi PicoとRTCモジュール、及びOLEDディスプレイモジュールは以下のように接続します。

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

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

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)に文字を表示させる」ソフトをベースとします。

【Raspberry Pi Pico】OLEDディスプレイ(SSD1306)に文字を表示する
目的 Raspberry Pi PicoとOELDディスプレイ(コントローラIC SSD1306搭載)をI2C接続し、画面に文字を表示させます。文字データとしては美咲フォントを利用します。 実は以下の記事で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] = 0x00;  /* 01h:分 */
    buf[3] = 0x00;  /* 02h:時 */
    buf[4] = 0x01;  /* 03h:曜日 */
    buf[5] = 0x01;  /* 04h:日 */
    buf[6] = 0x11;  /* 05h:月 */
    buf[7] = 0x21;  /* 06h:年 */
    
    (void)i2c_write_blocking(i2c_default, I2C_RTC_ADDR, buf, 8, false);
    
    return;
}

時刻読み出し処理

こちらも簡単な処理ですが、注意点がひとつ。本ICはアクセスすると同時にレジスタアクセスアドレスが自動インクリメントされます。よって読み出したいアドレスを最初に書き込む必要があります。そうしないと前回アクセスしたレジスタの次のアドレスから読み出されてしまいます。

static void RTC_DS1307_read(uint8_t *date)
{
    uint8_t buf;
    
    buf = 0x00;  /* レジスタアドレス */
    
    (void)i2c_write_blocking(i2c_default, I2C_RTC_ADDR, &buf, 1, false);
    (void)i2c_read_blocking(i2c_default, I2C_RTC_ADDR, date, 7, false);
    
    return;
}

OLEDディスプレイに日時を表示する

今回はメインループの中で秒レジスタの値を監視し、変化があったらディスプレイ表示を更新する方式としました。

int main(void)
{
    uint8_t buf[7];
    uint8_t data[2];
    uint8_t last = 0xFF;
    char *week[] = {"日","月","火","水","木","金","土"};
    
    // This example will use I2C0 on the default SDA and SCL pins (4, 5 on a Pico)
    i2c_init(i2c_default, 100 * 1000);
    
    gpio_set_function(I2C_SDA_PIN, GPIO_FUNC_I2C);
    gpio_set_function(I2C_SCL_PIN, GPIO_FUNC_I2C);
    gpio_pull_up(I2C_SDA_PIN);
    gpio_pull_up(I2C_SCL_PIN);
    // Make the I2C pins available to picotool
    bi_decl(bi_2pins_with_func(I2C_SDA_PIN, I2C_SCL_PIN, GPIO_FUNC_I2C));
    
    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);
        }
    }
    
    return 0;
}

できました!

思った通り動かない場合など、ロジアナがあると心強いです。

自分が使っているロジアナはZEROPLUS LAP-Cです。

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

最終プログラム

ビルド方法

以下記事相当の環境構築が行われていることが前提となります。

【Raspberry Pi Pico】環境構築
目的 Windows 10/64bitのパソコン上にRaspberry Pi Picoの開発環境を構築します。また、Picoを2個用意して1個をエミュレータとして接続することでブレークポイント・ステップ実行ベースのデバッグが可能となる環境を...

以下の配置とした場合を例として記載します。

c:/user/pico/pico-ds1307/
├── CMakeLists.txt
├── pico_sdk_import.cmake
└── pico-ds1307
    ├── CMakeLists.txt
    ├── OLED_SSD1306.h
    ├── comdef.h
    ├── main.c
    ├── misakiUTF16.c
    ├── misakiUTF16.h
    └── misakiUTF16FontData.h
$ cd c:/user/pico/pico-ds1307
$ mkdir build
$ cd build
$ cmake .. -G "MSYS Makefiles"
$ make

注釈

注釈
1 そのまま繋いでもたまたま動くことが多いと思われますがお勧めできません。

コメント

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