ADS1115 and AC => Power Monitor

Hi
I picked up a sct013 100A current clamp and a ads1115 for a homebrew powermonitor system using a pico/arduino.
I followed the write up by https://solarduino.com/diy-ac-energy-meter/ and this forum thread: https://forum.arduino.cc/t/solved-how-ac-current-can-connect-to-ads1115/953906 but the reading I'm getting out seem to be wrong or wrong accoring to my current meter.
I am using 2.5V to power the sct013 so in theory my lowest reading should be 0V and my highest 5V. Firstly is this wrong and secondly if someone could just go through my code and point out where my calculation is whack that would be great :sweat_smile:

/*/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/////////////*/
#include <WiFi.h>
#include <HTTPClient.h>
#include <Wire.h>
#include <Adafruit_ADS1X15.h>
/*/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/////////////*/
        /* 0- General */
        Adafruit_ADS1115 ads1115_1;	  
        Adafruit_ADS1115 ads1115_2;
        const byte PICO_I2C_SDA = 16;
        const byte PICO_I2C_SCL = 17;	     
        int timeOut = 0;
        int decimalPrecision = 1;                         // decimal places for large values such as voltage, wattage, apparent power, and frequency shown in LED Display & Serial Monitor
                                                          // decimal places for small values such as current, power factor and accumulate energy will be decimal places x 2.
        
        /* 1- AC Voltage Measurement */        
        float voltageSampleRead  = 0;                     /* to read the value of a sample*/
        float voltageLastSample  = 0;                     /* to count time for each sample. Technically 1 milli second 1 sample is taken */
        float voltageSampleSum   = 0;                     /* accumulation of sample readings */
        float voltageSampleCount = 0;                     /* to count number of sample. */
        float voltageMean ;                               /* to calculate the average value from all samples*/ 
        float RMSVoltageMean ;                            /* square roof of voltageMean*/
        /*1.1 Offset AC Voltage */    
        float voltageOffset1 = 0;                   // to Offset deviation and accuracy. Offset any fake current when no current operates. 
                                                          // Offset will automatically callibrate when SELECT Button on the LCD Display Shield is pressed.
                                                          // If you do not have LCD Display Shield, look into serial monitor to add or minus the value manually and key in here.
        float voltageOffset2 = 0;                   // to offset value due to calculation error from squared and square root.
        /* 2- AC Current Measurement */
        float mVperAmpValue = 31.25;                      // If using ACS712 current module : for 5A module key in 185, for 20A module key in 100, for 30A module key in 66
                                                          // If using "Hall-Effect" Current Transformer, key in value using this formula: mVperAmp = maximum voltage range (in milli volt) / current rating of CT
                                                          /* For example, a 20A Hall-Effect Current Transformer rated at 20A, 2.5V +/- 0.625V, mVperAmp will be 625 mV / 20A = 31.25mV/A */
        float currentSampleRead_1  = 0;                     /* to read the value of a sample*/
        float currentLastSample_1  = 0;                     /* to count time for each sample. Technically 1 milli second 1 sample is taken */
        float currentSampleSum_1   = 0;                     /* accumulation of sample readings */
        float currentSampleCount_1 = 0;                     /* to count number of sample. */
        float currentMean_1 ;                               /* to calculate the average value from all samples*/ 
        float RMSCurrentMean_1 =0 ;                         /* square roof of currentMean*/
        float FinalRMSCurrent_1 ;                           /* the final RMS current reading*/
        /*2.1 Offset AC Current */    
        float currentOffset1_1 = 0;                   // to Offset deviation and accuracy. Offset any fake current when no current operates. 
                                                          // Offset will automatically callibrate when SELECT Button on the LCD Display Shield is pressed.
                                                          // If you do not have LCD Display Shield, look into serial monitor to add or minus the value manually and key in here.
                                                          // 26 means add 26 to all analog value measured
        float currentOffset2_1 = 0;                   // to offset value due to calculation error from squared and square root.

        float currentSampleRead_2  = 0;                     /* to read the value of a sample*/
        float currentLastSample_2  = 0;                     /* to count time for each sample. Technically 1 milli second 1 sample is taken */
        float currentSampleSum_2   = 0;                     /* accumulation of sample readings */
        float currentSampleCount_2 = 0;                     /* to count number of sample. */
        float currentMean_2 ;                               /* to calculate the average value from all samples*/ 
        float RMSCurrentMean_2 =0 ;                         /* square roof of currentMean*/
        float FinalRMSCurrent_2 ;                           /* the final RMS current reading*/
        /*2.1 Offset AC Current */    
        float currentOffset1_2 = 0;                   // to Offset deviation and accuracy. Offset any fake current when no current operates. 
                                                          // Offset will automatically callibrate when SELECT Button on the LCD Display Shield is pressed.
                                                          // If you do not have LCD Display Shield, look into serial monitor to add or minus the value manually and key in here.
                                                          // 26 means add 26 to all analog value measured
        float currentOffset2_2 = 0;                   // to offset value due to calculation error from squared and square root.
        
        float currentSampleRead_3  = 0;                     /* to read the value of a sample*/
        float currentLastSample_3  = 0;                     /* to count time for each sample. Technically 1 milli second 1 sample is taken */
        float currentSampleSum_3   = 0;                     /* accumulation of sample readings */
        float currentSampleCount_3 = 0;                     /* to count number of sample. */
        float currentMean_3 ;                               /* to calculate the average value from all samples*/ 
        float RMSCurrentMean_3 =0 ;                         /* square roof of currentMean*/
        float FinalRMSCurrent_3 ;                           /* the final RMS current reading*/
        /*2.1 Offset AC Current */    
        float currentOffset1_3 = 0;                   // to Offset deviation and accuracy. Offset any fake current when no current operates. 
                                                          // Offset will automatically callibrate when SELECT Button on the LCD Display Shield is pressed.
                                                          // If you do not have LCD Display Shield, look into serial monitor to add or minus the value manually and key in here.
                                                          // 26 means add 26 to all analog value measured
        float currentOffset2_3 = 0;                   // to offset value due to calculation error from squared and square root.
        
        /* 5- frequency measurement */
        unsigned long startMicros;            /* start counting time for frequency (in micro seconds)*/
        unsigned long currentMicros;        /* current counting time for frequency (in micro seconds) */  
        int expectedFrequency = 46;                   // This is to collect number of samples. for 50Hz use 46 or below. For 60Hz use 54 or below.                         
        float frequencySampleCount = 0;           /* count the number of sample, 1 sample equivalent to 1 cycle */
        float frequency = 0;                      /* shows the value of frequency*/                       
        float switch01 = 9;                       /* use for switching function */
        float vAnalogRead = 0; 
        float zz;                                  /* use for calculation purpose*/    
        /* 5- wifi stuff */
        const char* ssid = "";                                                           /*SSID of the network being connected to*/
        const char* password = "";                                    /*Password of the network being connected to*/
        float lastReadingSent  = 0;                       /* to count time for reading send. Reading sent every 30000 milliseconds*/
        char * deviceName = "";
/*/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/////////////*/        
void setup()                                          /*codes to run once */
{                             
        /* 0- General */
        
        Serial.begin(115200);  

        Wire.setSDA(PICO_I2C_SDA);
        Wire.setSCL(PICO_I2C_SCL);
        Wire.begin();

        ads1115_1.begin(0x48);
        ads1115_2.begin(0x49);

        WiFi.setHostname("Power_Pico");
        WiFi.begin(ssid, password);
        Serial.println("Connecting");
        while(WiFi.status() != WL_CONNECTED) 
        {
          delay(500);
          Serial.print(".");
          timeOut = timeOut + 1;
          if(timeOut >= 30)
          {
            watchdog_reboot(0,0,300);    
          } 
        }      
        Serial.println("");
        Serial.print("Connected to WiFi network with IP Address: ");
        Serial.println(WiFi.localIP());   
        startMicros = micros();  
}
/*/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/////////////*/
void loop() 
{
        /* 1- AC Voltage Measurement */
        if(millis() >= voltageLastSample + 10)                                                    /* every 1 milli second taking 1 reading */
          {
            voltageSampleRead = 2*(ads1115_2.readADC_SingleEnded(2)- 32768) + voltageOffset1;      /* read the sample value */     
            voltageSampleSum = voltageSampleSum + sq(voltageSampleRead) ;                         /* accumulate value with older sample readings*/     
            voltageSampleCount = voltageSampleCount + 1;                                          /* to move on to the next following count */
            voltageLastSample = millis() ;                                                        /* to reset the time again so that next cycle can start again*/ 
          }
        
        if(voltageSampleCount == 100)                                                            /* after 1000 count or 1000 milli seconds (1 second), do the calculation and display value*/
          {     
            voltageMean = voltageSampleSum/voltageSampleCount;                                    /* calculate average value of all sample readings taken*/
            RMSVoltageMean = sqrt(voltageMean)+ voltageOffset2;                                   /* square root of the average value*/
            Serial.print(RMSVoltageMean,decimalPrecision);
            Serial.print(" V   ");
            voltageSampleSum =0;                                                                  /* to reset accumulate sample values for the next cycle */
            voltageSampleCount=0;                                                                 /* to reset number of sample for the next cycle */
          }
          
        /* 2- AC Current Measurement */        
        if(millis() >= currentLastSample_1 + 10)                                                     /* every 1 milli second taking 1 reading */
          {
            currentSampleRead_1 = ads1115_1.readADC_SingleEnded(0) - 32768 + currentOffset1_1;           /* read the sample value */
            currentSampleSum_1 = currentSampleSum_1 + sq(currentSampleRead_1) ;                         /* accumulate value with older sample readings*/
            currentSampleCount_1 = currentSampleCount_1 + 1;                                          /* to move on to the next following count */
            currentLastSample_1 = millis();                                                         /* to reset the time again so that next cycle can start again*/ 
          }
        
        if(currentSampleCount_1 == 100)                                                            /* after 1000 count or 1000 milli seconds (1 second), do the calculation and display value*/
          {
            currentMean_1 = currentSampleSum_1/currentSampleCount_1;                                    /* calculate average value of all sample readings taken*/
            RMSCurrentMean_1 = sqrt(currentMean_1)+currentOffset2_1 ;                                   /* square root of the average value*/
            FinalRMSCurrent_1 = (((RMSCurrentMean_1 /1024) *5000) /mVperAmpValue);                    /* calculate the final RMS current*/
            Serial.print("Phase 1 ");
            Serial.print(FinalRMSCurrent_1,decimalPrecision*2);
            Serial.println(" A   ");
            currentSampleSum_1 =0;                                                                  /* to reset accumulate sample values for the next cycle */
            currentSampleCount_1=0;                                                                 /* to reset number of sample for the next cycle */
          }

        /* 3- AC Current Measurement */        
        if(millis() >= currentLastSample_2 + 10)                                                     /* every 1 milli second taking 1 reading */
          {
            currentSampleRead_2 = ads1115_1.readADC_SingleEnded(1) - 32768 + currentOffset1_2;           /* read the sample value */
            currentSampleSum_2 = currentSampleSum_2 + sq(currentSampleRead_2) ;                         /* accumulate value with older sample readings*/
            currentSampleCount_2 = currentSampleCount_2 + 1;                                          /* to move on to the next following count */
            currentLastSample_2 = millis();                                                         /* to reset the time again so that next cycle can start again*/ 
          }
        
        if(currentSampleCount_2 == 100)                                                            /* after 1000 count or 1000 milli seconds (1 second), do the calculation and display value*/
          {
            currentMean_2 = currentSampleSum_2/currentSampleCount_2;                                    /* calculate average value of all sample readings taken*/
            RMSCurrentMean_2 = sqrt(currentMean_2)+currentOffset2_2 ;                                   /* square root of the average value*/
            FinalRMSCurrent_2 = (((RMSCurrentMean_2 /1024) *5000) /mVperAmpValue);                    /* calculate the final RMS current*/
            Serial.print("Phase 2 ");
            Serial.print(FinalRMSCurrent_2,decimalPrecision*2);
            Serial.println(" A   ");
            currentSampleSum_2 =0;                                                                  /* to reset accumulate sample values for the next cycle */
            currentSampleCount_2=0;                                                                 /* to reset number of sample for the next cycle */
          }
        
        /* 4- AC Current Measurement */        
        if(millis() >= currentLastSample_3 + 1)                                                     /* every 1 milli second taking 1 reading */
          {
            currentSampleRead_3 = ads1115_1.readADC_SingleEnded(2) - 32768 + currentOffset1_3;           /* read the sample value */
            currentSampleSum_3 = currentSampleSum_3 + sq(currentSampleRead_3) ;                         /* accumulate value with older sample readings*/
            currentSampleCount_3 = currentSampleCount_3 + 1;                                          /* to move on to the next following count */
            currentLastSample_3 = millis();                                                         /* to reset the time again so that next cycle can start again*/ 
          }
        
        if(currentSampleCount_3 == 1000)                                                            /* after 1000 count or 1000 milli seconds (1 second), do the calculation and display value*/
          {
            currentMean_3 = currentSampleSum_3/currentSampleCount_3;                                    /* calculate average value of all sample readings taken*/
            RMSCurrentMean_3 = sqrt(currentMean_3)+currentOffset2_3 ;                                   /* square root of the average value*/
            FinalRMSCurrent_3 = (((RMSCurrentMean_3 /1024) *5000) /mVperAmpValue);                    /* calculate the final RMS current*/
            Serial.print("Phase 3 ");
            Serial.print(FinalRMSCurrent_3,decimalPrecision*2);
            Serial.println(" A   ");
            currentSampleSum_3 =0;                                                                  /* to reset accumulate sample values for the next cycle */
            currentSampleCount_3=0;                                                                 /* to reset number of sample for the next cycle */
          }   
    sendReading(deviceName, RMSVoltageMean, FinalRMSCurrent_1, FinalRMSCurrent_2, FinalRMSCurrent_3, lastReadingSent);   
}
/*/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/////////////*/
void sendReading(char * deviceName, float RMSVoltageMean, float FinalRMSCurrent_1, float FinalRMSCurrent_2, float FinalRMSCurrent_3, float & lastReadingSent)
{
            const char* serverName = "";
            if(millis() >= lastReadingSent + 60000 )                                                /* every 30000 milli seconds sending 1 reading */
            {
              if(WiFi.status()== WL_CONNECTED)
              {                  
                  WiFiClient client;
                  HTTPClient http;
                  http.begin(client, serverName);
                  http.addHeader("Content-Type", "application/json");
                  String httpRequestData = "{\"deviceName\":\"" + String(deviceName) + "\",\"RMSVoltage\":" + String(RMSVoltageMean,decimalPrecision*2) + 
                                           ",\"RMSCurrentP1\":" + String(FinalRMSCurrent_1,decimalPrecision*2) +
                                           ",\"RMSCurrentP2\":" + String(FinalRMSCurrent_2,decimalPrecision*2) +
                                           ",\"RMSCurrentP3\":" + String(FinalRMSCurrent_3,decimalPrecision*2) + "}";  
                  Serial.println(httpRequestData);   
                  int httpResponseCode = http.POST(httpRequestData);
                  Serial.print("HTTP Response code: ");
                  Serial.println(httpResponseCode);
                  Serial.println();
                  http.end();                  /*Free Up resources*/
              }
              else 
              {
                  Serial.println("WiFi Disconnected");
                 timeOut = timeOut + 1;
                 if(timeOut >= 30)
                {
                  watchdog_reboot(0,0,300);    
                }  
              }
              lastReadingSent = millis() ;                                                        /* to reset the time again so that next cycle can start again*/ 
            } 
}

Please post a wiring diagram of the input circuitry.

This tutorial is a very useful resource, with clever Arduino code. Your CT should work fine with the suggested circuit and software.

I have no idea how people make those arduino sketches but I do have my pcb schematic. :sweat_smile:

Pencil and paper works fine to produce a wiring diagram. Otherwise, just follow the OpenEnergyMonitor schematic.

It aint pretty

Sorry, I can't make any sense of that. Unnamed parts, unidentified pins.

This is a sensible wiring diagram of the CT input circuitry, from the OpenEnergyMonitor site, and is an excellent example to follow.

Capture

Yeah this is pretty much what I'm doing, my current transform only has two wire so I have an external dc-dc circuit that gives me the 2.5v for the power wire.

Bad idea. The dc-dc circuit injects electrical noise.

A much better and cheaper idea is the standard approach of two resistors and a capacitor, as done in the OpenEnergyMonitor example.

I'll have a look on my oscilloscope what the noise floor looks like over the weekend, been using a simple voltage divider anyway :sweat_smile: (Only got the dc-dc converter today). Still don't know why my code is not outputting correctly though

You are using the defaults for the ADS1115 so the readings will represent 6.144V/2^15 bits, but I do not see this embodied anywhere in your code.

Fot the current reading I did supplement in the 2^15 part, can you maybe show which parts need to be modified?

ads1115_1.readADC_SingleEnded(2) - 32768

So you are reading current by a Hall sensor which outputs a voltage proportional to current right? And reading that voltage by the ADS1115 right?

Voltage at ADS1115(2) = ads1115_1.readADC_SingleEnded(2)*(6.144V/2^15);

And then whatever you do with that (i.e sample average and convert based on sensor conversion factor) to yield a current.

Hmmm let me try this out and then get back to just need to quickly setup a dummy load.
Thanks :100:

Quick and dirty you may just want read 5V or 3.3V off the MCU via the ADS1115 to make sure you have everything straight on how the ADS1115 single ended read works, then wire in the sensor and a load.

Cool I'll start with that, just need to setup everything again

Had a bit of a poke and I'm getting close all I need help figuring out now is the mVperAmp for the sct013

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