15x ZHT-103 on a single arduino, speed up current calculation


I’m using EmonLib.h to monitor current in a DIY domotics installation. I designed and produced PCB’s that connect directly to an Arduino Mega supporting 15 ZHT-103 (have a look at it there is you’re interested : Arduino MEGA + 15x ZHT-103 - EasyEDA open source hardware lab)

It works quite well but I’m having a ‘speed’ issue.

Actually, I’m currently ‘calculating’ the current of each sensor during the construction of the JSON objet that will be sent to the MQTT server for future use, this takes something like 3 seconds to complete which is too slow (I need it every second max).

There must be some possibilities to group this and calculates values at the same time (using an array?) but I couldn’t get it working so far :frowning:

Any help would be appreciated.

Here’s the code :

  //Build json object
  String jsonPayload = "{\"ZHT_1_0\":\"";
    double Irms = emon0.calcIrms(1480);
    jsonPayload += Irms;
    jsonPayload +="\",\"ZHT_1_1\":\"";
    Irms = emon1.calcIrms(1480);
    jsonPayload += Irms;
    jsonPayload +="\",\"ZHT_1_2\":\"";
    Irms = emon2.calcIrms(1480);
    jsonPayload += Irms;
    jsonPayload +="\",\"ZHT_1_3\":\"";
    Irms = emon3.calcIrms(1480);
    jsonPayload += Irms;
    jsonPayload +="\",\"ZHT_1_4\":\"";
    Irms = emon4.calcIrms(1480);
    jsonPayload += Irms;
    jsonPayload +="\",\"ZHT_1_5\":\"";
    Irms = emon5.calcIrms(1480);
    jsonPayload += Irms;
    jsonPayload +="\",\"ZHT_1_7\":\"";
    Irms = emon7.calcIrms(1480);
    jsonPayload += Irms;
    jsonPayload +="\",\"ZHT_1_8\":\"";
    Irms = emon8.calcIrms(1480);
    jsonPayload += Irms;
    jsonPayload +="\",\"ZHT_1_9\":\"";
    Irms = emon9.calcIrms(1480);
    jsonPayload += Irms;
    jsonPayload +="\",\"ZHT_1_10\":\"";
    Irms = emon10.calcIrms(1480);
    jsonPayload += Irms;
    jsonPayload +="\",\"ZHT_1_11\":\"";
    Irms = emon11.calcIrms(1480);
    jsonPayload += Irms;
    jsonPayload +="\",\"ZHT_1_12\":\"";
    Irms = emon12.calcIrms(1480);
    jsonPayload += Irms;
    jsonPayload +="\",\"ZHT_1_13\":\"";
    Irms = emon13.calcIrms(1480);
    jsonPayload += Irms;
    jsonPayload +="\",\"ZHT_1_14\":\"";
    Irms = emon14.calcIrms(1480);
    jsonPayload += Irms;
    jsonPayload +="\",\"ZHT_1_15\":\"";
    Irms = emon15.calcIrms(1480);
    jsonPayload += Irms;
    jsonPayload +="\"}";

Thanks a lot in advance for your help !

I actually don’t need a precise value. What I need is ‘is there current flowing’ or not.

Do you think I could lower the samples qty ? to what value ?

I’ll have some tests tomorrow as I’m connected remotely tonight …

Thanks in advance for your answers :slight_smile:

I think you need to forget that approach. The problem is emonLib uses the basic, simple “analogRead( )” function, which makes the sketch wait while the ADC measures the voltage. Then you measure one channel for 1480 samples, before you even think about the next one.

You’ll need to create your own sketch based on the inner workings of emonLibCM. In that, the ADC runs freely all the time, and there’s an Interrupt Service Routine, which feeds it with the next channel it needs to read while processing the result from the last channel it read, while the ADC is working on the channel between those two. I suggest you download emonLibCM, search out the ISR and work through understanding how it works with pencil and paper (and an eraser). The ISR then feeds the results (in your case every second) back into the main part of the sketch that formats and sends the payload.

Whether you can do a scan of all 15 channels and still have a fast enough sample rate on each channel, I don’t know (I don’t know the ADC in the Arduino Mega), you’ll have to do the maths to check, but I’d say you need a minimum of about 30 samples per 20 ms mains cycle to have a reasonably accurate measure of current. This implies a sampling time of less than 44µs. I’ve read that it’s the same ADC as the Uno, which is the same as our emonTx, in which case it’s 105 µs, so you can have about 12 samples per cycle - this is not really enough. You will need to use two processors, or sample 7 for about half a second, then the remaining 8 for the rest of the second.

It is a quite complicated project.

Thanks a lot for your return Robert.

So far, I lowered the samples to 318 which speeded up the process enough without compromising the level of accuracy I needed.

So far so good.

For the ATmel ATMega328P, calcIrms( ) will do approx 5588 current samples per second, so if yours is the same ADC, you are reading just under 3 cycles of 50 Hz for each input.