Need help reading an analog voltage using ADC pins

We are trying to use a ESP32 WRover-B to read the voltage level out of a sensor and no matter what we try we are unable to get a consistent reading using the ADC Pins. Our circuit is currently outputting a very consistent AC voltage of about 600 mV.

We currently are trying to read this voltage using pin 34 of the WRover, which according to the specs would equate to ADC1 A6. Using the Serial Plotter we can see that the voltage does vary as one would expect from an AC voltage; however, our readings are showing the maximum voltage output of the Arduino quite frequently, and are quite often incredibly inconsistent.

We have tried a number of different circuit configurations that read clean outputs on a multimeter and an ammeter, and we have been unable to read consistent data from any of them, let alone correct data, so we are under the impression that our software has an error we haven't been able to figure out.

This is my first time posting in these forums so hopefully the picture comes through clearly. Apparently new users are only allowed to put in one image per post so I'll just paste the code and include a picture of the Arduino pins we're using, i.e. Ground, 3.3V, and pin 34 for reading.

#include <driver/adc.h>

uint16_t volt = 0;

#define ADC_PIN 34

void setup() {
  // put your setup code here, to run once:
  pinMode(ADC_PIN, INPUT);


  analogReadResolution(10);
  analogSetAttenuation(ADC_2_5db);  //For all pins

  Serial.begin(19200);

  Serial.println("Starting");

  adc1_config_channel_atten(ADC1_CHANNEL_6, ADC_ATTEN_DB_11);



  
}

uint16_t get_max() {
  uint16_t max_v = 0;
  for(uint16_t i = 0; i < 10000; i++) {
    uint16_t r = analogRead(ADC_PIN);  // 
    if(max_v < r) max_v = r;
    delayMicroseconds(100);
  }
  return max_v;
}


void loop() {
  // put your main code here, to run repeatedly:


  volt = analogRead(ADC_PIN);
  Serial.print("Volt Integer: ");
  Serial.println(volt);


  delay(1000);

}

First, you're talking about AC voltage: what kind of AC signal you're trying to read? I mean, what you mean with "consistent", what kind of signal is (in terms of frequency, and fixed or variable), what circuit generates it, and what you exactly need to detect.
Second, together with the previous information, post here also your serial plotter display (capture it with any screen capture and paste it here inside your message or as JPG attachment) and some serial output.
Third, are you sure you have GND in common between the signal and Arduino?

PS: why you have that unused "get_max" function? Do the code shown here is the exact and full code you're running to test? Remember, never post "partial" code, we need to examine a full code and, if possible, compile and test it!

How I set up a ADC on a ESP32.

#include <driver/adc.h>
#include <SimpleKalmanFilter.h>


voiding setup()
{
  eg = xEventGroupCreate(); // get an event group handle
  x_message.topic.reserve(100);
  adc1_config_width(ADC_WIDTH_12Bit);
  adc1_config_channel_atten(ADC1_CHANNEL_6, ADC_ATTEN_DB_11);// using GPIO 34 wind direction
  adc1_config_channel_atten(ADC1_CHANNEL_3, ADC_ATTEN_DB_11);// using GPIO 39 current
  adc1_config_channel_atten(ADC1_CHANNEL_0, ADC_ATTEN_DB_11);// using GPIO 36 battery volts

}


void fReadBattery( void * parameter )
{
  const float r1 = 50500.0f; // R1 in ohm, 50K
  const float r2 = 10000.0f; // R2 in ohm, 10k potentiometer
  const TickType_t xFrequency = 1000; //delay for mS
  float    adcValue = 0.0f;
  float    Vbatt = 0.0f;
  int      printCount = 0;
  float    vRefScale = (3.3f / 4096.0f) * ((r1 + r2) / r2);
  uint64_t TimePastKalman  = esp_timer_get_time(); // used by the Kalman filter UpdateProcessNoise, time since last kalman calculation
  SimpleKalmanFilter KF_ADC_b( 1.0f, 1.0f, .01f );
  TickType_t xLastWakeTime = xTaskGetTickCount();
  for (;;)
  {
    adc1_get_raw(ADC1_CHANNEL_0); //read and discard
    adcValue = float( adc1_get_raw(ADC1_CHANNEL_0) ); //take a raw ADC reading
    KF_ADC_b.setProcessNoise( (esp_timer_get_time() - TimePastKalman) / 1000000.0f ); //get time, in microsecods, since last readings
    adcValue = KF_ADC_b.updateEstimate( adcValue ); // apply simple Kalman filter
    Vbatt = adcValue * vRefScale;
    xSemaphoreTake( sema_CalculatedVoltage, portMAX_DELAY );
    CalculatedVoltage = Vbatt;
    xSemaphoreGive( sema_CalculatedVoltage );
    
      printCount++;
      if ( printCount == 3 )
      {
      //log_i( "Vbatt %f", Vbatt );
      printCount = 0;
      }
    
    TimePastKalman = esp_timer_get_time(); // time of update complete
    xLastWakeTime = xTaskGetTickCount();
    vTaskDelayUntil( &xLastWakeTime, xFrequency );
    //log_i( "fReadBattery %d",  uxTaskGetStackHighWaterMark( NULL ) );
  }
  vTaskDelete( NULL );
}

Hope it helps.

From the ESP32 documentation:
The ESP32 ADC can be sensitive to noise leading to large discrepancies in ADC readings. Depending on the usage scenario, users may connect a bypass capacitor (e.g. a 100 nF ceramic capacitor) to the ADC input pad in use, to minimize noise. Besides, multisampling may also be used to further mitigate the effects of noise.

I dint think you could measure an AC. Waveform with the ADC .
As it’s 600mV you will have got away without damage . 600mV is only using a small part of the ADC. Range
If you are randomly reading ADC values you will get a different result depending on which part of the waveform the ADC measures.

What is the sensor and how is it powered ?

I love secrets.

Mains frequency?

The common way is to bias that voltage midway the supply of the ESP with a voltage divider,
so the ESP outputs half of the A/D range (4096/2) without AC signal.
Then read the analogue pin continuously for a time period of at least 3/4 of the sinewave,
while storing min and max deviation from mid A/D in two variables.
Subtract those two variables from each other to find a peak/peak value, that can be converted to a voltage value.
Leo..

Are you certain that the thing is a sensor?

Certainty is an utopistic concept, especially if we miss information.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.