google-site-verification: google3bd66dd162ef54c7.html

ESP8266のアナログリードで嵌る

 久しぶりの更新です。実は、以前に、ESP8266のアナログポートの挙動がおかしい、という記事を書いたのですが、この問題を何とか解決出来ないかいろいろ試していたのですが、どうしてもうまくいかなくて時間だけ経ってしまいました。

 このまま続けても解決出来そうに無い感じなので、ここまでにやってみたことを書いておこうと思います。まあ、頭の整理をしつつ自分へのメモ代わりを兼ねています。

 問題になっている環境は、ESP-WROOM-02 (ESP8266) を Arduino の IDE(1.6.5)で実行した場合で、現象としてはsystem_adc_read(); を高速で繰り返し呼ぶと実行時間が短くなることがあるというものです。ちゃんとAD変換やった結果ならそれでもいいのですが、どうもAD変換を実際にやらないで、単に以前の値を返してきている疑いがあります。

 詳しい現象は以前の記事を見ていただくとして、おっと今回試したのは以前の記事の最後に書いた for ループで回数を指定してAD変換を実行させた場合の話です。

 以下のようなプログラムでテストしました。AD変換がうまくいかない現象の対策として、割り込みを禁止したり、タイミングを調整したりいろいろやったのですが、全部ダメでした。コメントに 対策・・・・ と書いてあるのが試した内容の痕跡です。

◆テストプログラム
/* ESP8622-WROOM-02
* アナログデーターを高速で連続読み取りするテスト
* 2016/10/30 ラジオペンチ
* 最初は良いが、15から35回くらい繰り返すとAD変換しないで
* 値を返してくる場合がある。(実行時間が短い)
*
*/
int dataNN = 0;
int dataN, AdcData;
long SumAdc, SumAdc2;
unsigned long TimeStart, TimeElapsed;

//ESP-WROOM-02でアナログ入力をするための設定
extern "C" { // ADCを使うためのおまじない
#include "user_interface.h"
}

void setup() {
// noInterrupts(); // 対策テスト、割り込み禁止
Serial.begin(115200);
pinMode(13, OUTPUT); // 観察用ポート
loops(); // 自前のloopで実行
}

void loops() { // loop()では無い場所でループ
for (;;) {
dataN = 0; SumAdc = 0; SumAdc2 = 0; // 変数初期化
dataNN++;
digitalWrite(13, HIGH);
//system_timer_reinit(); // ダメ対策 タイマー初期化
wdt_disable(); // ダメ対策 WDT禁止
TimeStart = micros();
for (int i = 0; i < 1058; i++) { // 約100msのループを実行
// __asm__ __volatile__ ("nop"); // 対策 nopでタイミング調整
// __asm__ __volatile__ ("nop");
noInterrupts(); // 対策 割り込み禁止
delayMicroseconds(100); // 対策 delayMicrosecondsでタイミング調整
AdcData = system_adc_read(); // アナログ電圧読み出し
// AdcData = 700; // 固定値代入テスト
// Interrupts(); // 対策 でもこんな関数無かった
// __asm__ __volatile__ ("nop");
// __asm__ __volatile__ ("nop");

SumAdc = SumAdc + AdcData; // ΣXi
SumAdc2 = SumAdc2 + AdcData * AdcData; // ΣXi^2
dataN++; //
}
TimeElapsed = micros() - TimeStart; // ループ通過時間を求める
delay(10); // 対策 シリアル出力前にちょっと待つ
digitalWrite(13, LOW);
Serial.print(dataNN); Serial.print(", "); // 平均値
Serial.print(SumAdc / dataN); Serial.print(", "); // 平均値
Serial.print(sqrt(SumAdc2 / dataN)); Serial.print(", "); // 実効値
Serial.print(TimeElapsed); Serial.print(", "); // 測定時間
Serial.println(dataN); // ループ回数

delay(400); // 適当に待つ
}
}

void loop() {
delay(1); // 対策 意味の無いdelay
}

 どうやってもリセット後ある程度の時間経過後、具体的には数秒以上経つとAD変換の実行時間が短い場合が発生します。裏にデーモンのようなプロセスが走っていてそいつが悪さをしている気がします。

 この現象の対策につきいろいろ検索しているのですが、うまい情報がヒットしません。system_adc_read() の中で何をやっているのか調べた方が早いのかも知れません。

 あるいは、いつまでもやっていてもダメそうなので、外付けのADCを使った方が早道なのかも知れません。んと、これは7月頃に考えていた話で、ちっとも進歩してません。トホ、

ESP8266のWiFi接続の所要時間を調べてみた

 久しぶりにマイコンの話題です。ESP-WROOM-02に入っているチップのESP8266はI/Oピンの数が少ないので使い難い点はありますが、格安で無線LANを通したネット接続が出来るのでとても魅力的です。私のところではまだ意味のある使い方まで出来ていないのですが、少しずつ使いこなしていきたいと思っています。

 ということで、今回はESP8266を無線LANに接続する時の所要時間につき、固定IPアドレスとDHCPサーバーを使った動的なIPアドレス割り当てを行った場合で比較を行ってみました。ESP8266をデーターロガーとして使う場合、できるだけ短時間でネット接続と測定を行い、あとに時間はスリープ状態にすることでトータルの消費電力を減らすことが出来ます。この時、ネット接続に時間がかかるようだと消費電力が思うように減らないことになります。

 実験に使った回路は 以前の記事に掲載した、アナログポートのデーターをWiFiに流しているだけのものですが、かなり時間が経っているので再掲しておきます。

▼回路図
回路図
 何も値が変化しないと面白くないので、デモ用に周囲の明るさをCDSで検出する回路になっています。

 使ったプログラムのソースはこの記事の末尾に掲載しますが、毎回WiFiへの接続を行い、アナログポートの値を読んでAmbientへデーターを送信、その後10秒間のDeep Sleepを行っています。IO16とRSTを接続しているのでDeep Sleep後はリセットがかかるので、毎回WiFi接続から開始するような動作になっています。

ロジアナをつないで測定
ロジアナでタイミングを見る

 以下測定結果です。なお波形は上からリセット(Pin15), IO13(Pin5)、シリアルデーターTXD(Pin12)です。IO13はプログラムの動作中にソフトでLEDを点灯させている信号です。

▼固定IPアドレスの場合
固定IP
 約10秒周期でプログラムが動いている様子を示しています。なお、各周期の先頭にリセットパルスが存在しているはずですが、パルス幅が小さすぎてキャプチャ出来ていません。

▼固定IPアドレスの場合の波形詳細
固定IPの場合のタイミング詳細
 中央の波形がHighの期間がプログラムが動いている状態です。リセットがかかってから約0.7秒間は内部の初期化などをやっているのでしょう、この間ユーザーのプログラムは動きません。この期間に下の波形(TXD)に変化があるのは初期化などのメッセージが出ているためです。

 プログラムの動作時間(IO13のONの期間)は約0.37秒になっています。リセット後の初期化期間を含めると、約1秒間はESP8266がフルに動いていることになります。

▼DHCPの場合
DHCPの時
 プログラムが動いている時間が大幅に長くなり、3秒から10秒近くかかっています。DHCPサーバーにIPアドレスの割り当て要求を行い、アドレスが確定するのに多くの時間が必要なのだと思います。こんなに時間がかかると電池駆動の場合の連続稼働時間に与える影響は大きいはずです。

◆まとめ
 消費電力を出来るだけ減らす必要がある場合は、固定IPアドレスで使った方が良さそうです。

 リセット以降の消費電力(消費電流)波形を測定すればよかったのですが、アナログオシロでは苦しそうなので測定していません。

 ちなみに使ったこちらのLAN環境は以下の通りで、接続先はAmbientです。
  ・回線:VDHL、ルーター:Aterm BL150HV (NEC)、Wifi AP:WHR-G301N(バッファロー)

参考にさせていただいたサイト
ESP8266 起動から Wi-Fi 接続までの時間を実測してみた (FIRMLOGICS)

▼使ったスケッチ (これ以外に関連ライブラリが必要です)
/*******************************************************************************
Example 09c: 湿度センサ HDC1000 [Ambient対応版]
Copyright (c) 2016 Wataru KUNINO
********************************************************************************
本サンプルで使用するクラウドサービスAmbient用の設定の確認
http://ambidata.io/ch/channels.html
********************************************************************************
自分の環境用にカストマイズ。 by ラジオペンチ 2016/10/15
・UDPアップロード機能を削除。
・CDSで測った明るさデーターをADCで取り込んで60秒間隔でAmbientにアップロード
*/

#include <ESP8266WiFi.h> // ESP8266用ライブラリ
#include <WiFiUdp.h> // UDP通信を行うライブラリ
#include "Ambient.h" // Ambient用のライブラリの組み込み

//ESP-WROOM-02でアナログ入力をするための設定
extern "C" {
#include "user_interface.h"
}

#define PIN_LED 13 // IO 13(5番ピン)にLEDを接続する
#define SSID "xxxxxxxxxxxxxxx" // 無線LANアクセスポイントのSSID
#define PASS "xxxxxxxxxxxxxxx" // パスワード

#define AmbientChannelId xxx // チャネルID(整数)
#define AmbientWriteKey "xxxxxxxxxxxxxxxx" // ライトキー(16桁の16進数)
// #define SLEEP_P 60*1000000 // スリープ時間 60秒
#define SLEEP_P 10000000 // スリープ時間 10秒

Ambient ambient;
WiFiClient client;

void setup() { // 起動時に一度だけ実行する関数
int waiting = 0; // アクセスポイント接続待ち用

pinMode(PIN_LED, OUTPUT);
digitalWrite(PIN_LED, HIGH); // LED点灯


Serial.begin(115200); // 動作確認のためのシリアル出力開始
Serial.println();
Serial.println("Example 09C HUM->Amb"); // 「Example 09」をシリアル出力表示
WiFi.mode(WIFI_STA); // 無線LANをSTAモードに設定

// 固定IPアドレスの設定 IP Address, Gate way, Subnet mask の順に指定
WiFi.config(IPAddress(192, 168, 0, 27), IPAddress(192, 168, 0, 1), IPAddress(255, 255, 255, 0));

WiFi.begin(SSID, PASS); // 無線LANアクセスポイントへ接続
while (WiFi.status() != WL_CONNECTED) { // 接続に成功するまで待つ
delay(100); // 待ち時間処理
waiting++; // 待ち時間カウンタを1加算する
if (waiting % 10 == 0)Serial.print('.'); // 進捗表示
if (waiting > 300) sleep(); // 300回(30秒)を過ぎたらスリープ
}
Serial.println(WiFi.localIP()); // 本機のIPアドレスをシリアル出力
ambient.begin(AmbientChannelId, AmbientWriteKey, &client); // Ambient開始
}

void loop() {
float cdsVolt; // CDS電圧の測定値
char s[6]; // 文字列操作バッファ

cdsVolt = (float) system_adc_read(); // CDSの電圧をアナログポートから読む
dtostrf(cdsVolt, 6, 1, s); // 温度を文字列に変換
ambient.set(1, s); // Ambient(データ1)へCDSの電圧を送信
ambient.send(); // Ambient送信の終了(実際に送信する)
Serial.println(cdsVolt);
digitalWrite(PIN_LED, LOW);
sleep();
}

void sleep() {
delay(200); // 送信待ち時間
ESP.deepSleep(SLEEP_P, WAKE_RF_DEFAULT); // スリープモードへ移行する
while (1) { // 繰り返し処理
delay(100); // 100msの待ち時間処理
} // 繰り返し中にスリープへ移行
}

 47行目をコメントアウトすることでDHCPによるIPアドレス割り当てになります。
カレンダー
09 | 2016/10 | 11
- - - - - - 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 - - - - -
プロフィール

ラジオペンチ

Author:ラジオペンチ
電子工作を中心としたブログです。たまに近所(東京都稲城市)の話題など。60過ぎて視力や器用さの衰えを感じつつ日々挑戦!
コメントを入れる時にメールアドレスの記入は不要です。なお、非公開コメントは受け付けていません。

記事が気に入ったらクリックを!
最新記事
カテゴリ
最新コメント
リンク
FC2カウンター
検索フォーム
月別アーカイブ
RSSリンクの表示
QRコード
QRコード