今回は、ESP-IDFでADCを使って見ます。今回実行する例題は、/esp/esp-idf/examples/peripherals/adc/single_read。またADCに付いての詳細はここで説明されています。
ADCに付いての簡単な説明。
- 使用出来るポートは、
- ADC1: 8 channels: GPIO32 – GPIO39
- ADC2: 10 channels: GPIO0, GPIO2, GPIO4, GPIO12 – GPIO15, GOIO25 – GPIO27
- の計18ポート
- 0VからVrefまでの値を測定する。
- Vrefの値は基本的に1.1Vだが、Attenuationを使用して測定範囲を広げることが可能。
Attenuation | Measurable input voltage range |
---|---|
ADC_ATTEN_DB_0 | 100 mV ~ 950 mV |
ADC_ATTEN_DB_2_5 | 100 mV ~ 1250 mV |
ADC_ATTEN_DB_6 | 150 mV ~ 1750 mV |
ADC_ATTEN_DB_11 | 150 mV ~ 2450 mV |
- 測定の分解能は12ビット。adc1_config_width()関数で分解能を指定
- adc1_get_raw()関数で電圧を測定しデジタルに変換する。
- 測定は、測定のばらつきを考慮する必要がある。通常は何回か測定を行いその平均値を測定値とする。
サンプルプログラム、
サンプルプログラム、/esp/esp-idf/examples/peripherals/adc/single_readを下記に示します。プログラムは、mainフォルダーの下の、adc1_example_main.c”です。
hello_04.py
/* ADC1 Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "driver/adc.h"
#include "esp_adc_cal.h"
#define DEFAULT_VREF 3900 //Use adc2_vref_to_gpio() to obtain a better estimate
#define NO_OF_SAMPLES 64 //Multisampling
static esp_adc_cal_characteristics_t *adc_chars;
#if CONFIG_IDF_TARGET_ESP32
static const adc_channel_t channel = ADC_CHANNEL_4; //GPIO32 if ADC1, GPIO14 if ADC2
static const adc_bits_width_t width = ADC_WIDTH_BIT_12;
#elif CONFIG_IDF_TARGET_ESP32S2
static const adc_channel_t channel = ADC_CHANNEL_6; // GPIO7 if ADC1, GPIO17 if ADC2
static const adc_bits_width_t width = ADC_WIDTH_BIT_13;
#endif
static const adc_atten_t atten = ADC_ATTEN_DB_11;
static const adc_unit_t unit = ADC_UNIT_1;
static void check_efuse(void)
{
#if CONFIG_IDF_TARGET_ESP32
//Check if TP is burned into eFuse
if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_TP) == ESP_OK) {
printf("eFuse Two Point: Supported\n");
} else {
printf("eFuse Two Point: NOT supported\n");
}
//Check Vref is burned into eFuse
if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_VREF) == ESP_OK) {
printf("eFuse Vref: Supported\n");
} else {
printf("eFuse Vref: NOT supported\n");
}
#elif CONFIG_IDF_TARGET_ESP32S2
if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_TP) == ESP_OK) {
printf("eFuse Two Point: Supported\n");
} else {
printf("Cannot retrieve eFuse Two Point calibration values. Default calibration values will be used.\n");
}
#else
#error "This example is configured for ESP32/ESP32S2."
#endif
}
static void print_char_val_type(esp_adc_cal_value_t val_type)
{
if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP) {
printf("Characterized using Two Point Value\n");
} else if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF) {
printf("Characterized using eFuse Vref\n");
} else {
printf("Characterized using Default Vref\n");
}
}
void app_main(void)
{
//Check if Two Point or Vref are burned into eFuse
check_efuse();
//Configure ADC
if (unit == ADC_UNIT_1) {
adc1_config_width(width);
adc1_config_channel_atten(channel, atten);
} else {
adc2_config_channel_atten((adc2_channel_t)channel, atten);
}
//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, width, DEFAULT_VREF, adc_chars);
print_char_val_type(val_type);
//Continuously sample ADC1
while (1) {
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, width, &raw);
adc_reading += raw;
}
}
adc_reading /= NO_OF_SAMPLES;
//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));
}
}
- ADCの設定
- ADC1を使用。測定ポートはGPIO32
- 解像度は12ビット
- Attenuationは、
ADC_ATTEN_DB_11
。測定範囲150 mV ~ 2450 mV
- 実際の測定
- 電圧を12ビットの解像度で64回測定しその平均を算出。それを測定値とする。
- その測定値を元に測定電圧に変換。
- その2つの値をモニターに表示し、この操作を繰り返す。
このサンプルは問題無く動作しました。サンプル実行時には気が付かなかったのですが、サンプリング回数を減らすと値がばらつきます。測定電圧の振れか測定自体の振れか分からないですが、流石に64回測定すると安定しました。