Multiple library conflicts for serial comms

Hello

I have an issue with multiple library conflicts....

I started with a Mega2560p. Any DMX library I install (DMXSerial, DMXSerial2, DMXSimple) conflicts with the serial ports of the Mega. Therefore rendering any other serial comms impossible due to vector conflicts.

This appears to be a well known issue. When I try to use any other means of serial comms, you get the error....

*HardwareSerial0.cpp.o (symbol from plugin): In function `Serial':*

*(.text+0x0): multiple definition of `__vector_25'*

*libraries\DMXSerial\DMXSerial.cpp.o (symbol from plugin):(.text+0x0): first defined here*

*c:/users/steve/appdata/local/arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/../lib/gcc/avr/7.3.0/../../../../avr/bin/ld.exe: Disabling relaxation: it will not work with multiple definitions*

*HardwareSerial0.cpp.o (symbol from plugin): In function `Serial':*

*(.text+0x0): multiple definition of `__vector_26'*

*libraries\DMXSerial\DMXSerial.cpp.o (symbol from plugin):(.text+0x0): first defined here*

*collect2.exe: error: ld returned 1 exit status*

*exit status 1*
*Error compiling for board Arduino Mega or Mega 2560.*

So... in desperation, I moved the whole project over to a Teensy 3.2. I know from experience that the DMX libraries do play together with other serial devices on the Teensy.

I am trying to add one of these voltage/amperage modules:

https://innovatorsguru.com/pzem-004t-v3/

These have examples of software and hardware comms, but they will not play with any Arduino due to this (apparently well known) Vector clash issue.

But now the Teensy will not let play with this module, you get the error....

C:\Users\steve\Documents\Arduino\libraries\PZEM-004T-v30-master\PZEM004Tv30.cpp:54:23: error: conflicting declaration 'HardwareSerial Serial'

 extern HardwareSerial Serial;

                       ^

In file included from C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy3/WProgram.h:54:0,

                 from C:\Users\steve\AppData\Local\Temp\arduino_build_412065/pch/Arduino.h:6,

                 from C:\Users\steve\Documents\Arduino\libraries\PZEM-004T-v30-master\PZEM004Tv30.h:41,

                 from C:\Users\steve\Documents\Arduino\libraries\PZEM-004T-v30-master\PZEM004Tv30.cpp:23:

C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy3/usb_serial.h:124:25: note: previous declaration as 'usb_serial_class Serial'

 extern usb_serial_class Serial;

                         ^

C:\Users\steve\Documents\Arduino\libraries\PZEM-004T-v30-master\PZEM004Tv30.cpp: In destructor 'PZEM004Tv30::~PZEM004Tv30()':

C:\Users\steve\Documents\Arduino\libraries\PZEM-004T-v30-master\PZEM004Tv30.cpp:118:22: warning: deleting object of abstract class type 'Stream' which has non-virtual destructor will cause undefined behaviour [-Wdelete-non-virtual-dtor]

         delete this->_serial;

                      ^

Any ideas how to get past either of these issues?
The first DMX libraries blocking the rest of the serial ports seems to be well known (and not fixed).

The second conflicting declaration error on the Teensy I do really understand

Obviously the library for the power module clashes with the Teensy declarations for the serial ports.

Not sure how I change that. Googling hasn't helped.

Please tell us how you installed these libraries so we can try them out for ourselves and find more information about them.

Right... its a mess, I have been trying all sorts of combinations etc...

//--------Libraries----------------------------------------------------------------------------------------------------------------------------------------

#include <Adafruit_GFX.h>                                                                                                
#include <Adafruit_ST7735.h>                                                                                         
#include <SPI.h>
#include <EEPROM.h>

#include <DMXSerial.h>    // DMX library when using an Arduino Mega

//#include <TeensyDMX.h>      // DMX library when using a Teensy
//namespace teensydmx = ::qindesign::teensydmx;

//#include <SoftwareSerial.h>

//#include <PZEM004Tv30.h>    // Library for the power monitor

//PZEM004Tv30 pzem(&Serial1);      // Define the serial port using HardSerial
//PZEM004Tv30 pzem1(22,23);         // Define the serial port using Softserial

OK. This is the basic declarations that will not mix.
Commented out are the ones that create issues in certain combinations.

The PZEM004Tv30.h requires a single serial comms link.

I need either:
DMXSerial.h + PZEM004Tv30.h
or
TeensyDMX.h + PZEM004Tv30.h

If you use the DMXSerial.h when trying an Arduino (Mega in my case) it will not allow you to also use the PZEM004Tv30.h library. It suffers several vector clashes. The DMXSerial.h does not allow you to use any serial port, not even for debugging.
Never found a solution to that problem.

SO.. I know the TeensyDMX.h library will allow you to use serial ports. I have done that before on another project.
But, when you again declare the PZEM004Tv30.h library you then get a 'conflicting declaration 'HardwareSerial Serial' error.

According to the examples for the PZEM004Tv30.h, you don't need to declare SoftwareSerial, just PZEM004Tv30 pzem1(22,23); (or whatever pins you want).... but it doesn't work anyway.

Maddening. Spend a whole day messing around with this.

You can try changing this line to match the usb_serial_class type used for the Serial object by the Teensy core library:

Thanks Pert, although not entirely sure I understand what I am changing where....

Am I editing the Teensy files or the PZEM files?

Eyes are getting old and tired

  1. Open this file in a text editor:
    C:\Users\steve\Documents\Arduino\libraries\PZEM-004T-v30-master\PZEM004Tv30.cpp
    
  2. Change line 54 from:
    extern HardwareSerial Serial;
    
    to:
    extern usb_serial_class Serial;
    
  3. Save the file

Now try compiling the sketch again.

OK Pert. Changing that in the PZEM004Tv30.cpp file allows it to compile.

It still will not let me declare the software serial port as the example shows:

PZEM004Tv30 pzem(22,23);

Troubleshooting_libraries:18: error: invalid conversion from 'int' to 'HardwareSerial*' [-fpermissive]
 PZEM004Tv30 pzem(22,23);         // Define the serial port using Softserial

                       ^

In file included from C:\Users\steve\Documents\Arduino\10 Way controller\Troubleshooting_libraries\Troubleshooting_libraries.ino:15:0:

C:\Users\steve\Documents\Arduino\libraries\PZEM-004T-v30-master/PZEM004Tv30.h:65:5: note:   initializing argument 1 of 'PZEM004Tv30::PZEM004Tv30(HardwareSerial*, uint8_t)'

     PZEM004Tv30(HardwareSerial* port, uint8_t addr=PZEM_DEFAULT_ADDR);

But, I can successfully declare a hard serial port:

PZEM004Tv30 pzem(&Serial1);.

I can apparently change the address of these voltage monitors using pzem.setAddress(addr);
There was going to be more than one on software serial addresses, but I can daisy chain them on the same serial port.

But I am not sure how I then talk to each address to retrieve the information?

The is the example code for reading a single module using hardware serial:

#include <PZEM004Tv30.h>

/* Hardware Serial3 is only available on certain boards.
 * For example the Arduino MEGA 2560
*/
PZEM004Tv30 pzem(&Serial3);

void setup() {
  Serial.begin(115200);
}

void loop() {
    float voltage = pzem.voltage();
    if(!isnan(voltage)){
        Serial.print("Voltage: "); Serial.print(voltage); Serial.println("V");
    } else {
        Serial.println("Error reading voltage");
    }

    float current = pzem.current();
    if(!isnan(current)){
        Serial.print("Current: "); Serial.print(current); Serial.println("A");
    } else {
        Serial.println("Error reading current");
    }

    float power = pzem.power();
    if(!isnan(power)){
        Serial.print("Power: "); Serial.print(power); Serial.println("W");
    } else {
        Serial.println("Error reading power");
    }

    float energy = pzem.energy();
    if(!isnan(energy)){
        Serial.print("Energy: "); Serial.print(energy,3); Serial.println("kWh");
    } else {
        Serial.println("Error reading energy");
    }

    float frequency = pzem.frequency();
    if(!isnan(frequency)){
        Serial.print("Frequency: "); Serial.print(frequency, 1); Serial.println("Hz");
    } else {
        Serial.println("Error reading frequency");
    }

    float pf = pzem.pf();
    if(!isnan(pf)){
        Serial.print("PF: "); Serial.println(pf);
    } else {
        Serial.println("Error reading power factor");
    }

    Serial.println();
    delay(2000);
}

How would I alter this to talk to the modules different addresses?

OK... Got it to read multiple versions of the module on the same bus.
Many thanks Pert

I'm glad to hear it! Thanks for taking the time to post an update.
Enjoy!
Per

Well for anyone interested, the default address of each module is 0x00.

I declared 5x of the modules on Serial 3 at the start. plus the factory address.

PZEM004Tv30 pzem0(&Serial3, 0x00);
PZEM004Tv30 pzem1(&Serial3, 0x01);
PZEM004Tv30 pzem2(&Serial3, 0x02);
PZEM004Tv30 pzem3(&Serial3, 0x03);
PZEM004Tv30 pzem4(&Serial3, 0x04);
PZEM004Tv30 pzem5(&Serial3, 0x05);

They arrive factory set at 0x00. So you have to individually power each one on (I have a digital pin allocated to power each module) and write it a new address:

pzem0.setAddress(0x##);

Power it off and address the next one.

I do this once on the first ever boot, and set an EEprom flag so it never does it again.

After this point, you can directly communicate with each module. For example:

float voltage1 = pzem1.voltage();
if(!isnan(voltage1)){
    Serial.print("Voltage: "); Serial.print(voltage1); Serial.println("V");
} else {
    Serial.println("Error reading voltage");
}
1 Like

Just a quick question...

How can I adjust the request for voltage (for example), so that I do not have to re-write all the requests multiple times for different modules.

By this I mean.... the line for retrieving voltage is:

Voltage = pzem1.voltage();

But I don't want to have:

Voltage = pzem1.voltage();
Voltage = pzem2.voltage();
Voltage = pzem3.voltage();
Voltage = pzem4.voltage();
Voltage = pzem5.voltage();

With all the other parameters, that is 25 lines, plus some failed data logic on each request.

How do I write this so that the module number can be replaced with a byte?

Voltage = pzem#.voltage(); ?

Is it even possible?

Use an array of PZEM004Tv30 objects. Then the "#" you want is the index of the array.

Ha OK. Pert. I will now Google what that means! Thanks
I assume you mean list the commands, then recall them as needed.

This is an object of the PZEM004Tv30 type:

If you had an array of them, we'll call it pzem for this example, then you can do things like this:

Voltage=pzem[3].voltage();

you can also use for loops to iterate over the array. For example:

// Print the voltage for each module
for (index=0; index < sizeof(pzem)/sizeof(pzem[0]); index++) {
  Serial.println(pzem[index].voltage());
}

Thank you Pert. You are a legend

1 Like

Just got back to this project tonight. Without coming across as entirely thick, I still can't get this array stuff to work.

If I declare: byte pzem[5];

Then:
Voltage = pzem[1].voltage();

I get the error:

C:\Users\steve\Documents\Arduino\10 Way controller\10_way_controller_v10_-_Teensy_3.2\10_way_controller_v10_-_Teensy_3.2.ino:795:21: error: request for member 'voltage' in 'pzem[1]', which is of non-class type 'int'

   Voltage = pzem[1].voltage();

That's creating an array of the byte data type. You need to create an array of objects of the PZEM004Tv30 type:

PZEM004Tv30 pzem[5];

At this point, the array is uninitialized. You need to populate it with PZEM004Tv30 objects.

Thanks Pert. I have Googled this and clearly not quite understanding objects and arrays.

I will have a tinker around, but for now I will have to leave it working the old 'long' way (at least it works!)