はじめに
プロジェクトにリアルタイムクロック(RTC)を追加したいけれど、手元にハードウェアがないと思ったことはありませんか?Velxioを使えば、Raspberry Pi Picoと仮想DS1307を使用して、完全なI2C RTC読み出しをブラウザ上でシミュレートできます。このチュートリアルでは、回路、コード、主要な概念を順を追って説明し、自身のプロジェクトでI2C通信を自信を持って使用できるようにします。
回路の解説
まずは回路を見てみましょう。Velxioでサンプルを開くと、以下のコンポーネントが表示されます。

回路はシンプルです。Raspberry Pi Pico(nano-rp2040)が2つのLEDと仮想DS1307 RTC(個別のコンポーネントとしては表示されません—RTCはシミュレーションに組み込まれています)に接続されています。LEDはI2Cアクティビティの視覚的なインジケータとして使用されます。
- LED(青):青いワイヤーでピンD12(SDAライン)に接続されています。アノード(A)はD12に接続され、カソード(C)は黒いワイヤーでGND.1に接続されています。
- LED(黄):オレンジのワイヤーでピンD10(SCLライン)に接続されています。アノード(A)はD10に接続され、カソード(C)は黒いワイヤーでGND.1に接続されています。
両方のLEDは同じグラウンド(GND.1)を共有しています。I2CバスはSDA(データ)ラインとSCL(クロック)ラインで構成されています。DS1307 RTCは内部でアドレス0x68のこれらのラインに接続されています。LEDはI2C通信に厳密には必要ありませんが、ラインがトグルしていることを視覚的に示します。
この回路を自分で構築するには、Velxioのコンポーネントピッカーを使用できます。

「Raspberry Pi Pico」と「LED」を検索し、説明の通りに配線します。キャンバスツールバーは、コンポーネントのズームや配置に役立ちます。

コードの解説
それではコードを見ていきましょう。スケッチはWireライブラリ(組み込み)を使用して、I2C経由でDS1307と通信します。以下が完全なコードです。
// Raspberry Pi Pico — I2C DS1307 RTC Read
// Reads time from virtual RTC at address 0x68
#include <Wire.h>
byte bcdToDec(byte val) {
return ((val >> 4) * 10) + (val & 0x0F);
}
void setup() {
Serial.begin(115200);
delay(500);
Wire.begin();
Serial.println("=== Pico I2C RTC Read ===");
Serial.println("Reading DS1307 at 0x68 (system time)");
Serial.println();
}
void loop() {
// Set register pointer to 0
Wire.beginTransmission(0x68);
Wire.write(0x00);
Wire.endTransmission();
// Read 7 bytes: sec, min, hr, dow, date, month, year
Wire.requestFrom(0x68, 7);
if (Wire.available() >= 7) {
byte sec = bcdToDec(Wire.read() & 0x7F);
byte min = bcdToDec(Wire.read());
byte hr = bcdToDec(Wire.read() & 0x3F);
byte dow = bcdToDec(Wire.read());
byte date = bcdToDec(Wire.read());
byte month = bcdToDec(Wire.read());
byte year = bcdToDec(Wire.read());
const char* days[] = {"", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
Serial.print("Time: ");
if (hr < 10) Serial.print('0'); Serial.print(hr); Serial.print(':');
if (min < 10) Serial.print('0'); Serial.print(min); Serial.print(':');
if (sec < 10) Serial.print('0'); Serial.print(sec);
Serial.print(" Date: ");
Serial.print(days[dow]); Serial.print(' ');
if (date < 10) Serial.print('0'); Serial.print(date); Serial.print('/');
if (month < 10) Serial.print('0'); Serial.print(month); Serial.print('/');
Serial.print("20"); if (year < 10) Serial.print('0'); Serial.println(year);
} else {
Serial.println("RTC not responding!");
}
delay(1000);
}
動作の仕組み
-
セットアップ:115200ボーでシリアル通信を開始し、
Wire.begin()でI2Cバスを初期化します。DS1307はアドレス0x68にあります。 -
ループ:1秒ごとに、以下の処理を行います。
- アドレス0x68に
beginTransmissionを送信し、0x00(秒レジスタへのレジスタポインタ)を書き込み、endTransmissionを実行します。 Wire.requestFrom(0x68, 7)を使用してRTCから7バイトを要求します。- 各バイトを読み取り、ヘルパー関数
bcdToDecを使用してBCD(2進化10進数)から10進数に変換します。 - 時刻と日付をフォーマットしてシリアルモニタに出力します。
- アドレス0x68に
-
BCD変換:DS1307は時刻値をBCD形式で保存します。例えば、バイト
0x45はBCDで45を表します(4*10 + 5 = 45)。bcdToDec関数は10の位(上位ニブル)と1の位(下位ニブル)を抽出して結合します。 -
マスキング:特定のレジスタにマスクを適用します。
- 秒:
& 0x7FでCH(クロック停止)ビットをクリアします。 - 時:
& 0x3Fで12/24時間モードビットをクリアします(24時間モードを想定)。
- 秒:
主要な概念
- I2Cプロトコル:マイクロコントローラとペリフェラル間の通信用の2線式シリアルバス(SDA、SCL)。各デバイスは固有のアドレスを持ちます。
- Wireライブラリ:Arduinoの組み込みI2Cライブラリ。
Wire.begin()でバスに参加し、Wire.beginTransmission(addr)でデバイスとの通信を開始し、Wire.write()でデータを送信し、Wire.endTransmission()で終了し、Wire.requestFrom(addr, count)でバイトを読み取ります。 - BCD形式:多くのRTCは表示を簡略化するためにBCDを使用します。人間が読める出力にするには、10進数に変換する必要があります。
- レジスタマッピング:DS1307には特定のレジスタマップがあります:秒(0x00)、分(0x01)、時(0x02)、曜日(0x03)、日付(0x04)、月(0x05)、年(0x06)。
よくある落とし穴とデバッグのヒント
- I2Cアドレスの間違い:デバイスアドレスを再確認してください。DS1307は通常0x68(7ビット)です。「RTC not responding!」と表示された場合は、アドレスを確認してください。
- プルアップ抵抗の欠落:実際のハードウェアでは、I2Cラインにプルアップ抵抗が必要です。Velxioでは内部でシミュレートされているため、追加する必要はありません。
- ボーレートの不一致:シリアルモニタのボーレートが115200と一致していることを確認してください。
- レジスタポインタが設定されていない:読み取り前に必ずレジスタポインタを設定してください。コードでは0x00を書き込んで秒レジスタを指すようにしています。
- マスキングエラー:CHビット(秒)や12/24時間ビット(時)のマスキングを忘れると、誤った値になる可能性があります。
推奨される拡張機能
- 時刻の設定:現在時刻をRTCに書き込むコードを追加します。各レジスタを設定するには
Wire.write()を使用します。 - アラーム機能:特定の時刻に達したときにLEDをトリガーするアラームを実装します。
- LCDへの表示:シリアルモニタの代わりにI2C LCDを使用して時刻を表示します。
- 複数のRTC:同じバス上の2つの異なるI2Cデバイスからの読み取りを試みます。
実際に試してみよう!
実験の準備はできましたか?Velxioでライブサンプルを開き、シミュレーションを実行してください。シリアルモニタに毎秒時刻が表示されます。コードを変更して更新間隔を変更したり、新しい機能を追加したりできます。
楽しいシミュレーションを!