I'm trying to track down a clearly/simply articulated piece of code to take a reading from the ACS712 current sensor (link to download PDF data sheet).

I understand that these sensors are noisy, and that reading AC current is quite different to DC current.

After looking at a range of examples in a variety of forums etc., I've based the following on http://henrysbench.capnfatz.com/henrys-bench/acs712-arduino-ac-current-tutorial/

void ac_read() {
  int rVal = 0;
  int maxVal = 0;
  int minVal = 1023;
  int sampleDuration = 100; // 100ms

  uint32_t startTime = millis();
  // take samples for 100ms
  while((millis()-startTime) < sampleDuration)
    rVal = analogRead(A0);
    if (rVal > maxVal) 
      maxVal = rVal;

    if (rVal < minVal) 
      minVal = rVal;

  // Subtract min from max to determine the peak to peak range
  // 1023 = the max value we'll get on the input (1024, zero indexed)
  // 5.0 = 5v total on adc input
  double volt = ((maxVal - minVal) * (5.0/1023.0));

  // div by 2 is to calculate RMS from peak to peak
  // 0.35355 is factor to calculate RMS from peak to peak
  // see http://www.learningaboutelectronics.com/Articles/Voltage-rms-calculator.php
  double voltRMS = volt * 0.35355;

  // x 1000 to convert volts to millivolts
  // divide by the number of millivolts per amp to determine amps measured
  // the 20A module 100 mv/A (so in this case ampsRMS = voltRMS
  double ampsRMS = (voltRMS * 1000)/100;

I unfortunately don't have sufficient test equipment at present to validate this, but I'm getting a value of around 8.9 for a 2300W device, which afaict is roughly accurate (based on this calculator http://www.rapidtables.com/calc/electric/Watt_to_Amp_Calculator.htm).

Is anyone able to confirm the above makes sense/is logical/sane? Is there anything obviously incorrect?

  • 1
    I think I've just worked it out—typo in my code should have been x 1000 for millivolts (which I copy and pasted into the comments). Will update the example in a sec. – Grant Jan 7 '16 at 7:02
  • Is anyone working with ACS 712 current measurement module with Arduino? I saw some emote on instructables.com/id/… which uses the differential amplifier after the module. I want to know , we should use the differential ckt or no/? Currently I didnt used the ckt and use the module alone and I have the 2.68 v permanently even after the load connection. I checked the module with a magnet and responds properly. – user16771 Jan 27 '16 at 13:13
  • Hi Ata—yes, I've successfully got the ACS712 working with AC on Arduino—see the answer marked as "correct" below, as this was the basic approach I used. You don't need a differential amplifier, but if you don't use that you need to do extra work in code. Assuming you're working with AC not DC (DC is much more straightforward). – Grant Jan 27 '16 at 22:52

Measuring the peak-to-peak current and scaling the result will get you an answer which will at least go up and down with the magnitude of your average AC current, so yes it is NOT incorrect. As you suggested it will be sensitive to noise from the sensor - in fact as you are taking the highest and lowest single readings the noise will always cause the measurement to be higher than actual.

However, I think you could do better. Given that the code is already having to take many samples (basically as fast as it can) for 100mS (which will sample 5 cycles of the waveform if it is 50Hz and 6 if it is 60Hz, depending on where you are in the world), then you could actually do the maths to measure the RMS value and by basing this on all of the signal the effect of the noise will be reduced.

You need to know the ADC reading when there is no current rZero (which should be around 511 but could be off a bit due to offset errors) - you could measure this with nothing connected to calibrate the sensor, or take a long term average even with the AC signal present.

As the henrysbench tutorial points out it is important that the Arduino samples the signal at a high enough frequency (say 1000Hz - hence 100 samples for your 100mS sample duration)- the count of the number of times that the while loop executes sampleCount will confirm if this still the case even with the extra computation time of this code.

Also if you increase the sample time please be careful that the unsigned long rSquaredSum can't overflow, but I would avoid use of doubles within the while loop as they will definitely slow it down a LOT.

void ac_read() {
  int rVal = 0;
  int sampleDuration = 100;       // 100ms
  int sampleCount = 0;
  unsigned long rSquaredSum = 0;
  int rZero = 511;                // For illustrative purposes only - should be measured to calibrate sensor.

  uint32_t startTime = millis();  // take samples for 100ms
  while((millis()-startTime) < sampleDuration)
    rVal = analogRead(A0) - rZero;
    rSquaredSum += rVal * rVal;

  double voltRMS = 5.0 * sqrt(rSquaredSum / sampleCount) / 1024.0;

  // x 1000 to convert volts to millivolts
  // divide by the number of millivolts per amp to determine amps measured
  // the 20A module 100 mv/A (so in this case ampsRMS = 10 * voltRMS
  double ampsRMS = voltRMS * 10.0;
  • Thanks @c-barnes. I'd seen something akin to this approach in my initial research (yours is clearer than other examples I'd seen, so thanks!), but given the need for the rZero value I hadn't pursued it. As I expect this code to run on a number of devices/with a variety of sensors, I'm interested in how I could "take a long term average even with the AC signal present". Are you able to point to an example or explain how this would be done with the AC present? The other option would be to implement a "calibrate" mode when no devices are attached to get this value. – Grant Jan 8 '16 at 4:28
  • I'm pretty sure you've got to use rZero – the sensor (if is the one I'm thinking of, haven't looked specifically for it tonight) reads +/- current, since the ADC can't give you a negative value the sensor uses Vcc/2 as the quiescent (0 A) voltage. Subtracting rZero gives you the negative part of the range. – dlu Jan 8 '16 at 5:14
  • You mention that you don't have much test equipment, but you don't need any to measure rZero – just let the device run for a bit with no load (disconnect or turn it off) and average a few readings – they should be close to 511/512 but may be off by a bit. The average is rZero. – dlu Jan 8 '16 at 5:24
  • The beauty of AC is that it averages out to nothing, which is why you needed to measure RMS in the first place. So even when AC is present if you just accumulate the sampled values and, as above, divide by the number of samples at the end of the period you will get an estimate of rZero. The only issue is that the AC only averages out to zero if you measure over a whole number of cycles. If you know the AC frequency you can set sampleDuration accordingly, or sample over a much longer time (few seconds) so that any non whole cycle is a small proportion of the total. – C Barnes Jan 8 '16 at 18:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.