ESP32マウス(shota)マウス自作研修

ESP32マウスPart.31 ADCでバッテリ電圧を計測

ESP32マウス(shota)
EspecialのADC変換結果

こんにちは、shotaです。

前回の記事ではESP-IDFのADCサンプルを動かし、コードを読み解きました。

今回はADC機能を使って、ESP32マウスEspecialのバッテリ電圧を計測します。

初めてのオリジナルマウス Especial

Especial用のサンプルプログラムを公開しました。

EspeicalのプログラムはGitHubに公開してます。
そして今回、そのプログラムにブログで作成したサンプルプログラム(hello_world、Lチカ)を追加しました。

especial/examples at master · ShotaAk/especial
ESP32を搭載したマイクロマウスのプログラム. Contribute to ShotaAk/especial development by creating an account on GitHub.

マウスのプログラムとは別にサンプルを用意しておくと、各機能(LEDやモータやエンコーダ)単体でデバックできます。

プログラムを書く前の下準備

プログラムを書く前に、Especialの回路図やESP32モジュールのデータシートを読み、情報をあつめます。

回路設計時に各ピンの機能を決めていますが、説明のために再度1つずつ確認していきます。

Especialの回路図を確認

まずはじめに、Especialの回路図を確認しましょう。

↓Especialの回路図はこちらです。
especial.pdf

また、電源回路についてのブログ記事はこちらです。

shotaのマイクロマウス研修14[回路設計② 電源回路]

今回必要なところは、バッテリ電圧監視回路です。

Especial-バッテリ電圧監視回路

Especial – AN_VCCの接続先

Especialでは、R2、R3の抵抗分圧回路でバッテリ電圧を1/2にし、ESP32のSENSOR_VPピンに印加しています。
バッテリの定格電圧は3.7Vなので、定格出力時、SENSOR_VPピンには約1.85Vが印加されます。(R2、R3には1%の誤差があるため、ピッタリ1.85Vにはなりません)

プログラムを書くに当たって、バッテリ電圧1/2と、SENSOR_VPピンがキーワードです。

SENSOR_VPピンのADCチャンネルを確認

つぎに、ESP32モジュールのデータシートを読み、SENSOR_VPピンで使えるADCのチャンネルを確認します。

SENSOR_VP ピンの機能

Pin Definitionsより、ADC1_CH0(ADC 1ユニットのチャンネル0)を使えることがわかりました。

サンプルコードを編集して、バッテリ電圧監視プログラム作成

↓前回使用したサンプルコードを編集して、Especialの環境に合わせます。

esp-idf/examples/peripherals/adc at release/v3.3 · espressif/esp-idf
Espressif IoT Development Framework. Official development framework for Espressif SoCs. - espressif/esp-idf

そして出来上がったサンプルコードがこちらです。

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/adc.h"
#include "esp_adc_cal.h"

#define DEFAULT_VREF 1100 // eFuseメモリのVrefを使うため、このデフォルト値は使用されない

// 公式マニュアル:
// https://docs.espressif.com/projects/esp-idf/en/stable/api-reference/peripherals/adc.html

void app_main()
{
    // ADC1_CH0はSENSOR_VPピンの機能
    static const adc_unit_t         unit = ADC_UNIT_1;
    static const adc_channel_t      channel = ADC_CHANNEL_0;
    // 11dB減衰を設定。フルスケールレンジは3.9V
    // SENSOR_VPピンにはバッテリ電圧の1/2 (約1.85V)が印加される
    // マニュアルより、
    //   6dBで正確な値が取れる電圧範囲は0.15 ~ 1.75V
    //   11dBで正確な値が取れる電圧範囲は0.15 ~ 2.45V
    // よって、11dB減衰を設定する
    static const adc_atten_t        atten = ADC_ATTEN_DB_11;
    // ADCの分解能を12bit (0~4095)に設定
    static const adc_bits_width_t   width = ADC_WIDTH_BIT_12;

    // ADCのユニットとチャンネルの設定
    adc1_config_width(width);
    adc1_config_channel_atten(channel, atten);

    // ADCの特性を設定
    esp_adc_cal_characteristics_t *adc_chars = calloc(1, sizeof(esp_adc_cal_characteristics_t));
    esp_adc_cal_characterize(unit, atten, width, DEFAULT_VREF, adc_chars);

    while (1) {
        uint32_t adc_reading = 0;
        static const int NO_OF_SAMPLES = 64; // 平均値を求めるためのサンプル数

        // ADCの変換結果のばらつきを抑えるため、
        // 結果を複数回取得して、平均値を求める
        for (int i = 0; i < NO_OF_SAMPLES; i++) {
            adc_reading += adc1_get_raw((adc1_channel_t)channel);
        }
        adc_reading /= NO_OF_SAMPLES;

        // ADCの変換結果(0 ~ 4095)を電圧値 mV に変換
        uint32_t voltage = esp_adc_cal_raw_to_voltage(adc_reading, adc_chars);
        // ピンにはバッテリ電圧の1/2が印加されるので、voltageを2倍する
        uint32_t battery_voltage = voltage * 2;
        printf("Raw: %d\tVoltage: %dmV\tBatteryVoltage: %dmV\n",
                adc_reading, voltage, battery_voltage);

        // 1秒待機
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

GitHubにも公開しています。

especial/examples/2_battery_checker/main/main.c at master · ShotaAk/especial
ESP32を搭載したマイクロマウスのプログラム. Contribute to ShotaAk/especial development by creating an account on GitHub.

それでは細かいところを説明します。

ADCの設定

つぎのコードブロックでADCの設定項目を決めてます。

    // ADC1_CH0はSENSOR_VPピンの機能
    static const adc_unit_t         unit = ADC_UNIT_1;
    static const adc_channel_t      channel = ADC_CHANNEL_0;
    // 11dB減衰を設定。フルスケールレンジは3.9V
    // SENSOR_VPピンにはバッテリ電圧の1/2 (約1.85V)が印加される
    // マニュアルより、
    //   6dBで正確な値が取れる電圧範囲は0.15 ~ 1.75V
    //   11dBで正確な値が取れる電圧範囲は0.15 ~ 2.45V
    // よって、11dB減衰を設定する
    static const adc_atten_t        atten = ADC_ATTEN_DB_11;
    // ADCの分解能を12bit (0~4095)に設定
    static const adc_bits_width_t   width = ADC_WIDTH_BIT_12;

先程の説明のとおり、ADC1のCH0を使うように設定します。

減衰量は11dBとしました。
バッテリ電圧の1/2である1.85VがSENSOR_VPピンに印加されます。
この場合、0dB減衰だと、フルスケールレンジが1.1Vのためバッテリ電圧を計測できません。

公式マニュアルを参考に、最適な減衰量を決めます。

Due to ADC characteristics, most accurate results are obtained within the following approximate voltage ranges:
・0dB attenuaton (ADC_ATTEN_DB_0) between 100 and 950mV
・2.5dB attenuation (ADC_ATTEN_DB_2_5) between 100 and 1250mV
・6dB attenuation (ADC_ATTEN_DB_6) between 150 to 1750mV
・11dB attenuation (ADC_ATTEN_DB_11) between 150 to 2450mV

と書かれているように、各減衰量ごとに正確に電圧を計測できる範囲が決まってます。
1.85Vを計測する場合は、6dB減衰の0.15 ~ 1.75Vでは足りません。
以上より、11dB減衰を選択します。

ADCの変換結果を取得

つぎのコードブロックで、ADCの変換結果(0 ~ 4095)を取得します。

        uint32_t adc_reading = 0;
        static const int NO_OF_SAMPLES = 64; // 平均値を求めるためのサンプル数

        // ADCの変換結果のばらつきを抑えるため、
        // 結果を複数回取得して、平均値を求める
        for (int i = 0; i < NO_OF_SAMPLES; i++) {
            adc_reading += adc1_get_raw((adc1_channel_t)channel);
        }
        adc_reading /= NO_OF_SAMPLES;

サンプルプログラムと同じように、ばらつきを抑えるために、変換結果を複数回取得して平均値を求めています。

ADCの変換結果を電圧値に変換

次のコードブロックでADCの変換結果(0 ~ 4095)を電圧値(mV)に変換します。

        // ADCの変換結果(0 ~ 4095)を電圧値 mV に変換
        uint32_t voltage = esp_adc_cal_raw_to_voltage(adc_reading, adc_chars);
        // ピンにはバッテリ電圧の1/2が印加されるので、voltageを2倍する
        uint32_t battery_voltage = voltage * 2;
        printf("Raw: %d\tVoltage: %dmV\tBatteryVoltage: %dmV\n",
                adc_reading, voltage, battery_voltage);

ここで、1/2されたバッテリ電圧を2倍して、もとの電圧値に戻しています。
変換結果はprintfでシリアルモニタに表示します。

プログラムのビルドと実行

それではプログラムをビルドして実行します。

cd ~/esp

# GitHubからEspecialのプログラムをクローン
git clone https://github.com/ShotaAk/especial.git

# サンプルのプロジェクトまで移動
cd especial/examples/2_battery_checker 

# ビルド・書き込み・モニタ起動
make flash monitor

--- 省略 ---

I (291) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
Raw: 2354	Voltage: 2087mV	BatteryVoltage: 4174mV
Raw: 2354	Voltage: 2087mV	BatteryVoltage: 4174mV
Raw: 2353	Voltage: 2086mV	BatteryVoltage: 4172mV
Raw: 2354	Voltage: 2087mV	BatteryVoltage: 4174mV
Raw: 2353	Voltage: 2086mV	BatteryVoltage: 4172mV
Raw: 2353	Voltage: 2086mV	BatteryVoltage: 4172mV
Raw: 2353	Voltage: 2086mV	BatteryVoltage: 4172mV
Raw: 2354	Voltage: 2087mV	BatteryVoltage: 4174mV

無事に電圧が表示されました。

が、しかし、バッテリ電圧が4.17 Vと表示されています。
満充電された定格3.7Vのバッテリを接続したので、4.0V以上と出てもおかしくは無いのですが、、、正しく計測できたのか不安です。

正しく電圧を測定できたのか確認

そこで、安定化電源から電圧を供給して、正しく計測できたのか確認します。

Especialに安定化電源を接続

計測結果がこちらです。

供給電圧 -> シリアルモニタの出力
4.10 V -> Raw: 2303	Voltage: 2045mV	BatteryVoltage: 4090mV
3.90 V -> Raw: 2184	Voltage: 1946mV	BatteryVoltage: 3892mV
3.80 V -> Raw: 2125	Voltage: 1898mV	BatteryVoltage: 3796mV
3.70 V -> Raw: 2064	Voltage: 1847mV	BatteryVoltage: 3694mV
3.60 V -> Raw: 2000	Voltage: 1794mV	BatteryVoltage: 3588mV
3.50 V -> Raw: 1941	Voltage: 1746mV	BatteryVoltage: 3492mV
3.40 V -> Raw: 1882	Voltage: 1697mV	BatteryVoltage: 3394mV
3.30 V -> Raw: 1818	Voltage: 1644mV	BatteryVoltage: 3288mV
3.20 V -> Raw: 1751	Voltage: 1589mV	BatteryVoltage: 3178mV
3.10 V -> Raw: 1686	Voltage: 1535mV	BatteryVoltage: 3070mV
3.00 V -> Raw: 1622	Voltage: 1482mV	BatteryVoltage: 2964mV

グラフにするとつぎのとおりです。

EspecialのADC変換結果

入力電圧が低くなると誤差が増えてるように見えますが、0.04Vの誤差なのでとても小さいです。
抵抗誤差1%を考えると悪くない値です。(ESP32のADCは優秀だとは言ってません

次回の記事

次回の記事では、同じくADC機能を使う物体検出センサのプログラムについて書きます。

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