Help monitoring 2 phases of AC current only ADS1115 & NodeMCU

Bookmark this thread in your browser, or click on your icon a couple of times till you come to a page with “Summary” and “Activity” on it, where some/all your posts are listed, and find it that way.

If you’re away for a while, I’ll post my version in full here. It’s not tested, but I’m bound to lose it if I don’t.

#include <ESP8266WiFi.h>
#include <Wire.h>
#include <Adafruit_ADS1015.h>

Adafruit_ADS1115 ads;  

double offsetI;
double filteredI;
double sqI,sumI;
int16_t sampleI;
double Irms;
double squareRoot(double fg)  
{
  double n = fg / 2.0;
  double lstX = 0.0;
  while (n != lstX)
  {
    lstX = n;
    n = (n + fg / n) / 2.0;
  }
  return n;
}

double calcIrms(unsigned int Number_of_Samples, byte inputChannel)
// A byte is unsigned, 8 bits wide. You'll only ever need 2 bits here (inputs 0-3)
{
  float multiplier = 0.02F;    
  for (unsigned int n = 0; n < Number_of_Samples; n++)
  {
    sampleI = ads.readADC_SingleEnded(inputChannel);

    //  Digital low pass filter extracts the 2.5 V or 1.65 V dc offset, 
    //  then subtract this - signal is now centered on 0 counts.
    offsetI = (offsetI + (sampleI-offsetI)/1024);
    filteredI = sampleI - offsetI;
    
    // Root-mean-square method current
    // 1) square current values
    sqI = filteredI * filteredI;
    // 2) sum 
    sumI += sqI;
  }
  
  Irms = squareRoot(sumI / Number_of_Samples)*multiplier; 

  //  Reset accumulators
  sumI = 0;
  //--------------------------------------------------------------------------------------       
 
  return Irms;
}

void setup() {
  Serial.begin(9600);
  delay(10);
  ads.setGain(GAIN_ONE);        // 1x gain   +/- 4.096V  1 bit = 2mV      0.125mV
  ads.begin();
}

void loop() {
     
  double IrmsA = calcIrms(1480, 0);
  double IrmsB = calcIrms(1480, 1);     // I'm guessing this is the second channel
  Serial.print(IrmsA); 
  Serial.print("  ");
  Serial.print(IrmsB); 
  Serial.println(" "); 
}

/**********************************************************************
 
On a practical level, you will need to change "1480" to a value which gives you 
the number of samples as close as possible to a whole number of mains cycles, 
and about 200 ms worth, because if you have an "overhang" of say ¼-cycle, you'll 
have an error which varies according to where you catch the mains cycle - unless 
you have so many cycles that the error is negligible.

**********************************************************************/

I’ve got a list of books & on-line resources.

1 Like

Thanks Robert,

I’m over the anxious moment having achieved one hardware project, putting a fan on the wood stove. Ha! I’ll probably get back on it tonight. :crazy_face: while it’s still fresh in my brain, waiting for a month or more I’d be back at SQ1.

Here is my most successful hardware project and really where I learned about Arduino and figured out all the code required to make it work. As you can see, it’s a real hardware project. Hope it’s okay to post non energy subject matter here. Also, if you go from that video to my main page you can see part 1 of the Telecine machine as well as the generator I am building this 2 phase monitor for.

Paul’s Telecine project

PS I am not going to read your last post with the code yet, I’m going to study post 19 for a while and see if I can figure it out myself. It’s just started raining again so I can’t complete any outdoor projects for now, time for more code writing.

Thank you.

Paul

Good morning gentlemen,

I spent a further 3 hours working on the code, trying to get the 2 channels reading correctly then finally gave in and I looked at Roberts code…oh man, how simple is that? I was changing all the code within the {} loop, obviously the wrong loop to modify. Robert, your code works perfectly, I thank you. I spent another hour trying to figure out why it works, but couldn’t. If you have time, I would appreciate a brief explanation, and then point me to your recommended online learning resources please.

So now that it’s working I want to go through the code and ensure the ADS1115 is working at its highest speed of 860s/s. I have the 1015 on the way but want to learn how the libraries interact with the sketch, I should be able to figure this out. I also find that there are several different libraries for the ADS1115/1015 which I am also going to play with.

The current measurements are very accurate, at least for me, from .5A up to 12A, reads within .1A of my Fluke 333 clamp meter, and all data is being passed to Thingspeak successfully.

Thank you both for getting me this far, I’m going to continue tweaking and playing to ensure it’s 100%.

cheers

Paul

1 Like

I told you you were changing too much :wink: I did try to tell you a few posts ago:

OK, a function in C (or C++, except it’s called a “method” there when it’s part of a ‘class’) can be invoked with no parameters, or many. When it’s done its job, it can return one or no value.

double squareRoot(double fg)
{
  ...
  return n;
}

When you invoke it, you give it a number to work with, a double precision floating point variable. Outside of the function, that variable can be called anything. Inside, the value of the variable is assigned to fg. You can do what you like with it inside the function, it has absolutely no effect outside. (If you’ve got an fg outside the function, it is NOT the same variable! The two can exist entirely separately. If you want to learn more, the words are “scope of variables”.)
When the function has done its thing, it (the function itself) has the value of n, so you can use it wherever you can use a variable (or a constant).
Inside the function, you use fg in exactly the same way as any variable anywhere in a program, but it only exists inside the function. You can’t know anything about it outside.

So, when I wrote

followed by

what I was trying to tell you was to look at the 1480 in double current = calcIrms(1480); and work out how it uses that number to read 1480 samples inside calcIrms.
The answer is of course the parameter Number_of_Samples is assigned the value 1480 when you call the function, and so in the line
for (unsigned int n = 0; n < Number_of_Samples; n++)
Number_of_Samples is replaced by the number 1480, and it does the stuff inside the curly brackets 1480 times (from n = 0 to n = 1479), making n bigger by one (n++) each time.
Is it now clear what I did? I changed the 0 in ads.readADC_SingleEnded(0); into a variable so that I could vary it :dizzy_face:, and then made that variable a parameter in the function call so that I could feed the channel number into the function from outside.

And the rest was hopefully obvious (now, if not then).

You should have noticed I wrote above “When the function has done its thing, it (the function itself) has the value of n, so you can use it wherever you can use a variable (or a constant).”

Can you see anything wrong with writing this at the end of loop():

  Serial.print(calcIrms(1480, 0)); 
  Serial.print("  ");
  Serial.print(calcIrms(1480, 1)); 
  Serial.println(" "); 

The correct answer is NO, calcIrms(...)will get the samples and calculate the current, and return the value to Serial.print, which will print it. If you want the value again though, you can’t have it because it’s gone. That’s the only reason I created IrmsA & IrmsB because I reckoned you’d want the values again somewhere.

A function that doesn’t return a value is called a “void function” and it has to do something elsewhere to be useful. Quite often, functions that do something elsewhere, like writing to a disc or to EEPROM, do in fact return a value that will indicate success or failure.
You declare a void function with the keyword “void”, like this for setting values in emonLibDB:
void EmonLibDB_set_vInput(uint8_t input, double _amplitudeCal, double _phase) {... }
because there’s not a lot I can do even to mark an error - the emonTx4 can’t easily answer back and report it. You can’t use a void function like I suggested in Serial.print, it makes no sense (and the compiler would probably complain). It has to be a statement on its own.

1 Like

This could be part of my problem, the old brain just isn’t what it used to be.

Robert, thank you so much for the detailed explanation, I am going to study it again and try to understand exactly why it works. My son is here for the weekend so I will get back to this tomorrow evening. I referred to the Arduino reference section a few times to figure out some functions and terms etc… I’m going to search for a good online resource so I can learn much more about Arduino’s C++.

Thank you again!

Paul

1 Like

I think I might have beaten you to it, so I’m not buying that as an excuse :innocent:

Sorry, I forgot it, here’s the reading list:

My bible for C is of course “Kernigan & Ritchie” http://www.amazon.co.uk/C-Programming-Language-2nd/dp/0131103628/ref=sr_1_3?s=books&ie=UTF8&qid=1292502807&sr=1-3. This is the standard text book. The normal place I point people at who want to move up to C++ is C++ In Action: Industrial Strength Programming Techniques - Free Computer, Programming, Mathematics, Technical Books, Lecture Notes and Tutorials and that assumes you know C. Because the Arduino environment normally uses a very small subset of the language, neither are the best place for a beginner to start, nor are many of the other on-line tutorials. I’d still suggest you have both of those, and maybe Bruce Eckel’s “Thinking in C++”

http://engineering.nyu.edu/gk12/amps-cbri/pdf/ArduinoBooks/Arduino%20Programming%20Notebook.pdf does look to be a good starting place for a beginner, though I’ve not checked through it in detail. It does not go as far as classes and methods that are used here. For that, you need “Cpp In Action…” or one of the references below.

Learn C++ (Codecademy): Learn C++ | Codecademy

Object Oriented Programming with C++ - CodeProject (I’ve not been through this.)

O’Reilly Arduino Cookbook by Michael Margolis ISBN 978-1-449-31387-6 It’s pretty much ANSI C rather than C++ though.

Thank you for all those references, as I know NOTHING about C other than it’s the third letter of the alphabet and what I have picked up playing with Arduino in the last 3 years, I think this may be more my speed. Ha! :rofl:

I’ll review your recommendations and get ready to study this winter. Thanks Robert.

image