cancel
Showing results for 
Search instead for 
Did you mean: 

wrong voltage reading

meghasb
Senior

Hi,

i'm trying to read voltage through voltage divider circuit, o/p voltage is 3.2, but i could read only around 2.7, can some help whats wrong with the code

note: R1=6.8K ohm and R2=12K ohm.

im attaching circuit and code.

 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET);

   // get ADC value

   HAL_ADC_Start(&hadc1);

   HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);

   raw=HAL_ADC_GetValue(&hadc1);

  HAL_ADC_Stop(&hadc1);

   HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET);

  data= (3.3*raw/4095);

  uint8_t length= sprintf(msg, "%.3lf\r\n\0", data);

  HAL_UART_Transmit(&huart1, msg, length, 100);

0693W00000Y6maFQAR.png

6 REPLIES 6
S.Ma
Principal

Real world hardly is ideal.

When ADC is used to read the divider, during the sample and hold time, it will be equivalent to a low pass RC filter, which values are usually in the electrical adc table in datasheet.

Run calibration and put a cap to ground, or max out the sampling time to get closer.

If the chip has vdda pin make sure it is supplied.

AND, ground the mcu with the same ground as R1

we dont need to firmware by ourselves, lets talk
meghasb
Senior

Got it.. thanku

what do you see if you remove the voltage divider and tie the ADC to 3v3?

we dont need to firmware by ourselves, lets talk
gbm
Lead III

What you are trying to display (incorrectly) is the voltage at ADC input, not at the input of voltage divider.

With 12k/6k8 voltage divider, the proper formula for voltage in mV in your case is:

Vin_mV = adcval * Vdd_mV * (120 + 68) / 68 / 4096;

where Vdd_mV should be measured by acquiring Vref channel but for start it may be assumed to be 3300. Note that no floating point math is needed if you stick to mV instead of Volts. 🙂

Piranha
Chief II

It's better to avoid the additional division and ensure the calculation is always done with 32-bit integers:

Vin_mV = (uint32_t)adcval * Vdd_mV * (120 + 68) / (68 * 4096);

And even better to do the same with a correct rounding:

#define DIVU_ROUND(n, d)    ( ((n) + (d) / 2) / (d) )
 
Vin_mV = DIVU_ROUND((uint32_t)adcval * Vdd_mV * (120 + 68), 68 * 4096);