目的
Raspberry Pi PicoとRTCモジュール(DS1307)をI2C接続し、時刻を計時します。また、時刻情報をOLEDディスプレイに表示し毎秒更新します。
実は以下の記事でC-Firstボードで同様の対応をしていますが、都合により初めて対応するていで進めていきます。

※当該RTCモジュールにはEEPROMも実装されています。EEPROMの制御は別の機会に。
情報
Raspberry Pi Pico
Raspberry Pi Picoについては以下の記事を参照ください。


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

使用するRTC部品
似たような商品が複数見つかりましたが、今回は5個入りでコスパの高いこちらを購入しました。
搭載ICは以下の通りです。
- RTC:DS1307
- EEPROM:AT24C32(32Kb)
ピンヘッダは実装されていません。使い勝手を考えてピンヘッダを実装しました。左右に端子がありますが、私はとりあえずP2側にのみピンヘッダを付けました。

また、バックアップ用の電池も購入しました。指定のLIR2032です。この電池は二次電池で本モジュールに5V給電中は充電されます。
容量が少ないからなのか、出荷時満充電になっていないのか、最初はRTCのバックアップが安定せず頼りない感じでしたが、使っているうちに充電されたのか安定していきました。
尚、同型・同電圧であってもCR2032等の一次電池は絶対に使用しないでください。最悪は発火など大きな事故となる可能性もあります。
※充電ラインをパターンカットすることで一次電池が使用可能になるとの情報も見かけましたが詳細は調べていません。
ロジックレベル変換基板
Raspberry Pi PicoのGPIOは3.3Vですが、DS1307は5Vです。Picoは5Vトレラントではないためレベル変換が必要になります[1]そのまま繋いでもたまたま動くことが多いと思われますがお勧めできません。。今回は以下のモジュールを使用しました。
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ディスプレイモジュールは以下のように接続します。

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

今回使用したジャンパーワイヤーは以下のものになります。
DS1307制御
インターネット上を検索すれば有志の方による解説をすぐに見つけられると思いますが、今回のRTCは制御が簡単なので、まずは自力で対応してみることをお勧めします。データシートの内容(特にレジスタ)をしっかり確認しましょう。
作業
環境
「OLEDディスプレイ(SSD1306)に文字を表示させる」ソフトをベースとします。

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です。
最終プログラム
ビルド方法
以下記事相当の環境構築が行われていることが前提となります。

以下の配置とした場合を例として記載します。
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 | そのまま繋いでもたまたま動くことが多いと思われますがお勧めできません。 |
---|
コメント