cancel
Showing results for 
Search instead for 
Did you mean: 

To measure AC current using ACS712 (30A) and STM32F030C8, what is the ideal configuration for ADC??

SSS
Associate

Problem Description:

We have interfaced STM32F030C8with ACS712(30A) current sensor.

We are having difficulty in measuring AC current accuetly. ADC values keep changing.

ACS712 works at 5V and STM adc operates at 3.3V. We collect adc samples for 1 min to find the minimum peak value(not max peak value) and then we do ADC peakValue * 3.3/4096.

At no load, We expect the ADC value to be 4096/2=2048, this is the offset value.

But this value keeps varying everytime when we run the code.

We are unable to understand, What could be causing this problem?

ADC Configuration(using Cubemx to generate initialization code, using polling method).

void MX_ADC_Init(void)

{

 ADC_ChannelConfTypeDef sConfig;

  /**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) 

  */

 hadc.Instance = ADC1;

 hadc.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;

 hadc.Init.Resolution = ADC_RESOLUTION_12B;

 hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;

 hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;

 hadc.Init.EOCSelection = ADC_EOC_SINGLE_CONV;

 hadc.Init.LowPowerAutoWait = DISABLE;

 hadc.Init.LowPowerAutoPowerOff = DISABLE;

 hadc.Init.ContinuousConvMode = DISABLE;

 hadc.Init.DiscontinuousConvMode = DISABLE;

 hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START;

 hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;

 hadc.Init.DMAContinuousRequests = DISABLE;

 hadc.Init.Overrun = ADC_OVR_DATA_PRESERVED;

 if (HAL_ADC_Init(&hadc) != HAL_OK)

 {

  _Error_Handler(__FILE__, __LINE__);

 }

  /**Configure for the selected ADC regular channel to be converted. 

  */

 sConfig.Channel = ADC_CHANNEL_6;

 sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;

 sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;

 if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)

 {

  _Error_Handler(__FILE__, __LINE__);

 }

}

statusCode_t GetADC(uint8_t DeviceID, adcChannel_t adcChannel, uint32_t *pAdcOut)

{

HAL_StatusTypeDef status = HAL_OK;

/* check for invalid slave address */

if(DeviceID != slaveAddr) return INVALID_DEVICEID;

status = HAL_ADC_Start(&hadc);              /* Start ADC          */

if(status != HAL_OK) return INTERNAL_ERROR;

status = HAL_ADC_PollForConversion(&hadc, adcTimeout); /* Poll for end of conversion */

if(status != HAL_OK) return INTERNAL_ERROR;

*pAdcOut = HAL_ADC_GetValue(&hadc);             /* Get adc value to pAdcOut  */

status = HAL_ADC_Stop(&hadc);               /* Stop the adc        */

if(status != HAL_OK) return INTERNAL_ERROR;       

return STATUS_OK;

}

double getVPP(uint8_t deviceID)

{

statusCode_t status;

 float result;

float maxValue_volts = 0.0;

float minValue_volts = 0.0;

 uint32_t readValue;    /* value read from the sensor */

 int maxValue = 0;     /* store max value here */

 int minValue = 4096;    /* store min value here */

 uint32_t start_time = 0;

 start_time = HAL_GetTick();

/* sample for 1 Sec */

 while((HAL_GetTick() - start_time) < 1000) 

{

/* read current sensor */

// status = GetADC(deviceID, ADC_5, &readValue); 

readValue = Relay_adcVal;

/* see if you have a new maxValue */

if (readValue > maxValue) 

{

/* record the maximum sensor value */

maxValue = readValue;

}

if (readValue < minValue) 

{

/* record the maximum sensor value */

minValue = readValue;

}

}

maxValue_volts = maxValue;

/* convert maxValue to the voltage with reference to STM32 board operating voltage i.e 3.3V */

maxValue_volts = (maxValue_volts * 3.3)/4096.0;

/* convert the maxValue_volts to the voltage with reference to ACS712 operatinf voltage i.e 5V */

maxValue_volts = (maxValue_volts * 5) / 3.3;

minValue_volts = minValue;

/* convert minValue to the voltage with reference to STM32 board operating voltage i.e 3.3V */

minValue_volts = (minValue_volts * 3.3)/4096.0;

return minValue_volts;

 }

statusCode_t get_AC_Current(uint8_t deviceID, relayChannel_t channelID, double *pAC_Current)

{

statusCode_t status = STATUS_OK;

double mVperAmp = 66; /* use 100 for 20A Module and 66 for 30A Module */

uint32_t RawValue = 0;

double ACSoffset = 2500; // based on the ADC value we got at zero load condition

double Voltage = 0;

uint8_t i = 0;

if(deviceID != slaveAddr) return INVALID_DEVICEID;

switch(channelID)

{

case RELAY_CHANNEL_1:

Voltage = getVPP(deviceID);

/* convert Voltage to mV by multiplying with 1000 */

Voltage = Voltage * 1000;

/* get current */

*pAC_Current = ((ACSoffset - Voltage) / mVperAmp);

 break;

case RELAY_CHANNEL_2:

    /* to be implemented in future version */

break;

default:

 return INVALID_PARAM;

}

return STATUS_OK;

}

2 REPLIES 2
AvaTar
Lead

> At no load, We expect the ADC value to be 4096/2=2048, this is the offset value.

> But this value keeps varying everytime when we run the code.

How much ?

Depending on the stability of Vref, you input circuitry, and noise, the input values will fluctuate several counts.

Check with the datasheet / ADC section.

Integrated ADCs in MCUs are a compromise. If you need higher accuracy and stability, consider an external ADC.

Else, sample more often, and average.

T J
Lead

sample at exactly 256x 50hz then just add the results/256 for an over sampled average.,

I checked the ACS712 datasheet (not for new designs) it has an opamp output drive, that's what we need.

on your ADC input,

did you try to read a static voltage, is the value static ?

1Volt should read 1/3.3 x 4096

don't use the fastest clocks or conversion rates, slow down a little to get added stability.