ESP32 analogPin read Issue with Moisture Sensor.

Hi all,

I am pretty new to all this but I am trying to get into it.

I am trying to use a ESP32- Heltec WiFi kit 32 with a capacitive soil moisture sensor. Everything works perfectly when I use my espressif-ESP32-WROOM-32D to read the value from the sensor connected on pin VP (36) which is ADC 0.

But

When I use the Heltec WiFi kit 32, it seems like it reads the value once at setup but then when reading the value in the loop it is always the same value (as setup). The value is what it is suppose to be and If I reset the Wifi kit 32 with the sensor in water the value changes to what it is suppose to be in water (basically if I keep resetting it reads the value each time.)

So it looks like it can read it and it works, it just won't do it in the loop and I can't figure out why.

According to the Heltec documentation the pin layout says that pin 36 is indeed an ADC pin, but anyway if I try with any other ADC pin it does the same thing.

The code (attached) I am running is very simple right now just to try to solve that issue.

Any thoughts on why the Heltec board does that? I would really like to use it for its embedded OLED display (and because I bought it...).
Otherwise I guess I'll hook up an OLED to another ESP32.

Board:
Heltec - WiFi Kit 32:
https://heltec.org/project/wifi-kit-32/

Capacitive soil moisture sensor v1.0:

Connections:
A > Pin 36

  • 5V

  • GND

Thanks for the support !

Basic_sensor_tester.ino (341 Bytes)

Change your Code... You initialize the varaible sensorVal only once (after reset) with the analog value, which is the sam as if you place the analogRead in the setup-function. You have to place the analogRead into the loop:

int sensorVal;

void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
Serial.println("Setup done");
sensorVal = analogRead(inputPin); // if you nee a startup value, otherwise delete this line
delay(500);
}

void loop() {
// put your main code here, to run repeatedly:
sensorVal = analogRead(inputPin); // measrure repeatedly!
// you can also use the ACD-Name analogRead(A0); or use some proper name

Serial.print("sensor val :");
Serial.println(sensorVal);
delay(2000);
}

Other thoughts on the ADC of the ESP32-Controller...
The minimum analog input voltage is 150mV, and above 2.45V the ADC becomes non-linear (see datasheet!).
Only the input-range between 0.15V and 2.45V (ADC-value 0 to 3000 approx.) is usable.
If i want to read a voltage, i use the map-function:

int Millivolts = map (analogRead(A0), 0, 3000, 150, 2450);
// map to millivolts, has to be calibrated!

The other thing with the ESP32 is that you can't use analog inputs above ADC7 (only ADC0 to ADC7 on GPIO32-39) when you are using WiFi - and that's what most people use the ESP32 for...
see Page not Found - ESP32 - — ESP-IDF Programming Guide latest documentation

b_spi:
Other thoughts on the ADC of the ESP32-Controller...
The minimum analog input voltage is 150mV, and above 2.45V the ADC becomes non-linear (see datasheet!).
Only the input-range between 0.15V and 2.45V (ADC-value 0 to 3000 approx.) is usable.
If i want to read a voltage, i use the map-function:

int Millivolts = map (analogRead(A0), 0, 3000, 150, 2450);
// map to millivolts, has to be calibrated!

The other thing with the ESP32 is that you can't use analog inputs above ADC7 (only ADC0 to ADC7 on GPIO32-39) when you are using WiFi - and that's what most people use the ESP32 for...
see Page Not Found - ESP32 - — ESP-IDF Programming Guide latest documentation

Thnx for this info! I've had no end of frustration with this non-linear ADC response . . . lots of conflicting info but this solved my particular issue. I only needed to measure 0-5VDC - voltage diver was fine at 5V, but non-linear below that.

I took your suggestion and dropped the input V to 2VDC, mapped the ADC and voila, stable, linear response.

thnx again!!

billd

I find that with the ESP32, to het the best results from the A:D is to use the ESP32 A:D API
Page not Found - ESP32 - — ESP-IDF Programming Guide latest documentation instead of the Arduino way.

#include "sdkconfig.h"
#include "esp_system.h" //This inclusion configures the peripherals in the ESP system.
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/timers.h"
#include "freertos/event_groups.h"
#include <SimpleKalmanFilter.h>
#include <driver/adc.h>
#include "driver/mcpwm.h"
2000 mocrosecond
const int TaskCore1 = 1;
const int TaskCore0 = 0;
const int TaskStack20K = 20000;
const int Priority3 = 3;
const int Priority4 = 4;
const int SerialDataBits = 115200;
const int servo_EW_Park = 900; //using writeMicroseconds
const int servo_NS_Pin = GPIO_NUM_12; //
const int servo_NS_Park = 900; //using writeMicroseconds
////
void setup()
{
  // https://dl.espressif.com/doc/esp-idf/latest/api-reference/peripherals/adc.html
  // set up A:D channels
  adc_power_on( );
  vTaskDelay( 1 );
  adc1_config_width(ADC_WIDTH_12Bit);
  // ADC1 channel 0 is GPIO36 (ESP32), GPIO1 (ESP32-S2)
  adc1_config_channel_atten(ADC1_CHANNEL_0 , ADC_ATTEN_DB_11);
  // ADC1_CHANNEL_3  ADC1 channel 3 is GPIO39 (ESP32)
  adc1_config_channel_atten(ADC1_CHANNEL_3, ADC_ATTEN_DB_11);
  // ADC1 channel 5 is GPIO33
  adc1_config_channel_atten(ADC1_CHANNEL_5, ADC_ATTEN_DB_11);
  // ADC1 channel 6 is GPIO34
  adc1_config_channel_atten(ADC1_CHANNEL_6, ADC_ATTEN_DB_11);
  // adc for light dark detection, ADC1 channel 7 is GPIO35 (ESP32)
  adc1_config_channel_atten(ADC1_CHANNEL_7, ADC_ATTEN_DB_11);
  //
  mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM1A, GPIO_NUM_4 ); // Azimuth
  mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0A, GPIO_NUM_12 ); // Altitude servo
  //  ////
  mcpwm_config_t pwm_config = {};
  pwm_config.frequency = 50;    //frequency = 50Hz, i.e. for every servo motor time period should be 20ms
  pwm_config.cmpr_a = 0;    //duty cycle of PWMxA = 0
  pwm_config.cmpr_b = 0;    //duty cycle of PWMxb = 0
  pwm_config.counter_mode = MCPWM_UP_COUNTER;
  pwm_config.duty_mode = MCPWM_DUTY_MODE_0;
  mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_0, &pwm_config);    //Configure PWM0A timer 0 with above settings
  mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_1, &pwm_config);    //Configure PWM0A timer 1 with above settings
  ////
  fMoveAltitude( 1500 );
  vTaskDelay( 10 );
  fMoveAzimuth( 1500 );
  vTaskDelay(10);
  ////
  xTaskCreatePinnedToCore( fDaylight, "fDaylight", TaskStack20K, NULL, Priority3, NULL, TaskCore0 ); // assigned to core
}
////
void mcpwm_gpio_initialize(void)
{
  mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM1A, GPIO_NUM_4 );
  mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0A, GPIO_NUM_12 );
}
void TrackSun( void * pvParameters )
{
  int Altitude = 1500;
  int Azimuth = 1500;
  int maxAltitudeRange = 2144;
  int minAltitudeRange = 900;
  int maxAzimuthRange = 2144;
  int minAzimuthRange = 900;
  SimpleKalmanFilter kfAltitude0( 5.0, 10.0, .01 ); // kalman filter Altitude 0
  SimpleKalmanFilter kfAltitude1( 5.0, 10.0, .01 ); // kalman filter Altitude 1
  SimpleKalmanFilter kfAzimuth0( 5.0, 5.0, .01 ); // kalman filter Azimuth 0
  SimpleKalmanFilter kfAzimuth1( 5.0, 5.0, .01 ); // kalman filter Azimuth 1
  float filteredAltitude_0 = 0.0f;
  float filteredAltitude_1 = 0.0f;
  float filteredAzimuth_0 = 0.0f;
  float filteredAzimuth_1 = 0.0f;
  int64_t AzimuthEndTime = esp_timer_get_time();
  int64_t AzimuthStartTime = esp_timer_get_time(); //gets time in uSeconds like Arduino Micros,
  int64_t AltitudeEndTime = esp_timer_get_time();
  int64_t AltitudeStartTime = esp_timer_get_time(); //gets time in uSeconds like Arduino Micros,
 float AltitudeThreashold = 80.0f;
float AzimuthThreashold = 60.0f;
  while (1)
  {
    //Altitude
    AltitudeEndTime = esp_timer_get_time() - AltitudeStartTime; // produce elasped time for the simpleKalmanFilter
    kfAltitude0.setProcessNoise( (float)AltitudeEndTime / 1000000.0f ); //convert time of process to uS, update SimpleKalmanFilter q
    kfAltitude1.setProcessNoise( (float)AltitudeEndTime / 1000000.0f ); //convert time of process to uS, update SimpleKalmanFilter q
    filteredAltitude_0 = kfAltitude0.updateEstimate( (float)adc1_get_raw(ADC1_CHANNEL_3) );
    filteredAltitude_1 = kfAltitude1.updateEstimate( (float)adc1_get_raw(ADC1_CHANNEL_0) );
    if ( (filteredAltitude_0 > filteredAltitude_1) && (abs(filteredAltitude_0 - filteredAltitude_1) > AltitudeThreashold))
    {
      Altitude -= 1;
      if ( Altitude < minAltitudeRange )
      {
        Altitude = 1500;
      }
      fMoveAltitude( Altitude );
      vTaskDelay( 12 );
      AltitudeStartTime = esp_timer_get_time();
    }
    if ( (filteredAltitude_0 < filteredAltitude_1) && (abs(filteredAltitude_0 - filteredAltitude_1) > AltitudeThreashold) )
    {
      Altitude += 1;
      if ( Altitude >= maxAltitudeRange )
      {
        Altitude = 1500;
      }
      fMoveAltitude( Altitude );
      vTaskDelay( 12 );
      AltitudeStartTime = esp_timer_get_time();
    }
    // Serial.println();
    //// AZIMUTH
    AzimuthEndTime = esp_timer_get_time() - AzimuthStartTime; // produce elasped time for the simpleKalmanFilter
    kfAzimuth0.setProcessNoise( (float)AzimuthEndTime / 1000000.0f ); //convert time of process to uS, update SimpleKalmanFilter q
    kfAzimuth1.setProcessNoise( (float)AzimuthEndTime / 1000000.0f ); //convert time of process to uS, update SimpleKalmanFilter q
    filteredAzimuth_0 = kfAzimuth0.updateEstimate( (float)adc1_get_raw(ADC1_CHANNEL_5) );
    filteredAzimuth_1 = kfAzimuth1.updateEstimate( (float)adc1_get_raw(ADC1_CHANNEL_6) );
    if ( (filteredAzimuth_0 > filteredAzimuth_1) && (abs(filteredAzimuth_0 - filteredAzimuth_1)) > AzimuthThreashold )
    {
      Azimuth += 2;
      if ( Azimuth >= maxAzimuthRange )
      {
        Azimuth = 900;
      }
      fMoveAzimuth( Azimuth );
      vTaskDelay( 12 );
      AzimuthStartTime = esp_timer_get_time();
    }
    //    //
    if ( (filteredAzimuth_0 < filteredAzimuth_1) && (abs(filteredAzimuth_1 - filteredAzimuth_0)) > AzimuthThreashold )
    {
      Azimuth -= 2;
      if ( (Azimuth >= maxAzimuthRange) || (Azimuth <= minAzimuthRange) )
      {
        Azimuth = 900;
      }
      fMoveAzimuth( Azimuth );
      vTaskDelay( 12 );
      AzimuthStartTime = esp_timer_get_time();
    }
    vTaskDelay( 30 );
    //
  } // while(1)
} //void TrackSun()