ESP32-WROOM-32E(ESP32)を使ってサンプリング周波数1kHzの測定器を製作する方法の紹介をしています。
ここでは、ADコンバータ部分のハードウェア・ソフトウェアの解説と実際の動作確認などをまとめていますので、参考になればと思います。
ハードウェア
I2C通信の2本の信号線と、電源・GNDを接続します。電源とリファレンス用のコンデンサも忘れずに接続します。少しでもノイズの影響を軽減したい場合は、電源とGNDの配線を専用にすると良いかと思います。
回路図
ADコンバータ
型名:LTC2301IMS
12bit、1チャンネル、14ksps、逐次比較、内部リファレンス有、5V電源、I2CインタフェースのADコンバータです。3.3V電源の16bit分解能ADコンバータを使いたかったのですが、購入できるお店で見つけることが出来ませんでした。
下の写真は秋次電子通商で購入したADコンバータ(LTC2301IMS)をMSOPパッケージ用DIP変換基板(AE-MSOP12P-DIP)にはんだ付けしたものです。これを使用しました。
他にセラミックコンデンサ10μFと0.1μFが2個づつ必要です。
レベルシフタ
ESP32の信号レベルが3.3V、ADコンバータLTC2301MSの信号レベルが5Vなので、信号のレベル変換をします。
下の写真は秋次電子通商で購入したロジックレベル変換モジュール(AE-LCNV4-MOSFET(BSS138))です。これを使用しました。
配線
電源とGNDの配線をADコンバータ回路用に準備することでノイズの影響を軽減できる場合があります。
何も気にせず下図のように配線すると、電源とGNDからのノイズがAD変換データに大きく影響を与える場合が有ります。
電源とGNDを大元の電源の根元から専用線で引き出すことで、他の回路のノイズを極力受けないようにします。下図のようなイメージです。
今回製作した測定器も電源の根元から専用の配線でつなげています。
ソフトウェア
Arduino IDE
統合開発環境 Arduino IDE を使ってプログラミング・コンパイル・転送を行っています。
Arduino IDEついては、詳しく解説しているサイトがいろいろあるので、そちらを参照して頂けると幸いです。
ソースコード
1kHz(1msec)の測定データ読み込みタイミングをとるために、タイマー割り込みを使います。
タイマー割り込み内でAD変換開始のフラグを立てて、メインループ内でそのフラグを監視します。フラグが立っていればADコンバータからデータを読み込む流れです。
#include <stdio.h>
#include <Wire.h>
#define LTC2301_ADR 0x08
#define SDA_NUM 21
#define SCL_NUM 22
#define FREQ_HZ 400000
// AD変換フラグ
volatile byte irt_adc = false;
// タイマー割り込み
hw_timer_t *timer = NULL;
//*************************
// タイマー割り込み
//*************************
void IRAM_ATTR onTimer()
{
// AD変換フラグを立てる
irt_adc = true;
}
//*************************
// AD変換
//*************************
int adConversion()
{
byte ret[2];
int dat;
// I2C開始
Wire.requestFrom(LTC2301_ADR, 2);
// 2バイト取得で終了
if (2 <= Wire.available())
{
ret[0] = Wire.read();
ret[1] = Wire.read();
dat = (ret[0] << 4)|((ret[1] >> 4) & 0x0F);
}
return dat;
}
//*************************
// Setup関数
//*************************
void setup(void)
{
// シリアル通信
Serial.begin(115200);
delay(100);
// I2C通信
Wire.begin(SDA_NUM, SCL_NUM, FREQ_HZ);
delay(100);
// タイマー割り込み
timer = timerBegin(0, 80, true); // 80clock = 1count (1clock = 12.5ns(80Mhz) 1count = 1us)
timerAttachInterrupt(timer, &onTimer, true);
timerAlarmWrite(timer, 1000, true); // 1us * 1000 = 1ms
timerAlarmEnable(timer);
}
//*************************
// loop関数
//*************************
void loop(void)
{
int ad_dat;
// AD変換
if(irt_adc == true)
{
ad_dat = adConversion();
irt_adc = false;
}
}
LTC2301はデフォルト設定のままで、ユニポーラ(ストレートバイナリ)です。内蔵のリファレンスを使用して、入力範囲0V~+4.095Vで1LSBが1mVとなります。
補足説明
〇タイマー割り込みに使用する変数は、volatile宣言が必要
〇setup関数内のシリアル通信宣言はデバック用に残しているだけで使っていません。
動作確認
サンプリング周波数の確認
I2C通信のSCL信号とSDA信号に遅れやジッタが無く、1kHzで測定データを取得していることを確認しました。
下図は、上がSCL信号で下がSDA信号です。
1kHz(1msec)間隔でデータを読み込んでいることを確認できます。
上記の赤点線枠を拡大したI2C通信波形です。
ちなみに信号の内容は、
【7bitアドレス】【R/W】【Ack】【8bitデータ】【Ack】【8bitデータ】【Ack】です。
ESP32とADコンバータLT2301のI2C通信は fast mode(400kbps)で行っているので、1回の通信時間はおおよそ予想できる思います。実測では約74μsecでした。
結果
1kHz(1msec)間隔での測定データ取得に対して、通信時間が約74μsecなので十分に余裕があると思います。また、通信の異常な遅れやジッタなどは確認できませんでした。
参考動画(49秒)
測定データの確認
精度
データシートでは、微分・積分の直線性誤差がそれぞれmax ±1LSBで、オフセット誤差がmax±6LSBです。残念ながらデータシートの仕様を確認することができる機器を持っていないので未確認です。
ノイズ
ノイズは、1秒間(1000データ)の測定で、1digtという結果でした。
ちなみに測定対象はアルカリ乾電池の電圧の1.5Vです。
特筆すべき環境としては、LTC2301の電源はESP32の電源と共通でPCからのUSB供給です。
ADデータは1502と1503の2数値という結果でした。単純に換算すると、アルカリ乾電池の電圧は『1.502V~1.503V』という結果です。
結果
ほとんど気を遣うことなくデータシート通りの回路を配線しただけで、良好な結果を得られました。
ただし、回路図に記載されているコンデンサ(特にREFCOMP)を接続しないと、とんでもなくノイズが増えるので注意してください。
拡張機能
最終的には、複数台の測定器を接続してAD変換タイミングを合わせる(同期)機能と、複数台接続した測定器のうちのいずれかが測定開始(トリガ)信号を発生させ、すべての測定器が測定開始を合わせる機能を追加する予定です。
これらの拡張機能は、ここで紹介したプログラムにハードウェア割り込みを追加して実現します。
詳しくは、こちらで解説していますので参考にしてください。
まとめ
ADコンバータのハードウェアとソフトウェア、動作確認について解説しましたが如何でしたでしょうか。期待通りでない場合は、メーカー推奨の回路どおりに作っていなかったりするので確認してみてください。
いろいろなセンサーの使い方を紹介しています。
コメント
とても興味・参考になる公開資料と思いやってみたいと思いました。
M5stickCPlusとADS1115orADS1015の組み合わせでは試したりはしてないでしょうか?
また作成したコードを提供いただくことは難しいでしょうか?
鶴翔様
問い合わせありがとうございます。
残念ながらM5stickCPlusおよびADS1115/ADS1015を試したことがありません。
現物も触ったことがないのでコード提供は厳しいです。すみません。
コードについてはこの記事で作成されたESP32のものでも難しいでしょうか?SDカードへの書き込みや同期等どのように処理されているのか気になりました。
鶴翔様
ADCのインタフェースはI2C通信ですが、ADS1115とLTC2301は別物なので何らかしらのコード変更が必要になると思います。
またM5stickCPlusなのでADC以外の所でコードの変更が必要になるかもしれません(この部分は実際に動かしてみないとわからないです)。
SDカードへの書き込みや同期の方法は、現在記事を作成中しております。
(更新が遅くなりすみません)