#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_adc/adc_oneshot.h"
#include "esp_adc/adc_cali.h"
#include "esp_adc/adc_cali_scheme.h"
#define ADC_UNIT ADC_UNIT_1
#define ADC_CHANNEL ADC_CHANNEL_4
#define ADC_ATTENUATION ADC_ATTEN_DB_12
#define ADC_THRESHOLD 2000
#define WOOKWI_THRESHOLD 100
static bool adc_calibration_init(adc_unit_t unit, adc_channel_t channel, adc_atten_t atten, adc_cali_handle_t *out_handle);
static void adc_calibration_deinit(adc_cali_handle_t handle);
void app_main(void)
{
static int adc_raw;
static int voltage_mv;
static float voltage_v;
// Инициализация АЦП
adc_oneshot_unit_handle_t adc_handle;
adc_oneshot_unit_init_cfg_t init_config = { .unit_id = ADC_UNIT };
ESP_ERROR_CHECK(adc_oneshot_new_unit(&init_config, &adc_handle));
// Настройка АЦП
adc_oneshot_chan_cfg_t config = {
.bitwidth = ADC_BITWIDTH_DEFAULT,
.atten = ADC_ATTENUATION,
};
ESP_ERROR_CHECK(adc_oneshot_config_channel(adc_handle, ADC_CHANNEL, &config));
// Калибровка
adc_cali_handle_t adc_calibration_handle = NULL;
bool calibrated = adc_calibration_init(ADC_UNIT, ADC_CHANNEL, ADC_ATTENUATION, &adc_calibration_handle);
printf("Фоторезистор в Wokwi (инверсная логика)\n");
printf("ADC\tНапр.\tСостояние\tWokwi UI\n");
printf("---\t-----\t--------\t--------\n");
while (1) {
ESP_ERROR_CHECK(adc_oneshot_read(adc_handle, ADC_CHANNEL, &adc_raw));
if (calibrated) {
ESP_ERROR_CHECK(adc_cali_raw_to_voltage(adc_calibration_handle, adc_raw, &voltage_mv));
voltage_v = voltage_mv / 1000.0;
// Wokwi: высокий ADC = темно (<100 лк), низкий ADC = светло (>=100 лк)
const char* state = (adc_raw > ADC_THRESHOLD) ? "Темно" : "Светло";
float wokwi_value = (adc_raw > ADC_THRESHOLD) ? 50.0 : 150.0;
printf("%4d\t%5.3fV\t%s\t\t%.0f лк\n",
adc_raw, voltage_v, state, wokwi_value);
} else {
printf("%d (без калибровки)\n", adc_raw);
}
vTaskDelay(pdMS_TO_TICKS(1000));
}
ESP_ERROR_CHECK(adc_oneshot_del_unit(adc_handle));
if (calibrated) {
adc_calibration_deinit(adc_calibration_handle);
}
}
static bool adc_calibration_init(adc_unit_t unit, adc_channel_t channel, adc_atten_t atten, adc_cali_handle_t *out_handle)
{
adc_cali_handle_t handle = NULL;
esp_err_t ret = ESP_FAIL;
bool calibrated = false;
#if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
if (!calibrated) {
adc_cali_curve_fitting_config_t cali_config = {
.unit_id = unit, .chan = channel, .atten = atten, .bitwidth = ADC_BITWIDTH_DEFAULT,
};
ret = adc_cali_create_scheme_curve_fitting(&cali_config, &handle);
if (ret == ESP_OK) calibrated = true;
}
#endif
#if ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED
if (!calibrated) {
adc_cali_line_fitting_config_t cali_config = {
.unit_id = unit, .atten = atten, .bitwidth = ADC_BITWIDTH_DEFAULT,
};
ret = adc_cali_create_scheme_line_fitting(&cali_config, &handle);
if (ret == ESP_OK) calibrated = true;
}
#endif
*out_handle = handle;
return calibrated;
}
static void adc_calibration_deinit(adc_cali_handle_t handle)
{
#if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
ESP_ERROR_CHECK(adc_cali_delete_scheme_curve_fitting(handle));
#elif ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED
ESP_ERROR_CHECK(adc_cali_delete_scheme_line_fitting(handle));
#endif
}