ESP32 ソフトウェア 回路設計

ESP32 ADC完全ガイド|アナログ入力の基本と使い方を現役エンジニアが解説

更新日:

ESP32は、Wi-FiやBluetoothだけでなく、アナログ信号を読み取るためのADC(Analog to Digital Converter)も搭載しています。

温度センサーや可変抵抗、光センサーなど、多くのデバイスはアナログ電圧を出力します。

ESP32のADCを利用することで、これらのアナログ信号をデジタルデータとして取得し、さまざまな制御やデータ処理に活用できます。

ESP32で開発を始めると、

  • ADCとはどのような機能なの?
  • ADC1とADC2は何が違うの?
  • 分解能とは何を意味するの?
  • なぜ思ったより精度が出ないことがあるの?

といった疑問を持つ方も多いでしょう。

この記事では、ADCの基本からESP32で利用する際の注意点、実務で押さえておきたいポイントまで分かりやすく解説します。

ADCとは?

ADC(Analog to Digital Converter)は、アナログ電圧をデジタル値へ変換する機能です。

例えば、

  • 可変抵抗を回す
  • 光の明るさが変わる
  • 温度が変化する

こうした現象は、多くの場合「電圧の変化」として表れます。

しかし、マイコンは電圧をそのまま理解することはできません。

そこでADCを利用して電圧を数値へ変換し、プログラムで扱えるようにします。

ESP32のADCの概要

ESP32には複数のADCチャネルが搭載されており、複数のアナログ入力を扱うことができます。

入力された電圧は一定の分解能でデジタル値へ変換されます。

ESP32シリーズでは、デバイスごとに利用できるADCチャネル数や性能が異なるため、使用する製品のデータシートを確認することが重要です。

また、ESP32のADCは一般的な計測器ほど高精度ではなく、簡易的な電圧測定やセンサー入力を目的として利用されることが多くあります。

ADC1とADC2の違い

ESP32(初代)では、ADCはADC1ADC2の2つに分かれています。

特に注意したいのは、ADC2はWi-Fi機能と内部リソースを共有している点です。

そのため、Wi-Fiを使用している間はADC2が利用できなかったり、期待どおりに動作しなかったりすることがあります。

一方、ADC1はWi-Fiの影響を受けずに利用できるため、Wi-Fiを使用するアプリケーションではADC1を選ぶことが一般的です。

なお、ESP32-S2、ESP32-S3、ESP32-C3、ESP32-C5などではADCの構成が異なるため、シリーズごとの仕様を確認してください。

分解能と入力電圧

ADCは入力された電圧を一定の段階に分けて数値へ変換します。

この段階の細かさを分解能と呼びます。

一般的には、

  • 分解能が高いほど細かな電圧変化を検出できる
  • 分解能が低いほど変化を大まかにしか判別できない

という特徴があります。

ただし、分解能が高くてもノイズの影響を受ければ、実際の測定精度が向上するとは限りません。

ADCでは、分解能だけでなく、回路設計やノイズ対策も重要になります。

ADCが使われる場面

ESP32のADCは、次のような用途でよく利用されます。

  • 可変抵抗の読み取り
  • 温度センサー(アナログ出力タイプ)
  • 光センサー
  • バッテリー電圧の監視
  • 電流センサー
  • アナログジョイスティック

これらは、連続的に変化する値を取得したい場合に適しています。

一方、I²CやSPI対応のデジタルセンサーではADCは不要です。

用途に応じて、アナログ入力とデジタル通信を使い分けることが重要です。

今回使用する開発環境

この記事では、次の環境を使用してADCの動作を確認します。

  • ESP-IDF:v5.5系
  • ターゲット:ESP32-C5
  • 開発環境:Visual Studio Code
  • ADC入力:GPIO1
  • 入力回路:10kΩ可変抵抗

ESP32-C5では、GPIO1~GPIO6をADC入力として使用できます。

今回のサンプルでは、GPIO1をADC入力として使用します。

使用するESP32シリーズや開発ボードによってADC対応GPIOは異なるため、別のデバイスで試す場合はデータシートを確認してください。

ESP32-C5ではADC入力がGPIO1~GPIO6へ割り当てられており、GPIO1はADC1_CH0です。

可変抵抗を使ったADC入力回路

今回は、10kΩの可変抵抗を使って0V~3.3Vの電圧をADCへ入力します。

接続は次のとおりです。

ESP32-C5                    10kΩ可変抵抗

3.3V  ─────────── 端子1
                              │
                              │
GPIO1(ADC1_CH0)───── 中央端子
                              │
                              │
GND   ─────────── 端子3

可変抵抗の両端を3.3VとGNDへ接続し、中央端子であるワイパ端子をGPIO1へ接続します。

可変抵抗を回すとGPIO1へ入力される電圧が変化し、ADCの変換値も変化します。

配線時の注意点

ADC入力へESP32-C5の許容範囲を超える電圧を加えてはいけません。

また、可変抵抗の中央端子とGPIO1の間の配線は、できるだけ短くしてください。

測定値が大きく変動する場合は、GPIO1とGNDの間に0.1µF程度のセラミックコンデンサを追加すると、ノイズを低減できる場合があります。

ESP-IDFでADCを使用する流れ

ESP-IDFでは、ADCを利用する際に専用のドライバを使用します。

基本的な流れは次のとおりです。

  1. ADCユニットを初期化する
  2. 使用するチャネルを設定する
  3. 減衰率(Attenuation)を設定する
  4. 必要に応じてキャリブレーションを実施する
  5. ADC値を取得する

ESP-IDFでは、キャリブレーション機能を利用することで、実際の入力電圧に近い値へ補正できます。

単にADC値を取得するだけではなく、補正まで行うことでより実用的な測定が可能になります。

CMakeLists.txtの設定

ADCのOneshotドライバとキャリブレーション機能を使用するため、mainフォルダ内のCMakeLists.txtを次のように記述します。

idf_component_register(
    SRCS "main.c"
    INCLUDE_DIRS "."
    REQUIRES esp_adc
)

ESP-IDF v5系では、ADCの新しいドライバはesp_adcコンポーネントとして提供されています。

以前のdriver/adc.hを使用する方式は旧APIであるため、この記事では新しいOneshotドライバを使用します。

ESP32-C5でADC値を読み取るサンプルコード

以下は、GPIO1へ入力された電圧を500msごとに測定し、ADCの生データとキャリブレーション後の電圧を表示するサンプルです。


#include <stdio.h>

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#include "esp_err.h"
#include "esp_log.h"

#include "esp_adc/adc_oneshot.h"
#include "esp_adc/adc_cali.h"
#include "esp_adc/adc_cali_scheme.h"

#define ADC_INPUT_GPIO     1
#define ADC_ATTENUATION    ADC_ATTEN_DB_12
#define ADC_BIT_WIDTH      ADC_BITWIDTH_DEFAULT
#define ADC_READ_INTERVAL  500

static const char *TAG = "ADC_SAMPLE";

void app_main(void)
{
    adc_unit_t adc_unit;
    adc_channel_t adc_channel;

    /*
     * GPIO番号からADCユニットとADCチャネルを取得します。
     * GPIO1はESP32-C5のADC入力端子です。
     */
    ESP_ERROR_CHECK(
        adc_oneshot_io_to_channel(
            ADC_INPUT_GPIO,
            &adc_unit,
            &adc_channel
        )
    );

    /*
     * ADCユニットをOneshotモードで初期化します。
     */
    adc_oneshot_unit_handle_t adc_handle;

    adc_oneshot_unit_init_cfg_t unit_config = {
        .unit_id = adc_unit,
        .ulp_mode = ADC_ULP_MODE_DISABLE,
    };

    ESP_ERROR_CHECK(
        adc_oneshot_new_unit(
            &unit_config,
            &adc_handle
        )
    );

    /*
     * ADCチャネルの分解能と減衰率を設定します。
     */
    adc_oneshot_chan_cfg_t channel_config = {
        .bitwidth = ADC_BIT_WIDTH,
        .atten = ADC_ATTENUATION,
    };

    ESP_ERROR_CHECK(
        adc_oneshot_config_channel(
            adc_handle,
            adc_channel,
            &channel_config
        )
    );

    /*
     * ESP32-C5のCurve Fitting方式で
     * ADCキャリブレーションを初期化します。
     */
    adc_cali_handle_t calibration_handle = NULL;

    adc_cali_curve_fitting_config_t calibration_config = {
        .unit_id = adc_unit,
        .chan = adc_channel,
        .atten = ADC_ATTENUATION,
        .bitwidth = ADC_BIT_WIDTH,
    };

    ESP_ERROR_CHECK(
        adc_cali_create_scheme_curve_fitting(
            &calibration_config,
            &calibration_handle
        )
    );

    ESP_LOGI(
        TAG,
        "ADC measurement started: GPIO%d",
        ADC_INPUT_GPIO
    );

    while (1)
    {
        int raw_value = 0;
        int voltage_mv = 0;

        /*
         * ADCの生データを取得します。
         */
        ESP_ERROR_CHECK(
            adc_oneshot_read(
                adc_handle,
                adc_channel,
                &raw_value
            )
        );

        /*
         * 生データをキャリブレーション済みの
         * 電圧値(mV)へ変換します。
         */
        ESP_ERROR_CHECK(
            adc_cali_raw_to_voltage(
                calibration_handle,
                raw_value,
                &voltage_mv
            )
        );

        ESP_LOGI(
            TAG,
            "Raw: %d, Voltage: %d mV",
            raw_value,
            voltage_mv
        );

        vTaskDelay(
            pdMS_TO_TICKS(ADC_READ_INTERVAL)
        );
    }
}

このプログラムでは、ESP-IDF v5系のOneshotドライバを使用しています。

adc_oneshot_read()でADCの生データを取得し、adc_cali_raw_to_voltage()でキャリブレーション後の電圧値へ変換しています。

サンプルコードのポイント

GPIO番号からADCチャネルを取得する

adc_oneshot_io_to_channel(
    ADC_INPUT_GPIO,
    &adc_unit,
    &adc_channel
);

ESP32シリーズでは、GPIO番号とADCチャネル番号の対応がデバイスごとに異なります。

このサンプルでは、GPIO番号からADCユニットとチャネルを自動的に取得しています。

ADCに対応していないGPIOを指定するとエラーになるため、GPIO番号の設定ミスにも気づきやすくなります。

ADCユニットを初期化する

adc_oneshot_new_unit(
    &unit_config,
    &adc_handle
);

ADCをOneshotモードで使用するためのハンドルを作成します。

Oneshotモードは、必要なタイミングで1回ずつADC値を読み取る用途に適しています。

ADCチャネルを設定する

adc_oneshot_config_channel(
    adc_handle,
    adc_channel,
    &channel_config
);

ここではADCの分解能とAttenuationを設定しています。

今回のサンプルでは、入力範囲を広く取るためにADC_ATTEN_DB_12を使用しています。

ADCの生データを取得する

adc_oneshot_read(
    adc_handle,
    adc_channel,
    &raw_value
);

raw_valueにはADCの生の変換結果が格納されます。

この値は、そのままでは正確な電圧を表しているわけではありません。

電圧値へ変換する

adc_cali_raw_to_voltage(
    calibration_handle,
    raw_value,
    &voltage_mv
);

ADCの生データを、キャリブレーション情報を使って電圧へ変換します。

変換結果はmV単位で取得できます。

実行結果

プログラムを書き込み、シリアルモニターを開くと、次のようなログが表示されます。

I (325) ADC_SAMPLE: ADC measurement started: GPIO1
I (825) ADC_SAMPLE: Raw: 428, Voltage: 341 mV
I (1325) ADC_SAMPLE: Raw: 1642, Voltage: 1327 mV
I (1825) ADC_SAMPLE: Raw: 3015, Voltage: 2458 mV
I (2325) ADC_SAMPLE: Raw: 3984, Voltage: 3251 mV

可変抵抗を回すと、RawVoltageの値が変化します。

  • Raw:ADCの生データ
  • Voltage:キャリブレーション後の入力電圧
  • 電圧の単位:mV

実際に表示される値は、使用するESP32-C5の個体差、電源電圧、可変抵抗、配線、ノイズなどによって異なります。

OneshotモードとContinuousモードの違い

ESP-IDFのADCドライバには、主にOneshotモードとContinuousモードがあります。

Oneshotモードは、温度や可変抵抗、バッテリー電圧などを一定間隔で測定する用途に適しています。

一方、Continuousモードは、ADCデータを高速かつ連続的に取得する用途に適しており、DMAを利用してデータをメモリへ転送します。

今回のサンプルは500msごとに電圧を確認するため、構成がシンプルなOneshotモードを使用しています。

Attenuation(減衰率)とは?

ESP32では、入力電圧の範囲に応じて**Attenuation(減衰率)**を設定できます。

減衰率を適切に設定することで、測定できる入力電圧範囲を変更できます。

例えば、低い電圧を高い分解能で測定したい場合と、より高い電圧を測定したい場合では、最適な設定が異なります。

入力電圧に合わない設定を選ぶと、測定値が飽和したり、十分な分解能を得られなかったりするため、データシートに記載された入力範囲を確認して設定しましょう。

ADCでよくあるトラブル

ADCはデジタル通信と違い、周囲の環境や回路設計の影響を受けやすい機能です。

実務でよくあるトラブルを紹介します。

1.測定値が安定しない

ADC値が毎回変化する原因として、

  • 電源ノイズ
  • センサー出力の揺らぎ
  • 配線からのノイズ

などが考えられます。

単純に1回だけ読み取るのではなく、複数回測定して平均化することで、より安定した値を得られる場合があります。

2.Wi-Fi使用時にADC2が利用できない

ESP32(初代)では、ADC2はWi-Fi機能と内部リソースを共有しています。

そのため、Wi-Fiを利用するアプリケーションでは、ADC2が正常に利用できないことがあります。

Wi-Fiを使用する予定がある場合は、ADC1を使用する設計がおすすめです。

3.入力電圧が範囲を超えている

ADCの入力範囲を超える電圧を加えると、正しい値を取得できません。

場合によってはデバイスを破損する可能性もあります。

分圧回路や保護回路を設け、入力電圧が許容範囲を超えないよう設計しましょう。

実務での設計ポイント

実際の製品開発では、ADCの精度はソフトウェアだけでは決まりません。

私は次の点を特に意識しています。

  • アナログ配線をできるだけ短くする
  • GNDを安定させる
  • デジタル信号と並走させない
  • 電源ノイズ対策を行う
  • キャリブレーションを実施する
  • 平均化やフィルタ処理を組み合わせる

ADCは「回路設計」と「ソフトウェア処理」の両方を最適化して初めて、本来の性能を発揮できます。

まとめ

ADCは、ESP32でアナログ信号を扱うために欠かせない機能です。

可変抵抗や温度センサー、電圧監視など、多くの用途で利用されます。

一方で、Wi-Fiとの競合やノイズの影響、入力電圧範囲など、設計時に注意すべきポイントも少なくありません。

ESP32のADCを正しく理解し、適切な回路設計とソフトウェア処理を組み合わせることで、安定した測定結果を得られるようになります。

関連記事

ESP32 UART完全ガイド|UART0・UART1・UART2の違いと使い方を現役エンジニアが解説

ESP32 SPI完全ガイド|SPI通信の基本と使い方を現役エンジニアが解説

ESP32 I²C完全ガイド|I²C通信の基本と使い方を現役エンジニアが解説

ESP32 BLEとWi-Fiは同時に使える?現役エンジニアが仕組みと注意点を解説

ESP32 Deep Sleepとは?消費電力を大幅に削減する省電力機能を現役エンジニアが解説

技術は、経験から価値になる。

DLROW Design|現場エンジニア

スポンサーリンク

スポンサーリンク

-ESP32, ソフトウェア, 回路設計

Copyright© 江藤良樹の仕事は物づくり , 2026 All Rights Reserved.