外部のADCを利用せず、スイッチをつけて内部のADCを利用するというアプローチが以下にありました。
TINKERING WITH TECHNOLOGY
WHEN YOU NEED MULTIPLE ANALOG INPUTS FOR YOUR ESP8266 APPLICATION
なるほどーです。FSA3157 というスイッチをつけて、GPIO ピンからデジタルでHigh Low させることによりスイッチを動作させるものです。なんか日本語変ですが。上記ブログと、データシート見たほうがわかりやすいです。
FarChild Semiconductor FSA3157
datasheet
これで、ADCのソースを2つから選べるようになるということですね。
3つのソースを2つのGPIOで制御する場合は、以下のICを。
FSA3357
価格的には、どちらも安いので候補ですね。ハードの世界はいろいろなICがあって、面白いですね。
配置した感じでは、大きさがほとんど変わらないので、8pin の 3チャンネル切り替えられる FSA3357 を導入することに。前回検討していた、ダイオードを挟む方法は、正確に抵抗値を読みたいので、適しませんでした。
AliExpress にて、10個1083円なり。1個110円くらいです。
これを組み込んで、電源電圧他、2つのアナログ値を取れるようにして、1つはCDSの照度に使い、あと1つはPINを出しておく形にしておきます。
抵抗分圧して、3.3v をいったん、0.5VにしてADC で値を読ませた後に、元の値に戻しています。wifi eink のコードにあったやつです。まだ、ものがないのでS1,S2 の切り替えコードは書いていませんが、抵抗分圧して、内臓のADC で1V 以上の抵抗を読めるようにテストしてみました。
/* ADC Read Sample Arduino IDE 1.6.5 Hourly Build 2015/06/12 03:13 esp8266 by ESP8266 Community version 1.6.5 Hourly Build 2015/06/12 JunkHack 2015.10.10 --- ex Serial output. Blink Count: 40 ADC mv: 3319 ADC mv: 3313 Blink Count: 41 ADC mv: 3319 ADC mv: 3313 :: */ #include <ESP8266WiFi.h> int ledState = LOW; unsigned long previousMillis = 0; const long interval = 1000; void setup() { pinMode(BUILTIN_LED, OUTPUT); Serial.begin(115200); delay(10); } int value = 0; int count = 0; int adc = 0; int batteryMeasMv = -1; void loop() { delay(interval); ++value; unsigned long currentMillis = millis(); if(currentMillis - previousMillis >= interval) { previousMillis = currentMillis; if (ledState == LOW){ ledState = HIGH; // Note that this switches the LED *off* } else { ledState = LOW; // Note that this switches the LED *on* digitalWrite(BUILTIN_LED, ledState); delay(1); count += 1; Serial.print("Blink Count: "); Serial.println(count); } } //Battery voltage is divided by an 5.6K/1K resistor divider. //ADC: 1024 = 1V adc = analogRead(A0); batteryMeasMv=(adc*10020*6.6)/10000; // ^^^^^To correct an error in the resistance value Serial.print("ADC mv: "); delay(1); Serial.println(batteryMeasMv); }
テスターで実測値に近くなるよう係数を補正しています。
自分自身の電圧をグラフに投げて、長期DeepSpeel の電圧降下具合を記録できそうです。
手抜きですが、以下のようなコードになる感じですかね。
/* ADC Read Sample. Fairchild Semiconductor FSA3357 adc Select. Arduino IDE 1.6.5 Hourly Build 2015/06/12 03:13 esp8266 by ESP8266 Community version 1.6.5 Hourly Build 2015/06/12 JunkHack 2015.10.10 --- ex Serial output. Blink Count: 1 >adc1(B0) ADC mv: 3280 >adc2(B1) ADC mv: 3273 >adc3(B2) ADC mv: 3293 >adc off :: */ #include <ESP8266WiFi.h> int ledState = LOW; unsigned long previousMillis = 0; const long interval = 1000; //1sec /****************************************************** * Fairchild Semiconductor FSA3357 adc Select. * 0 = No Connection * 1 = B0 to A * 2 = B1 to A * 3 = B2 to A */ const int S1 = 14; // S1 to GPIO Pin const int S2 = 16; // S2 to GPIO Pin void adcset(int port) { pinMode(S1, OUTPUT); pinMode(S2, OUTPUT); switch (port){ case 1: digitalWrite(S1, HIGH); digitalWrite(S2, LOW); Serial.println(">adc1(B0)"); break; case 2: digitalWrite(S1, LOW); digitalWrite(S2, HIGH); Serial.println(">adc2(B1)"); break; case 3: digitalWrite(S1, HIGH); digitalWrite(S2, HIGH); Serial.println(">adc3(B2)"); break; case 0: digitalWrite(S1, LOW); digitalWrite(S2, LOW); Serial.println(">adc off"); break; } } /****************************************************** * */ void setup() { pinMode(BUILTIN_LED, OUTPUT); Serial.begin(115200); delay(10); } int value = 0; int count = 0; int adc = 0; int batteryMeasMv = -1; /****************************************************** * */ void loop() { adcset(0); delay(4000); delay(interval); ++value; unsigned long currentMillis = millis(); if(currentMillis - previousMillis >= interval) { previousMillis = currentMillis; if (ledState == LOW){ ledState = HIGH; // Note that this switches the LED *off* } else { ledState = LOW; // Note that this switches the LED *on* digitalWrite(BUILTIN_LED, ledState); delay(1); count += 1; Serial.print("Blink Count: "); Serial.println(count); } } // Select ADC source. adcset(1); delay(5000); //Battery voltage is divided by an 5.6K/1K resistor divider. //ADC: 1024 = 1V adc = analogRead(A0); batteryMeasMv=(adc*10020*6.6)/10000; // ^^^^^To correct an error in the resistance value Serial.print("ADC mv: "); delay(1); Serial.println(batteryMeasMv); adcset(2); delay(5000); adc = analogRead(A0); batteryMeasMv=(adc*10020*6.6)/10000; Serial.print("ADC mv: "); delay(1); Serial.println(batteryMeasMv); adcset(3); delay(5000); adc = analogRead(A0); batteryMeasMv=(adc*10020*6.6)/10000; Serial.print("ADC mv: "); delay(1); Serial.println(batteryMeasMv); }
さて、ぼちぼちと回路図書いてみます。
書いて、PCB上に配置してみました。あと、温度湿度センサーを載せればOKとします。
リチウムの電池からの電圧と、バックブーストで作られた後の電圧を計測して、あとは照度センサーからのADCを計測したら3チャンネル使い切りました。
で、最後にDHT-22 を裏側に乗せました。前回作ったやつと同じように、ESP8266 の上に載る感じ。
UART のPIN配列は、ブレッドボードに挿したときに上からLEDが見えるに配列を逆にしました。あと、UART からの信号のDTRを一工夫して、リセットを押さなくても、書き込みモードになるように回路を組んでおしまいです。
他、何か忘れているような気もしますが、最後の点検でチェックしていきます。
現時点で、忘れているもの。
・メインスイッチ
・CDS の調整用、半固定抵抗
・WEB アクセスのLEDと、WiFi アクセスのLED (をつけるかどうか)
・EN Pin の配線
最後に少し、プログラムを改良したのをメモ。まれに、ADC値が変なので、10回の平均値を出しています。ESP12でテストしているので、ESP13 だとどういう動きになるかは、実際にモノが着てからテスト。
/* ADC Read Sample2. Fairchild Semiconductor FSA3357 adc Select. Arduino IDE 1.6.5 Hourly Build 2015/06/12 03:13 esp8266 by ESP8266 Community version 1.6.5 Hourly Build 2015/06/12 JunkHack 2015.10.11 --- ex Serial output. >adc3(B2) ADC3 mv/10: 0 : 476 1 : 475 2 : 474 3 : 474 4 : 474 5 : 474 6 : 474 7 : 474 8 : 474 9 : 474 3139 >adc off :: */ #include <ESP8266WiFi.h> int ledState = LOW; unsigned long previousMillis = 0; const long interval = 200; //1sec /****************************************************** * */ void setup() { pinMode(BUILTIN_LED, OUTPUT); Serial.begin(115200); delay(10); } int value = 0; int count = 0; /****************************************************** * */ void loop() { // Select ADC source off. adcset(0); delay(interval); ++value; unsigned long currentMillis = millis(); if(currentMillis - previousMillis >= interval) { previousMillis = currentMillis; if (ledState == LOW){ ledState = HIGH; // Note that this switches the LED *off* } else { ledState = LOW; // Note that this switches the LED *on* digitalWrite(BUILTIN_LED, ledState); delay(1); count += 1; Serial.print("Blink Count: "); Serial.println(count); } } // Select ADC source. adcset(1); delay(interval); Serial.print("ADC1 mv/10: "); Serial.println(getMv()); adcset(2); delay(interval); Serial.print("ADC2 mv/10: "); Serial.println(getMv()); adcset(3); delay(interval); Serial.print("ADC3 mv/10: "); Serial.println(getMv()); } /****************************************************** * Fairchild Semiconductor FSA3357 adc Select. * 0 = No Connection * 1 = B0 to A * 2 = B1 to A * 3 = B2 to A */ const int S1 = 14; // S1 to GPIO Pin const int S2 = 16; // S2 to GPIO Pin void adcset(int port) { pinMode(S1, OUTPUT); pinMode(S2, OUTPUT); switch (port){ case 1: digitalWrite(S1, HIGH); delay(10); digitalWrite(S2, LOW); Serial.println(">adc1(B0)"); break; case 2: digitalWrite(S1, LOW); delay(10); digitalWrite(S2, HIGH); Serial.println(">adc2(B1)"); break; case 3: digitalWrite(S1, HIGH); delay(10); digitalWrite(S2, HIGH); Serial.println(">adc3(B2)"); break; case 0: digitalWrite(S1, LOW); delay(10); digitalWrite(S2, LOW); Serial.println(">adc off"); break; } } /****************************************************** * It reads the 10 times of the average value. */ int getMv(){ // correct an error in the resistance value. const int CORRECT = 10030; int mv = -1; int i; int adc = 0; for (i = 0; i<10; i++ ){ adc = 0; //Battery voltage is divided by an 5.6K/1K resistor divider. //ADC: 1024 = 1V adc = analogRead(A0); //delay(10); // Serial.print(i); // Serial.print(" : "); // Serial.println(adc); mv += (adc*CORRECT*6.6)/10000; // ^^^^^To correct an error in the resistance value } mv = mv / 10; return mv; }