MQ-3を使った簡易アルコールチェッカーの測定精度を上げる -ESP32のADCについて-

電子工作

ADCの応用編

後編で測定精度の向上を試してみましたが、M5StickCのマイコンであるESP32の理解を深めるためにさらなる測定精度向上を目指してみました。

アナログ電圧の測定精度を向上させるポイントはADCの変換精度になりますが、ESP32の設計元であるESPRESSIFのAPIリファレンスにその解があります。
V4.4.3のリファレンスには以下の記載があります。

表の下に記載の通り、eFuse ADCキャリブレーションビットを備えたボードの場合,
esp_adc_cal_raw_to_voltage()を使用して、個々のICのばらつきも考慮したキャリブレーションされた電圧(mV)が取得できるのです。

よって、-線形性の改善-で使用したような 式(1)を使用してデータを算出する必要はありません。なんとも便利ですね。
ということで以下にeFuse の使い方を説明します。

eFuseの使い方

上述のAPIリファレンスページのCalibration Valuesのセクションを参照すると、2018年第1週以降に生産されたESP32-D0WD と ESP32-D0WDQ6の個々のチップには、ばらつきを考慮したキャリブレーション後の電圧値がeFuse Vrefとして書き込まれているとのことですがその値を確認するためには、esptoolをインストールしたPC環境でデバイスを接続し以下のコマンドを打ちます。

$IDF_PATH/components/esptool_py/esptool/espefuse.py –port /dev/ttyUSB0 adc_info

私の環境では次のようになり、測定したデバイス固有のVrefは1093mVと分かります。
サンプルプログラムを参照して、今回のアルコールチェッカーのプログラミングに合わせるために、

・ADC1でサポートされるGPIO36を使用する
・アッテネータ値は6dBに設定する
・分解能は12BITに設定する
・Vrefが保存されていないチップ用のリファレンス電圧を1100mVに設定する

を行うには、次のようになります。

esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_6, ADC_WIDTH_BIT_12, 1100, &adcChar)

GPIO36の電圧値の読み取りは、

esp_adc_cal_get_voltage(ADC_CHANNEL_0, &adcChar, &gas_value);

このVrefを活用してプログラミングすればESP32Chip個々のばらつきを抑えて、今回のアルコールセンサー以外にもCO2センサーなど複数種類のアナログガスセンサーがESP32DEVKITやM5STSCK,M5STICKで使用でき色々なガス濃度を測定してみると面白そうです。

参考: Vrefを使用したプログラム

参考に上で述べた、Vrefが保存されていないチップ用のリファレンス電圧を1100mVに設定したプログラムをご紹介します。

//alcohol simple checker
//Arduino 1.8.15 , Board manager M5Stack Arduino M5stick-C 1.0.9 , libraray m5stickC 0.2.8
//Waveshare MQ-3 gas Sensor , https://www.waveshare.com/mq-3-gas-sensor.htm
#include "driver/adc.h" 
#include "esp_adc_cal.h"
#include <M5StickC.h>
int gas_din=26; // M5stick-C IO26 Degital Input ,connect to the Dout terminal 未使用
int gas_ain=36; // M5stick-C IO36 Analog Input ,connect to the Aout terminal
int ad_value;
float gas_value;
float gas_value_ave;
float gas_value_sum;
int avenum=10; //平均値取得用の測定回数
float ATT=(3.24+1.77)/1.77;//抵抗分圧
float VTH=2000;// mV アルコール検知のスレッシュ電圧 2.0 - 2.5V 位で設定
esp_adc_cal_characteristics_t adcChar;
void setup()
{
  M5.begin();
  Serial.begin(115200);
  pinMode(gas_din,INPUT);
  pinMode(gas_ain,ANALOG);
  adc_gpio_init(ADC_UNIT_1, ADC_CHANNEL_0);  // GPIO 36 = CHANNEL 0
  adc1_config_width(ADC_WIDTH_BIT_12);
  adc1_config_channel_atten(ADC1_CHANNEL_0, ADC_ATTEN_DB_6);
  esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_6, ADC_WIDTH_BIT_12, 1100, &adcChar);
  M5.Lcd.setRotation(3);
  M5.Lcd.setTextSize(1);
  M5.Lcd.fillScreen(BLACK); 
  M5.Lcd.setTextColor(WHITE, BLACK);
  M5.Lcd.setCursor(10, 0);
  M5.Lcd.print("Alcohol simple checker");
}
void loop()
{
  uint32_t gas_value;
  gas_value_ave = 0;
  gas_value_sum = 0;
  for (int i=0 ; i<avenum ;i++)
  {
    esp_adc_cal_get_voltage(ADC_CHANNEL_0, &adcChar, &gas_value);
    gas_value_sum = gas_value_sum + gas_value;
  }
    gas_value_ave = gas_value_sum / avenum;
    Serial.println("Gas leakage");
    Serial.print("gas_value:");
    Serial.print(gas_value_ave);
    Serial.println("mV");
    if (gas_value_ave * ATT > VTH) {
    M5.Lcd.setTextColor(RED, BLACK);
    }
    M5.Lcd.setTextSize(2);
    M5.Lcd.setCursor(10, 30);
    M5.Lcd.printf("%.0fmV", gas_value_ave * ATT);
    M5.Lcd.setTextColor(WHITE, BLACK);
    delay(500);
}

以上です。

コメント

タイトルとURLをコピーしました