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

ESP8266 でADC 増設その2

前回、ADC のアナログ入力を増設する方法として以下を調査していました。

ESP8266 でADC 増設するには?

作者に聞いてみたところ、Version2のICには、MAX11609EEE+ を使っているとの事。16ピンQSOP で、DigiKey で336円くらいのものです。

MAX11609EEE+

datasheet

データシートを見てみると、これは8チャンネルあるようです。通信は、I2Cでいけるようです。

MAX11609EEE

とりあえず、8チャンネルもいらないので、4チャンネルのMAX11607 というのを試しに使ってみようかと思っています。

Aliexpress で価格を調査すると、4ch8ch も値段がほとんど変わらないようです。1個400円ちょい。

 

他にも、I2C で ADC はいろいろあるようで、たとえば、TIの4チャンネルなんかの ADS7924IRTER は供給量も多いようです。

 

標準で付いている、ADC も工夫すればGPIO 分のアナログリードができるようなのでそれを試してみてから考えたいと思います。

ダイオードをつけて、計測前にGPIO x ピンをHigh にしてADC 値を読むという原理です。 Lua のサンプルコードでそんなロジックが書いてありました。なるほどーですね。

 

で、手持ちのダイオードがなぜか見つからず、ジャンクのマザーボードからチップダイオードを採取してユニバーサル基板につけたところまで今、作業が進んでいます。

ESP13 と BackBoost のPCBを作成中

Eagle の勉強と、PCB をプリントに出すため、まずはお手ごろな素材を元に勉強中。

 

コンセプト

・Lion の1セルに、充電ができて、過充電、過放電保護がある

・充電は、マイクロUSB からできる

・1セルから3.3v を効率よく、安定して作るため、backboost 回路を入れる

・自分が持っている、UART のシリアル変換を直接挿せるようにする

・ケースに入れる都合上、幅を2cm x 6.5cm 未満とする

・UART の PIN は自動的にリセットがかかるよう、DTR からの信号を処理する回路を埋め込む

・バッテリーや、3.3V 出力など後に計測したいので、PINを出しておく

・DeepSleep は必ず使うので、配線しておく

・ブレッドボードに挿せる様、PIN を出しておく

・なるべく安くする

・レゴブロック風のものをジョイントすると機能が拡張できるようにしたい。

 

といういうな、お題を掲げて作っています。

まだ、途中ですが、以下のようなものができてきました。

1

安くあげるため、USB と充電回路(保護付き)は既成のモジュールを使うことに、90円くらいのものです。

この基板をノギスや、スキャナで取ってeagle のライブラリを作成。ここが面倒でした。また、ESP12Eと、ESP13(WROOM-02)と大きさを比べると、ESP13の方が小さく、組み込みやすそうです。

2

今回の目玉である、バックブースト回路は表に載せました。ブレッドボードに指せば裏側に回る予定。真ん中のパッド部分はスルーホールを横に作って、裏側の胴箔に熱伝統させる予定です。

3

裏面に部品が回せるのを知ったので、(Mirrorすれば良いだけですが、、、)上記のような配置にしました。まだ配線は仮なので、これから変わります。

4

左には、UARTのPINを直接させるようメスピンヘッダーをつけます。順番は逆配列にしないとブレッドボードに挿した時LEDとか見えませんので、後に変更予定です。

 

5

回路図は、離れたところにある配線をどうやるのかわからず、あれこれググりました。これはラベルでやるようですが、いまいち良くわかっていません。とりあず、つなぎたいところに、配線を伸ばしNAMEをつけて、ラベルみたいなのは、シンボルがあったので、それを使っています。supply2.lbr というのにありました。たぶんもっといいやり方があるのでしょうが、良くわかりません。機能は満たしているので、今はこれでよしとします。

 

先人たちの回路図を見ると、機能ごとに分離して、見やすくする工夫をしているようです。なので上記のような感じにしてみました。その後、あれこれと思案し、以下のようになっています。まだ途中。

 6

ブレッドボードに挿すPINは最低限のものにしたけれども、案外空きスペースがなくなって来ているので、複雑な回路だと2階建てにする感じになりそう。

 

▼まとめ

・回路図は見やすくするため、機能ごとにわける。

・離れたところを配線するため、NAMEを使い、ラベルをつける

・ラベルは回路図だけに出るライブラリ(supply2.lbr )があるのでそれを使う

・裏面に部品を配置するには、Mirror を使う。

・実際の部品で仕様がわからないものは、スキャニングして大きさを算出。ノギスで実物を計測。

・独自ライブラリを作るには、3ステップ。

New > Library

Package 作成(左から5番目のアイコン)で、PCB基板に実際に付く図形を書く

Simbol 作成で、回路図上で見える図とPINを書く

Device 作成し、上記を対応づけ。Connect でPIN対応づけできる

・部品の配置の際、ルーラをドキュメントレイヤーに置いておくと便利(Metric ruler のLIB)

 

▼不明なこと

・離れたとこにある配線のやりかた。見やすいラベルを同時付け、対応づけるには?

・ESP13のUARTでリセットを自動的に行う回路。いろいろあるようです。現在3種類のやり方を模索。モノがまだ来ていないので着たら検討。

・ESP13 と ESP12のピンの対応づけ表がほしい。 EN は CHPD で、TOUTは、ADCに対応していると考えればよい?

・ESP13はGNDが2つ増え、合計3つ。なので、PIN数がESP13の18PINに対し、ESP12は、16PINということなのか?

 

▼調査すること

・幅、2cmx長さ5cm、暑さ5mmくらいのお値打ちLIONを探す。

・どっかの記事で、ADCはダイオードをかませば、GPIOのピン数分読めるというような英文記事を見たが、あれは本当か?

ESP8266 でADC 増設するには?

ESPシリーズは、全機種ADC が1ポートなので、アナログ値を読むには何かしら工夫しないといけないのですが、その方法を模索したいと思います。新しい課題です。

 

調査第一段階では、以下のものがあるようです。

ESP8266 Analog Input Expander Library for MCP3021 A/D Conveters

https://github.com/AllAboutEE/ESP8266-MCP3021-Library

これは、tindie で作っているヒトがいるようです。

ESP8266 Analog Inputs Expander (Version 2)

https://www.tindie.com/products/AllAboutEE/esp8266-analog-inputs-expander/

初期リリース版は、4つのMicrochip MCP3021を使っているようですが、Version2では、1ICとなっているようです。このIC は4チャンネルのやつだと思うのですが、型番がよくわかりません。MCP3304 か、MCP3008のTSSOP パッケージかな?ちょっとお尋ね申すことに。

 

とりあえず、回路は簡単そうなので部品を入手して模索してみたいと思います。