こんにちは、shotaです。
前回の記事ではLEDを点灯させました。
今回はESP-IDFのADC(Analog to Digital Converter)のサンプルを動かして、コードを読み解きます。
ESP-IDFバージョンについて訂正
前々回の記事では最新バージョンのESP-IDFを使用していましたが、
ドキュメントとサンプルコードの乖離がいくつかあったので、今回から安定バージョンに変更します。
そのため、ESP-IDFのインストール手順もGet Started(安定版)を参照してください。
私が使用している安定版のバージョンはv3.3.1です。
ADCサンプルの実行
ADC(Analog to Digital Converter)は、ピンにかかる電圧値をデジタル値に変換してくれる機能です。
バッテリの電圧や、センサの出力電圧等、1(Hi)か0(Lo)かではなく細かい電圧値を知りたいときに使う機能です。
今回はESP32の開発ボードであるESP32-DevKitC-32Dを用いて、サンプルコードを実行します。
ADCの使い方を確認した後に、ESP32マウスでプログラムを実行します。(ESP32マウスを使うのは次回の記事です)
サンプルコードはperipherals/adcです。
https://github.com/espressif/esp-idf/tree/release/v3.3/examples/peripherals/adc
まずサンプルコードをコピーします。
$ cd ~/esp $ cp -r esp-idf/examples/peripherals/adc .
ビルドして書き込み、シリアルモニタを表示します。
$ cd ~/esp/adc # ビルド、書き込み、モニタ表示 $ make flash monitor --- 省略 --- I (290) cpu_start: Starting scheduler on PRO CPU. I (0) cpu_start: Starting scheduler on APP CPU. eFuse Two Point: NOT supported eFuse Vref: Supported Characterized using eFuse Vref Raw: 15 Voltage: 79mV Raw: 44 Voltage: 86mV Raw: 36 Voltage: 84mV Raw: 27 Voltage: 82mV Raw: 11 Voltage: 78mV Raw: 0 Voltage: 75mV Raw: 0 Voltage: 75mV
画面にRawとVoltageが表示されました。
ADCサンプルコードを読み解く
それではRawとVoltageがそれぞれ何を表すのかコードを読み解きます。
公式ドキュメントのADCのページとサンプルコードを見比べます。
どのピンの電圧値を変換しているのか
adc/main/adc1_example_main.cに次のコードが書かれています。
static esp_adc_cal_characteristics_t *adc_chars; static const adc_channel_t channel = ADC_CHANNEL_6; //GPIO34 if ADC1, GPIO14 if ADC2 static const adc_atten_t atten = ADC_ATTEN_DB_0; static const adc_unit_t unit = ADC_UNIT_1; --- 省略 --- void app_main() { //Check if Two Point or Vref are burned into eFuse check_efuse(); //Configure ADC if (unit == ADC_UNIT_1) { adc1_config_width(ADC_WIDTH_BIT_12); adc1_config_channel_atten(channel, atten); } else { adc2_config_channel_atten((adc2_channel_t)channel, atten); }
ESP32のADCにはADC1とADC2の2つのユニットがあります。
サンプルコードではunitをADC_UNIT_1にするか、ADC_UNIT_2にするかで切り替えています。
チャンネルはchannel = ADC_CHANNEL_6で指定してます。
コメントを読むとADC1のCH6はGPIO34であると書かれていますが、本当にそうなのでしょうか?
モジュールのデータシートで確認してみましょう。
ADC1_CH6で検索すると、3ページにすすみます。
ここで、ADC1_CH6がIO34の機能であることがわかりました。
ADCを使うためのその他の設定
それでは、main関数内の他のコードを見てます。
void app_main() { //Check if Two Point or Vref are burned into eFuse check_efuse();
check_efuse()はサンプル用に作られた関数で、ESP内のeFuseメモリにADCの設定値が書き込まれているのかをチェックしています。
この設定値はADCに使われるリファレンス電圧値Vrefで、工場出荷時にeFuseに書き込まれます。
2018年以降のESP32にはVrefが書き込まれているようです。
先程の実行結果でもeFuse Vref: Supportedと表示されていましたね。
次のコードでADCのbit幅とチャンネルを設定します。
//Configure ADC if (unit == ADC_UNIT_1) { adc1_config_width(ADC_WIDTH_BIT_12); adc1_config_channel_atten(channel, atten); } else { adc2_config_channel_atten((adc2_channel_t)channel, atten); }
ADC1を使う場合はadc1_config_widthでビット幅を決めます。
ADC_WIDTH_BIT_12の場合、電圧値が12bit(0~4095)で表現されます。
attenにはADC_ATTEN_DB_0が設定されていますが、これはADCの減衰量を意味します。
ADC_ATTEN_DB_0は0dBの減衰で、フルスケールレンジは1.1Vになります。
(0dB減衰では、ADCで変換できる電圧範囲がおおよそ0 ~ 1.1 Vになる)
詳しくは公式ドキュメントを参照してください。
次のコードで、ADCの特性を設定します。
//Characterize ADC adc_chars = calloc(1, sizeof(esp_adc_cal_characteristics_t)); esp_adc_cal_value_t val_type = esp_adc_cal_characterize(unit, atten, ADC_WIDTH_BIT_12, DEFAULT_VREF, adc_chars); print_char_val_type(val_type);
adc_charsには設定値が格納されます。
val_typeにはどのリファレンス値で特性を設定したのか、判別値が入ります。
先程の実行結果では、Characterized using eFuse Vrefと表示されているので、eFuseに書き込まれたリファレンス値が使われていることがわかります。
次のコードがADC1_CH6の電圧変換結果を取得しているところです。
uint32_t adc_reading = 0; //Multisampling for (int i = 0; i < NO_OF_SAMPLES; i++) { if (unit == ADC_UNIT_1) { adc_reading += adc1_get_raw((adc1_channel_t)channel); } else { int raw; adc2_get_raw((adc2_channel_t)channel, ADC_WIDTH_BIT_12, &raw); adc_reading += raw; } } adc_reading /= NO_OF_SAMPLES;
adc1_get_raw()で、ADC1_CH6の電圧の変換結果を取得しています。
このサンプルでは値の変動を抑えるため、複数回(NO_OF_SAMPLES = 64)値を取得して、平均値を求めています。
次のコードでは、ADCで得たデジタル値(0~4095)を、電圧値(0~1100mV)に変換しています。
先程設定した特性adc_charsとAD変換結果adc_readingをesp_adc_cal_raw_to_voltage()に渡して変換しています。
//Convert adc_reading to voltage in mV uint32_t voltage = esp_adc_cal_raw_to_voltage(adc_reading, adc_chars); printf("Raw: %d\tVoltage: %dmV\n", adc_reading, voltage); vTaskDelay(pdMS_TO_TICKS(1000));
ここで最初の疑問
RawとVoltageがそれぞれ何を表すのか。
の答えがやっとわかりました。
RawはADC1_CH6(GPIO34)の電圧値の変換結果(デジタル値)で、VoltageはRawを電圧値に変換したものです。
次回の記事
次回は、ADCのサンプルコードを編集してマウスのバッテリ電圧値を取得します。