ESP8266 でADC 増設その3

外部のADCを利用せず、スイッチをつけて内部のADCを利用するというアプローチが以下にありました。

TINKERING WITH TECHNOLOGY

WHEN YOU NEED MULTIPLE ANALOG INPUTS FOR YOUR ESP8266 APPLICATION

なるほどーです。FSA3157 というスイッチをつけて、GPIO ピンからデジタルでHigh Low させることによりスイッチを動作させるものです。なんか日本語変ですが。上記ブログと、データシート見たほうがわかりやすいです。

FarChild Semiconductor FSA3157
datasheet

 www_farnell_com_datasheets_690558_pdf

 

これで、ADCのソースを2つから選べるようになるということですね。

3つのソースを2つのGPIOで制御する場合は、以下のICを。

FSA3357

datasheet

価格的には、どちらも安いので候補ですね。ハードの世界はいろいろなICがあって、面白いですね。

配置した感じでは、大きさがほとんど変わらないので、8pin の 3チャンネル切り替えられる FSA3357 を導入することに。前回検討していた、ダイオードを挟む方法は、正確に抵抗値を読みたいので、適しませんでした。

aaa

AliExpress にて、10個1083円なり。1個110円くらいです。

これを組み込んで、電源電圧他、2つのアナログ値を取れるようにして、1つはCDSの照度に使い、あと1つはPINを出しておく形にしておきます。

xxx

 

抵抗分圧して、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とします。

7

リチウムの電池からの電圧と、バックブーストで作られた後の電圧を計測して、あとは照度センサーからのADCを計測したら3チャンネル使い切りました。

 

で、最後にDHT-22 を裏側に乗せました。前回作ったやつと同じように、ESP8266 の上に載る感じ。

 

datasheets_sensors_temperature_dht22_pdf

8

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;
}