Multiple library conflicts for serial comms

Hi all. What am I doing wrong with this array?

My code is huge, so I will post the relevant bits here and hopefully someone can see the error...

First I declare:

#include <PZEM004Tv30.h>    

PZEM004Tv30 pzem(&Serial3, 0xF8);        // This is only used for the initial address programming
PZEM004Tv30 pzem1(&Serial3, 0x01);  
PZEM004Tv30 pzem2(&Serial3, 0x02);            
PZEM004Tv30 pzem3(&Serial3, 0x03);      
PZEM004Tv30 pzem4(&Serial3, 0x04);
PZEM004Tv30 pzem5(&Serial3, 0x05);

Then set up the array etc:

#define NUM_PZEM 5    
PZEM004Tv30 *pzem_array[NUM_PZEM] = { &pzem1, &pzem2, &pzem3, &pzem4, &pzem5 };

float Voltage;                                                                                                    
float Power;
float Frequency;
float Energy;
float Current;
float Pf;

boolean NoACdata = 0;  

You then have to apply 230v power to the 5x modules individually, and re-address them to be 0x01, 0x02, 0x03, 0x04 and 0x05 (They start at default 0xF8).

I then quiz the modules with Serial.println(pzem#.getAddress()); to confirm the address has changed.

I set up a thread to check this data once a second (all working fine):

threads.addThread(ReadPZEM);

Then, when I call my routine to check the data one at a time, I get issues. It locks up trying to read module 5 (00x5). This is an array issue. if I mess around with the array, I can get to read the fifth module, but then they all seem to get out of step.

void ReadPZEM(int index) {                                                                                                                              // Index is the module we are reading

  while (1) {

    NoACdata = 0;

    index++;
    if (index > 5) {
      index = 1;
    }
    
    threads.delay(1000);                                                                                                                                // Sampling time

    Voltage = pzem_array[index-1]->voltage();
    if (!isnan(Voltage)) {
      Serial.print(F("PZEM"));
      Serial.print(index);
      Serial.print(F(" Voltage: "));
      Serial.print(Voltage);
      Serial.println(F("V"));
    } else {
      Serial.print(F("No live supply on input: "));
      Serial.print(index);
      NoACdata = 1;
    }

    Current = pzem_array[index-1]->current();
    if (!isnan(Current)) {
      Serial.print(F("PZEM"));
      Serial.print(index);
      Serial.print(F(" Current: "));
      Serial.print(Current);
      Serial.println(F("A"));
    } else if (NoACdata == 0) {
      Serial.print(F("Error reading PZEM"));
      Serial.print(index);
      Serial.println(F(" current"));
    }

    Power = pzem_array[index-1]->power();
    if (!isnan(Power)) {
      Serial.print(F("PZEM"));
      Serial.print(index);
      Serial.print(F(" Power: "));
      Serial.print(Power);
      Serial.println(F("W"));
    } else if (NoACdata == 0) {
      Serial.print(F("Error reading PZEM"));
      Serial.print(index);
      Serial.println(F(" power"));
    }

    Energy = pzem_array[index-1]->energy();
    if (!isnan(Energy)) {
      Serial.print(F("PZEM"));
      Serial.print(index);
      Serial.print(F(" Energy: "));
      Serial.print(Energy);
      Serial.println(F("kWh"));
    } else if (NoACdata == 0) {
      Serial.print(F("Error reading PZEM"));
      Serial.print(index);
      Serial.println(F(" energy"));
    }

    Frequency = pzem_array[index-1]->frequency();
    if (!isnan(Frequency)) {
      Serial.print(F("PZEM"));
      Serial.print(index);
      Serial.print(F(" Frequency: "));
      Serial.print(Frequency);
      Serial.println(F("Hz"));
    } else if (NoACdata == 0) {
      Serial.print(F("Error reading PZEM"));
      Serial.print(index);
      Serial.println(F(" frequency"));
    }

    Pf = pzem_array[index-1]->pf();
    if (!isnan(Pf)) {
      Serial.print(F("PZEM"));
      Serial.print(index);
      Serial.print(F(" PF: "));
      Serial.println(Pf);
    } else if (NoACdata == 0) {
      Serial.print(F("Error reading PZEM"));
      Serial.print(index);
      Serial.println(F(" power factor"));
    }

    Serial.println(" ");
    threads.yield();
  }
}

What have I messed up where?

I have spent HOURS on this. I think I may just go back to 5x the same routine as that works.
The array index was originally set outside this routine in the main loop, but I have moved it into this subroutine for now.

Yea, I now think its these HORRIBLE Pzem004t mains detection modules.

They report back the incorrect addresses half the time. You set an address, ask it to confirm it and it does.... sometimes when it's not even connected, which is useless.

Back to the drawing board

Not sure if anyone is interested, but I believe the issue is my crappy wiring.

These PZEM (nightmare) modules require a serial connection to program them.
I had the 0v to the module (4 pins, +5v, 0v, TX and RX) switched through a TIP122 because that is what I had to hand. Seemed to work fine.

After some digging, the 5v supply to the module only runs the opto-isolators. You must have 230v AC applied to the module during programming, as that feeds the actual chip.

You program the PZEM module on their broadcast address 0xF8 (or 0x00 - this seems up for debate).
So I was switching them on one at a time and sending the new address to each module on this default address, then powering them off again.

I now believe the modules were still transmitting the data to the PZEM modules, even though I had disconnected its 0v. I think the RX and TX were still able to transmit the data.

This messes up all my addresses.

The other stupid thing is the GET.address function in the PZEM library doesn't actually read the address from the module, it just returns the variable. So it doesn't confirm anything.

So... I need a reliable way to switch 5v to these modules using +3.3v. I imagine this needs to be a Mosfet, but I don't use them that often. Unfortunately, the spec sheet does not tell me the load, but it's only 2x opto-isolators, so it's not going to be much.

My only other option would be assign a software serial port to each of the 5 modules and program them that way, but I don't have enough spare pins.

Suggestions for a suitable Mosfet would be gratefully appreciated.

Hi,

Unfortunately low side switching leads sometime to current from the 5V phantom powering the module by passing current to gnd through the Tx and Rx terminals.

Also the 0V of the module when powered up will not be at gnd but 2V or more above gnd if you read the specs for the TIP122.

So any programing will actually be done with a 3V supply and Tx and Rx offset form GND.

Thanks.. Tom... :grinning: :+1: :coffee: :australia:

Yes. I was fooled by the fact that when you quiz the PZEM modules, they were reporting the address variable I just sent them, not the address they just stored. Found another webpage all about this issue.

My other option is a pair of CD4051's which I have lying around here. Use those multiplexer switches to switch the RX and TX lines. Seems madly complicated way of doing it however.

But, it looks like having the RX's and TX's all on the same bus is going to be problematic.

I am certainly interested. Thanks for taking the time to share your findings.

Right, finally these damn Pzem004t modules are working. Here is what I have found.

The examples from the PZEM004 library work for programming addresses etc, and they use Baud 115200.

BUT... in normal operation, you can only read the live AC mains data at Baud 9600. This is also the Baud rate suggested in the instructions. So beware that the library is not entirely correct.

You must have the AC mains connected to the module to be able to change the address. The AC mains powers the actual IC.

The 5v you supply only feeds the opto-isolators.

If you remove the 0v or the +5v from the opto-isolators, you can still transmit the new address across the opto-isolator using the RX/TX pair. This is what was messing up my sampling routine.

I was switching in each module one at a time (5 of them on a serial bus) using the 5v or the 0v (I tried both).
First of all to reprogram each modules address, and then to read them individually during the loop.

But, removing the 5v or the 0v was not isolating it. So my initial reprogramming was basically setting them all to the last address I sent. The 'get.address' facility is flawed. It reports the address you sent, not the one it stored.

Same happens if you try reprogramming the address with no AC mains connected. You send the address, and then ask for confirmation with 'get.address'. But it reports the address you just sent, even though it didn't store it. So you think you changed it, and you didn't.

So, my solution is to leave them all at factory address 0xF8 (which is the broadcast address) and simply switch the RX and TX pair through a couple of CD4051 multiplexer switches.
I set the address on 3 pins, and then read the data using the same routine set to read default address 0xF8.
Now I can read 8x modules without issue.

Now they are working, they are very good.

1 Like

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