Понадобилось в моём проекте на ESP32 Devkit v1 измерение напряжения батареи, которая сей есп и питает. Через делитель напряжения я проложил в GPIO36 линию. (Распиновка моего ЕСП) Написал простой код с analogRead, написал сложный код с adc1_get_raw(ADC1_CHANNEL_0); Во всех случаях получил погоду на марсе, график получаемых значений после десяти минут измерений выглядит вот так: Рядом у меня подключён вольтметр, который и глазом не ведёт и держит значение на одном уровне. Я вычислил его - оно должно быть где-то около 2234. Но вместо этого вот. Я пробовал менять плату (у меня есть 2 одинаковых) и конкретный канал. Значения меняются, но всё равно остаются полной чепухой. Проверил опорное напряжение чипа - идеальные 1.11 При этом если брать ардуинку и её аналогРид - результат больше похож на правду (ссылка на 6 графиков). Запускаю следующий код. Код (C++): #include <driver/adc.h> int ledPin = 2; volatile bool ledState = true; void setup() { pinMode(ledPin, OUTPUT); Serial.begin(9600); adc1_config_width(ADC_WIDTH_12Bit);//настройка ширины канала ацп 0-4095 adc1_config_channel_atten(ADC1_CHANNEL_6,ADC_ATTEN_DB_11); //настройка уровня приёма, тут от 150 до 1750 мВ } void loop() { /* digitalWrite(ledPin, ledState); ledState = !ledState;*/ delay(500); int val = adc1_get_raw(ADC1_CHANNEL_6); //считывание из ГПИО36 //int val = analogRead(36); Serial.println(val); //заряжаем в сериал } Может кто сталкивался с такими приколами платы? Как её перебороть?
1. Либо измеряется не тот канал 2. Либо ногу надо перевести в альт. функцию 3. Возможно, что это всё бред, ибо догадки...
В примере у espressif-а используется тот же GPIO36 При инициализации используют adc1_config_channel_atten(ADC1_CHANNEL_0,ADC_ATTEN_DB_0); вместо adc1_config_channel_atten(ADC1_CHANNEL_6,ADC_ATTEN_DB_11); на ADC_ATTEN_DB_0 пока не смотрим он нужен для измерений 1/1, наш случай ADC_ATTEN_DB_11 1/3.6 но смущает ваш ADC1_CHANNEL_6 который объявлен в перечислении (в adc.h) и должен соответствовать GPIO34 Код (Text): typedef enum { ADC1_CHANNEL_0 = 0, /*!< ADC1 channel 0 is GPIO36 */ ADC1_CHANNEL_1, /*!< ADC1 channel 1 is GPIO37 */ ADC1_CHANNEL_2, /*!< ADC1 channel 2 is GPIO38 */ ADC1_CHANNEL_3, /*!< ADC1 channel 3 is GPIO39 */ ADC1_CHANNEL_4, /*!< ADC1 channel 4 is GPIO32 */ ADC1_CHANNEL_5, /*!< ADC1 channel 5 is GPIO33 */ ADC1_CHANNEL_6, /*!< ADC1 channel 6 is GPIO34 */ ADC1_CHANNEL_7, /*!< ADC1 channel 7 is GPIO35 */ ADC1_CHANNEL_MAX, } adc1_channel_t; Для исключения путаницы ещё есть определения в adc_channel.h Код (Text): #define ADC1_GPIO36_CHANNEL ADC1_CHANNEL_0 #define ADC1_GPIO34_CHANNEL ADC1_CHANNEL_6 С измерениями тоже не те adc1_channel_t используют adc1_get_raw(ADC1_CHANNEL_0); вместо adc1_get_raw(ADC1_CHANNEL_6);
Я полностью пересобрал свою схему и получил приблизительно верные значения, что было сделано криво я так и не понял. Но код в первом посте верный и работает нормально, хоть и шумит страшным образом. Ещё интересное наблюдение. При использовании в одном скетче блока работы с вайфай и функции analogRead МК вешается при прошивке. Потом только с танцем с бубном получается его вернуть в адекватное состояние. А вот если использовать ESPшные функции - всё отлично.
Хоть и решено, все-таки замечу, что в ESP32 есть встроенная функциоя калибровки. У меня значительно повысилась точность при ее использовании. Ну т.е. без нее если я подгонял по вольтметру показания в районе 3.7V (18650), то при разряде до 3V показания вольтметра и ESP32 сильно уже различались. И наоборот. А с ней все четко. Спойлер: Кусочки кода Код (C++): //#define ADC_coeff_a 54142 //#define ADC_coeff_b 142 // ADC VRef: 1128 // выше просто для памяти, что мне функция калибровки выдала, в реальности я их при старте измеряю и использую вместо дефайнов #define ADC_CHANNEL ADC1_CHANNEL_0 #define ADC_NO_OF_SAMPLES 64 #define ADC_V_MULT 2.01 // зависит от делителя на резисторах #define VPIN_Voltage 10 #pragma region ADC calibration // Полезные функции, связанные с АЦП #define DEFAULT_VREF 1100 /* ADC_0db: sets no attenuation (1V input = ADC reading of 1088). ADC_2_5db: sets an attenuation of 1.34 (1V input = ADC reading of 2086). ADC_6db: sets an attenuation of 1.5 (1V input = ADC reading of 2975). ADC_11db: sets an attenuation of 3.6 (1V input = ADC reading of 3959). */ static const adc_atten_t atten = ADC_ATTEN_DB_11; static const adc_unit_t unit = ADC_UNIT_1; // -!- 0? void check_efuse() { //Check TP is burned into eFuse if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_TP) == ESP_OK) { Serial.println("eFuse Two Point: Supported"); } else { Serial.println("eFuse Two Point: NOT supported"); } //Check Vref is burned into eFuse if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_VREF) == ESP_OK) { Serial.println("eFuse Vref: Supported"); } else { Serial.println("eFuse Vref: NOT supported"); } } void print_char_val_type(esp_adc_cal_value_t val_type) { if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP) { Serial.println("Characterized using Two Point Value\n"); } else if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF) { Serial.println("Characterized using eFuse Vref"); } else { Serial.println("Characterized using Default Vref"); } } String NumToAtten(int atten) { switch (atten) { case 0: return "ADC_ATTEN_DB_0. No chages for the input voltage"; case 1: return "ADC_ATTEN_DB_2_5. The input voltage will be reduce to about 1/1.34."; case 2: return "ADC_ATTEN_DB_6. The input voltage will be reduced to about 1/2"; case 3: return "ADC_ATTEN_DB_11. The input voltage will be reduced to about 1/3.6"; } return "Unknown attenuation."; } String NumToWidth(int width) { switch (width) { case 0: return "ADC_WIDTH_BIT_9. ADC capture width is 9Bit"; case 1: return "ADC_WIDTH_BIT_10. ADC capture width is 10Bit"; case 2: return "ADC_WIDTH_BIT_11. ADC capture width is 11Bit"; case 3: return "ADC_WIDTH_BIT_12. ADC capture width is 12Bit"; } return "Unknown width."; } void adc_calibrate() { adc1_config_width(ADC_WIDTH_BIT_12); adc1_config_channel_atten(ADC_CHANNEL, ADC_ATTEN_DB_11); check_efuse(); //Characterize ADC at particular atten adc_chars = (esp_adc_cal_characteristics_t *)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); Serial.println("ADC number:\t" + String(adc_chars->adc_num)); Serial.println("ADC attenuation:\t" + NumToAtten(adc_chars->atten)); Serial.println("ADC bit width:\t" + NumToWidth(adc_chars->bit_width)); Serial.println("ADC coeff_a:\t" + String(adc_chars->coeff_a)); Serial.println("ADC coeff_b:\t" + String(adc_chars->coeff_b)); Serial.println("ADC VRef:\t" + String(adc_chars->vref)); //Check type of calibration value used to characterize ADC print_char_val_type(val_type); } // adc_calibrate #pragma endregion // ADC calibration // собственно измерение: uint32_t reading = 0; //Multisampling for (int i = 0; i < ADC_NO_OF_SAMPLES; i++) { reading += adc1_get_raw((adc1_channel_t)ADC_CHANNEL); } reading /= ADC_NO_OF_SAMPLES; uint32_t pinVolt = esp_adc_cal_raw_to_voltage(reading, adc_chars); // основная функция, преобразующая из измерянных сырых самплов (0..4095) в милливольты исходя из коэффициентов, измеренных при автокалибровке и сохраненных в струтуре adc_chars uint32_t mvolt = pinVolt * ADC_V_MULT; // это уже преобразую измеренные милливольты в оригинальные, поскольку использую делитель на резисторах Blynk.virtualWrite(VPIN_Voltage, mvolt); BLYNK_LOG6("mV: ", mvolt, " PinV: ", pinVolt, " Raw: ", reading); snprintf(str, 50, "mV: %5i, Volt: %5i, Raw: %5i", mvolt, pinVolt, reading); // Serial.println(str); terminal.println(str); terminal.flush(); snprintf(str, 20, "%5.2f", (float) mvolt / 1000);
Какая то ерунда с esp32. Все работало нормально и в какой то момент емкостной датчик влажность почвы стал выдавать ахинею. Когда включаею МК первое показание выдает правильное, последующие сваливает в 1 (на пине 3.3В). Пин 35, на 34 тоже самое. На обоих каналах датчики влажность (с map и без). На скетч не грешу, до этого все работало. Сдох АЦП? Но почему первое показание правильное, не успевает подтянуть питание? Как назло нет 2го контроллера проверить. P.S. Подключил потенциометр и показывает все правильно, такая ерунда только с емкостными датчиками влажности почвы, со всеми 5ти.
Не затруднит ли разъяснить принцип калибровки ESP32? Можно ли как-то прописать константы, относительно которых АЦП будет считать значение? У меня дикий разброс в значениях после каждой перезагрузки. Даже с учетом того, что я применяю софтовую калибровку, взятую из VoltMI. т.е. грубо при, например, 2V на входе АЦП может показать 2480, а может быть 2350, а может быть 2550. При этом шум незначительный, проблема именно в сдвиге точки. Такое ощущение, что после перезагрузки 1100mV, по которым калибруется чип разное, и калибровка, соответственно разная.