皆さん こんにちは。
今回は I2C を使って気圧センサーモジュールとつないでみます。
気圧センサーモジュール
今回使った気圧センサーモジュールは こちら です。
端子設定で I2C と SPI のインターフェースを切り替えることができるのでマイコンペリフェラルの取り扱いを練習するのに良さそうです。
デバイスのデータシートは こちら です。
半田付けでジャンパー2か所を短絡すると SCL, SDA のラインに10kΩのプルアップ抵抗をつけることができます。
今回はジャンパー2か所を半田付けして SCL, SDA のラインを10kΩの抵抗でプルアップしてください。
接続例
配線のしやすさを考慮してこちらでは以下のように接続しました。
モジュールの4番はアドレスの最下位ビット(A0)でGNDにつなぎました。
モジュールの5番はモードセレクトで、I2Cのインターフェースを使う場合には3.3Vに接続します。

環境構築やプロジェクトのつくり方
環境構築やプロジェクトのつくり方、VSCodeの起動については、このブログの一番最初の記事に書きました。
環境構築してみたい方は こちら をご覧になってください。
プロジェクトの作成
以下の設定でプロジェクトを作成します。
Project Name: picoI2c
Library Options の I2C interface をチェックする
Console Options の Console over UART をチェックする
IDE Options の Create VSCode project をチェックする
Debugger: は PicoProbe を選択する

VSCodeを起動する
起動後、何かファイルが開いてたら File – Close Folder で閉じた後、File – Open Folder から picoI2c のフォルダーを辿って選択します。
こちらの環境では C:\Users\m3925\Documents\Pico\pico-project-generator\picoI2c です。
m3925の部分は皆さんのユーザー名に置き換えてください。
vscode関連の json ファイルは前回作成済のプロジェクトのものをドラッグ&ドロップでコピー&ペーストすると楽です。
ソースコードを書く
今回はファイルを分割してみました。
まずは picoI2c.c を以下の通りに編集します。
picoI2c.c
VSCodeのツリーから picoI2c.c を選択して次のように編集し、保存します。
#include <stdio.h>
#include "LPS25HB.h"
#include "hardware/i2c.h"
#include "pico/stdlib.h"
int main() {
stdio_init_all();
// I2C Initialisation. Using it at 100KHz.
i2c_init(i2c0, 100 * 1000);
gpio_set_function(I2C_SDA, GPIO_FUNC_I2C);
gpio_set_function(I2C_SCL, GPIO_FUNC_I2C);
puts("Hello, I2C!");
uint8_t buf[20];
bool result = LPS25HB_init(i2c0, buf);
if (result) {
puts("LPS25HB initialize success.");
buf[0] = CTRL_REG1;
buf[1] = WAKE_UP;
LPS25HB_write(i2c0, buf, 2, false);
sleep_ms(10);
buf[0] = P_ADRS | 0x80;
LPS25HB_write(i2c0, buf, 1, true);
LPS25HB_read(i2c0, buf, 3, true);
int pressure = buf[2] << 16 | buf[1] << 8 | buf[0];
pressure /= 4096;
printf("Today's atmospheric pressure is %d[hPa].", pressure);
} else {
puts("LPS23HB Init failure.");
}
return 0;
}
続いて LPS25HB.c を作成します。
LPS25HB.cの作成と編集
まず File - New File から入力ボックスに LPS25HB.c と入力し Enterキーを押します。
picoI2c のディレクトリーが出るので、そのまま Create File ボタンを押します。
続いて LPS25HB.c を以下の通りに編集します。
#include "LPS25HB.h"
bool LPS25HB_init(i2c_inst_t *i2c, uint8_t *buf) {
bool result;
buf[0] = WHO_AM_I;
result = LPS25HB_write(i2c, buf, 1, true);
if (result) {
result = LPS25HB_read(i2c, buf, 1, false);
if (result) {
if (LPS25HB_DEVICE_CODE == buf[0]) {
return true;
} else {
return false;
}
} else {
return false;
}
} else {
return false;
}
}
bool LPS25HB_write(i2c_inst_t *i2c, uint8_t *buf, int length, bool nostop) {
int ret = i2c_write_timeout_us(i2c, LPS25HB_ADRS, buf, length, nostop,
10000 * length);
if (ret == length) {
#ifdef PICO_DEBUG
puts("I2C write success.");
#endif
return true;
} else {
#ifdef PICO_DEBUG
if (PICO_ERROR_GENERIC == ret) {
puts("PICO Error Generic.");
} else if (PICO_ERROR_TIMEOUT == ret) {
puts("PICO Error timeout.");
}
#endif
}
return false;
}
bool LPS25HB_read(i2c_inst_t *i2c, uint8_t *buf, int length, bool nostop) {
int ret = i2c_read_timeout_us(i2c, LPS25HB_ADRS, buf, length, nostop,
10000 * length);
if (ret == length) {
#ifdef PICO_DEBUG
puts("I2C read success.");
#endif
return true;
} else {
#ifdef PICO_DEBUG
if (PICO_ERROR_GENERIC == ret) {
puts("PICO Error Generic.");
} else if (PICO_ERROR_TIMEOUT == ret) {
puts("PICO Error timeout.");
}
#endif
}
return false;
}
続いて LPS25HB.h を作成します。
LPS25HB.hの作成と編集
File - New File から入力ボックスに LPS25HB.h と入力し Enterキーを押します。
picoI2c のディレクトリーが出るので、そのまま Create File ボタンを押します。
続いて LPS25HB.h を以下の通りに編集します。
#ifndef __LPS25HB_H
#define __LPS25HB_H
#include "hardware/i2c.h"
#include "pico/stdlib.h"
#define PICO_DEBUG
#define I2C_SDA 20 // 26pin
#define I2C_SCL 21 // 27pin
#define LPS25HB_ADRS 0x5c
#define WHO_AM_I 0x0f
#define CTRL_REG1 0x20
#define WAKE_UP 0x90
#define P_ADRS 0x28
#define LPS25HB_DEVICE_CODE 0xbd
bool LPS25HB_init(i2c_inst_t *, uint8_t *);
bool LPS25HB_write(i2c_inst_t *i2c, uint8_t *, int, bool);
bool LPS25HB_read(i2c_inst_t *i2c, uint8_t *, int, bool);
#endif /* __LPS25HB_H */
CMakeLists.txtの編集
ファイルを追加したので、CMakeLists.txt を編集する必要があります。
add_executable() に LPS25HB.c を追加します。
add_executable(picoI2c picoI2c.c LPS25HB.c)
これで追加したファイルもビルドしてもらえるようになります。
それから最適化しないオプションをつけるとデバッグしやすくなることがあります。
「最適化しないオプション」をつける場合には以下の2行を追加します。
add_compile_options(-std=c11 -O0 -g -Wall)
add_compile_options(-std=c++17 -O0 -g -Wall)
私は快適なデバッグを優先するので、こちらを使っています。
(良く理解せずに使っているので何か不備があったらすみません)
PC側の準備
I2C通信の動作確認用として Tera Term を使います。
API関数がうまく動作したか否かなどの結果をUARTのputs()やprintf()でログ出力するようにしてみました。
Tera Termをお持ちでない方は こちら からダウンロードしてお使いください。
インストール後、 Tera Term を起動し、シリアルポートでPicoprobeのCOMポートを選択します。
もしCOMポートが複数ある場合には、Picoprobe以外の通信ケーブルをはずしてデバイスマネージャーでCOMポート番号を確認しておきます。

起動後、設定メニューのシリアルポートから以下の設定を行います。
スピート : 115200
データ : 8 bit
パリティ : なし
ストップビット : 1
フロー制御 : none
(設定値からスピードだけ変更すれば良いはずです)
今回使ったI2CのAPI
i2c_init()
I2Cの初期化を行います。
第1引数:I2Cのインスタンスを指定します。
第2引数:ボーレート(クロックの速度)を指定します。
i2c_write_timeout_us()
I2Cスレーブに対してタイムアウト付きで指定バイト数分書き込みを行います。
アドレスは書き込むバイト数には含まれません。
第1引数:I2Cのインスタンスを指定します。
第2引数:スレーブのアドレスを指定します。
このAPIでは左シフトしない7ビットのアドレスそのものを指定します。
第3引数:書き込み用のバッファを指定します。
第4引数:書き込むバイト数を指定します。
第5引数:書き込み後、ストップコンディションを実行する場合には true を指定します。
リスタートし、続けて読み込むシーケンスに入る場合には false を指定します。
第6引数:タイムアウト値をusecで指定します。
i2c_read_timeout_us()
I2Cスレーブからタイムアウト付きで指定バイト数分読み込みを行います。
アドレスは読み込むバイト数には含まれません。
第1引数:I2Cのインスタンスを指定します。
第2引数:スレーブのアドレスを指定します。
このAPIでは左シフトしない7ビットのアドレスそのものを指定します。
第3引数:読み込み用のバッファを指定します。
第4引数:読み込むバイト数を指定します。
第5引数:読み込み後、ストップコンディションを実行する場合には true を指定します。
第6引数:タイムアウト値をusecで指定します。
コードの説明
I2Cに使う端子は配線しやすい位置のピン番号を選びました(26, 27番)
デバイスに対して WHO_AM_I (0x0f) のコードを送り、1バイト読むとデバイスコードが返ってきます。
デバイスコードが LPS25HB_DEVICE_CODE (0xbd) であれば正しく応答できていると考えて良いでしょう。
LPS25HB_init() で上記の処理を行っています。
その後、Control Register1(CTRL_REG1) に WAKE_UP (0x90) のコードを送りモジュールを起こします。
そして、P_ADRS に連続するアドレスから3バイトの値を読みます。
P_ADRS に 0x80 を OR するとアドレスが自動でインクリメントされる機能を使っています。
読んできた3バイトを合成して 4096 で割ると気圧[hPa]を得ることができます。
詳しくはデータシートをご覧になってください。
動作させてみる
それでは F5キーを押してプログラムを動作させてみます。
Tera Term に計測した気圧が表示されれば成功です。
成功した時の画像を貼っておきます。

それから起動時に WHO_AM_I を送りコードが戻ってきた様子を観測した波形も貼っておきます。
上がクロック(SCL)、下がデータ(SDA)です。
データの左側がスレーブアドレスに続いて WHO_AM_I (0x0f) 、右側がスレーブアドレスに続いて 戻りのコード LPS25HB_DEVICE_CODE (0xbd) です。
波形からコードを読み取ってみてください (^^)

デバッグ時の様子を撮ったのでついでに貼っておきます。
上から Picoprobe , ラズピコ , 気圧センサーモジュール , ADALM2000(簡易オシロスコープ) です。

GitHub に picoI2c のコードをアップしましたのでご自由にお使いください。
(ただし当方では動作の保証は行っていません)
お疲れさまでした。