Arduinoで商用電源周波数を測定(ESP32編)
◆まえがき
電源周波数測定の話の続きです。前回は Arduino NANO (ATmega328P) を使いましたが 、今回はESP32でやってみます。ただ、簡単に出来ると思っていたのに思わぬ苦戦を強いられました。
◆電源周期の周期の測定方法
前の記事では、電源の周期測定の方法として micros() の値を参照する方法と、タイマーカウンタを使う二つの測定方法を試しました。タイマーカウンタを使った方が精度が高い測定が出来るのですが、残念ながらESP32で同じことをやる方法が判りません。仕方が無いので micros() の値を使う方法でやることにしました。
◆プログラム
プログラムは以下の通りです
セマフォやミューテックスを使った排他制御を行うべきなんでしょうが、正しいやり方が判らなかったので、今回は省略しています。でもアクセスするタイミングは固定で競合は起こらないはずなので、このままでも良い気もしますが、どうなんでしょう。
あと、前回の記事に書き忘れましたが、micros() の値は約70分でオーバーフローしてゼロに戻るので何か対策が必要になりそうで心配になります。でもよく考えたら、符号無し整数間の引き算なのでオーバーフローをまたいで計算しても大丈夫でした。
以下、入力回路を変えた場合の結果を見て行きます。
◆抵抗入力
前の記事のArduino NANO でやったのと同じで、一番簡単な回路です。
・回路図

I/Oピンはいっぱいありますが、とりあえず D32 ピンを使いました。なおこの回路図は モジュールとして ESP32 DEVKITV1を使った状態です。トランスの出力はP-Pで±20V出ますが、CPU内部の保護抵抗で0-3.3Vにクランプされます。
C1はノイズ対策用で、R1と組み合わせて時定数 1msとしてみました。
・入力電圧波形

保護ダイオードのVfの分だけ外側の電圧でクランプされています。
・測定結果(シリアルモニタで観察)

交流の1サイクル毎にその周期の値、つまり20000付近の値が出力されるはずなのですが、ゼロと10000付近の値しか出てこないので全然ダメです。
オシロの波形を見ると判りますが、入力電圧が変化するのに1msもかかっているので、スレッショルド電圧付近で もたもた しているうちに割り込みが何度も掛かってしまうのだと思います。ちなみに NANO (ATmega328) でこのような問題が起きなかったのは 、入力がシュミットトリガ回路になっているからだと思います。
◆トランジスタ入力
入力波形の遷移速度を早くすれば良さそうなので、トランジスタのバッファを入れてみました。
・トランジスタ入力バッファ回路

D1は、ベース電圧が大きくマイナスになってベース逆耐圧を超えないように入れています。
これでいけるのではと思ったのですが、結果はダメでした。ちょっとくらい増幅しても非飽和でアクティブな期間はあるので、論理が確定しないタイミングが残るということだと思います。ESP32 の I/O クロックは 80MHz なのでこれを上回る速度でスイッチングさせないと危険、ということだと思います。
◆シュミットトリガ入力
仕方が無いので74HC14を使い、シュミットトリガ入力にしました。
流石にここまでやれば問題解決して、きっちり電源周期の測定が出来るようになりました。
D1とD2 にはショットキバリアダイオードを使います。74HC14 の中にもクランプダイオードが入っているので D1,D2 は無くても良さそうなものですが、これを入れないと誤検知が発生しました。高速なオシロで見ると波形立ち上がり部に波形割れが発生していたので、これが原因だと思います。たぶん飽和したダイオードが逆回復する時に非線形な挙動を起こしているのだと思います。ちなみに D1,D2 にシリコンダイオードを使ってもダメだったので逆回復時間の影響と考えて間違い無いと思います。これって、ロジックの専門家なら常識なのかも知れませんが、私は初めて経験しました。
・測定結果

20000付近の値が出力されるようになって、やっとまともな測定結果が出るようになりました。
このグラフは電源の1サイクル毎の周期の測定結果を表わしていますが、そのバラツキは約6μs程度に収まっています。ATmega328 では micros() の仕様から 4μステップの値しか得られませんでしたが、ESP32 では 1μs ステップの値が得られるので分解能の点で有利になります。
・回路の外観

74HC14を使うとブレッドボードのピンをいっぱい消費するのが嫌だったんです。
◆まとめ
出来れば74HC14 は使いたくなかったのですが、仕方無いですね。他の手として、トランジスタでシュミットトリガ回路を作れば面白そうですが、そんなことやっているより話を先に進めた方が良さそうです。
Arduino UNO などで使われているCPUのATmega328Pはシュミットトリガ入力になっているので今回の記事のような苦労はしなくても良い訳で、改めて使い易さを再認識した次第です。
ともかくこれでAC電源の周期測定のための回路とプログラムは出来たので、この後はデーターの収集と保存関係のプログラム作りを開始できそうです。保存先としては、無料で使えるデーター可視化サービスの ambient を考えています。ここは昔使ったことがあるので何とかなりそうな気がしているのですが、さてどうなることやらです。
電源周波数測定の話の続きです。前回は Arduino NANO (ATmega328P) を使いましたが 、今回はESP32でやってみます。ただ、簡単に出来ると思っていたのに思わぬ苦戦を強いられました。
◆電源周期の周期の測定方法
前の記事では、電源の周期測定の方法として micros() の値を参照する方法と、タイマーカウンタを使う二つの測定方法を試しました。タイマーカウンタを使った方が精度が高い測定が出来るのですが、残念ながらESP32で同じことをやる方法が判りません。仕方が無いので micros() の値を使う方法でやることにしました。
◆プログラム
プログラムは以下の通りです
// AC period measurment ESP32電源の1周期毎に割り込みを掛け、micros() の値から周期の時間を求め、その値をシリアルに出力するようになっています。つまり50Hzなら1秒間に50回、結果を出力します。
// (割り込みの排他制御は省略している)
#define AC_pin 32 // 信号入力ピン
volatile uint32_t period; // ACの周期
volatile boolean flag;
void IRAM_ATTR acIrq() { // ピン割込み処理(排他制御は省略)
static uint32_t lastMicros;
uint32_t x;
x = micros(); // microsの値を取得
period = x - lastMicros; // 周期の値を計算
lastMicros = x; // save for next time
flag = true;
}
void setup() {
Serial.begin(115200);
pinMode(AC_pin, INPUT);
attachInterrupt(AC_pin, acIrq, FALLING);
}
void loop() {
while (flag == false) { // フラグが立っていたら
}
flag = false;
Serial.println(period); // 周期の値を出力
}
セマフォやミューテックスを使った排他制御を行うべきなんでしょうが、正しいやり方が判らなかったので、今回は省略しています。でもアクセスするタイミングは固定で競合は起こらないはずなので、このままでも良い気もしますが、どうなんでしょう。
あと、前回の記事に書き忘れましたが、micros() の値は約70分でオーバーフローしてゼロに戻るので何か対策が必要になりそうで心配になります。でもよく考えたら、符号無し整数間の引き算なのでオーバーフローをまたいで計算しても大丈夫でした。
以下、入力回路を変えた場合の結果を見て行きます。
◆抵抗入力
前の記事のArduino NANO でやったのと同じで、一番簡単な回路です。
・回路図

I/Oピンはいっぱいありますが、とりあえず D32 ピンを使いました。なおこの回路図は モジュールとして ESP32 DEVKITV1を使った状態です。トランスの出力はP-Pで±20V出ますが、CPU内部の保護抵抗で0-3.3Vにクランプされます。
C1はノイズ対策用で、R1と組み合わせて時定数 1msとしてみました。
・入力電圧波形

保護ダイオードのVfの分だけ外側の電圧でクランプされています。
・測定結果(シリアルモニタで観察)

交流の1サイクル毎にその周期の値、つまり20000付近の値が出力されるはずなのですが、ゼロと10000付近の値しか出てこないので全然ダメです。
オシロの波形を見ると判りますが、入力電圧が変化するのに1msもかかっているので、スレッショルド電圧付近で もたもた しているうちに割り込みが何度も掛かってしまうのだと思います。ちなみに NANO (ATmega328) でこのような問題が起きなかったのは 、入力がシュミットトリガ回路になっているからだと思います。
◆トランジスタ入力
入力波形の遷移速度を早くすれば良さそうなので、トランジスタのバッファを入れてみました。
・トランジスタ入力バッファ回路

D1は、ベース電圧が大きくマイナスになってベース逆耐圧を超えないように入れています。
これでいけるのではと思ったのですが、結果はダメでした。ちょっとくらい増幅しても非飽和でアクティブな期間はあるので、論理が確定しないタイミングが残るということだと思います。ESP32 の I/O クロックは 80MHz なのでこれを上回る速度でスイッチングさせないと危険、ということだと思います。
◆シュミットトリガ入力
仕方が無いので74HC14を使い、シュミットトリガ入力にしました。

流石にここまでやれば問題解決して、きっちり電源周期の測定が出来るようになりました。
D1とD2 にはショットキバリアダイオードを使います。74HC14 の中にもクランプダイオードが入っているので D1,D2 は無くても良さそうなものですが、これを入れないと誤検知が発生しました。高速なオシロで見ると波形立ち上がり部に波形割れが発生していたので、これが原因だと思います。たぶん飽和したダイオードが逆回復する時に非線形な挙動を起こしているのだと思います。ちなみに D1,D2 にシリコンダイオードを使ってもダメだったので逆回復時間の影響と考えて間違い無いと思います。これって、ロジックの専門家なら常識なのかも知れませんが、私は初めて経験しました。
・測定結果

20000付近の値が出力されるようになって、やっとまともな測定結果が出るようになりました。
このグラフは電源の1サイクル毎の周期の測定結果を表わしていますが、そのバラツキは約6μs程度に収まっています。ATmega328 では micros() の仕様から 4μステップの値しか得られませんでしたが、ESP32 では 1μs ステップの値が得られるので分解能の点で有利になります。
・回路の外観

74HC14を使うとブレッドボードのピンをいっぱい消費するのが嫌だったんです。
◆まとめ
出来れば74HC14 は使いたくなかったのですが、仕方無いですね。他の手として、トランジスタでシュミットトリガ回路を作れば面白そうですが、そんなことやっているより話を先に進めた方が良さそうです。
Arduino UNO などで使われているCPUのATmega328Pはシュミットトリガ入力になっているので今回の記事のような苦労はしなくても良い訳で、改めて使い易さを再認識した次第です。
ともかくこれでAC電源の周期測定のための回路とプログラムは出来たので、この後はデーターの収集と保存関係のプログラム作りを開始できそうです。保存先としては、無料で使えるデーター可視化サービスの ambient を考えています。ここは昔使ったことがあるので何とかなりそうな気がしているのですが、さてどうなることやらです。