Communication between RS485 ,DC communication module and Arduino mega?

// PZEM-017 DC Energy Meter with LCD By Solarduino

// Note Summary
// Note : Safety is very important when dealing with electricity. We take no responsibilities while you do it at your own risk.
// Note : This DC Energy Monitoring Code needs PZEM-017 DC Energy Meter to measure values and Arduio Mega / UNO for communication and display.
// Note : This Code monitors DC Voltage, current, Power, and Energy.
// Note : The values shown in LCD Display is refreshed every second.
// Note : The values are calculated internally by energy meter and function of Arduino is only to read the value and for further calculation.
// Note : The first step is need to select shunt value and change the value accordingly. look for line "static uint16_t NewshuntAddr = 0x0000; "
// Note : You need to download and install (modified) Modbus Master library at our website (PZEM-014 or 016 AC Energy Meter with Arduino – A blog about DIY solar and arduino projects )
// Note : The Core of the code was from EvertDekker.com 2018 which based on the example from PZEM-016 with Arduino PZEM-014 RS485 Modbus - Solar4Living
// Note : Solarduino only amend necessary code and integrate with LCD Display Shield.

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

    /* 1- PZEM-017 DC Energy Meter */
    
    #include <ModbusMaster.h>                   // Load the (modified) library for modbus communication command codes. Kindly install at our website.
    #define MAX485_DE      2                  // Define DE Pin to Arduino pin. Connect DE Pin of Max485 converter module to Pin 2 (default) Arduino board
    #define MAX485_RE      3// Define RE Pin to Arduino pin. Connect RE Pin of Max485 converter module to Pin 3 (default) Arduino board
                                                // These DE anr RE pins can be any other Digital Pins to be activated during transmission and reception process.
    static uint8_t pzemSlaveAddr = 0x01;        // Declare the address of device (meter) in term of 8 bits. You can change to 0x02 etc if you have more than 1 meter.
    static uint16_t NewshuntAddr = 0x0000;      // Declare your external shunt value. Default is 100A, replace to "0x0001" if using 50A shunt, 0x0002 is for 200A, 0x0003 is for 300A
                                                // By default manufacturer may already set, however, to set manually kindly delete the "//" for line "// setShunt(0x01);" in void setup
    ModbusMaster node;                          /* activate modbus master codes*/  
    float PZEMVoltage =0;                       /* Declare value for DC voltage */
    float PZEMCurrent =0;                       /* Declare value for DC current*/
    float PZEMPower =0;                         /* Declare value for DC Power */
    float PZEMEnergy=0;                         /* Declare value for DC Energy */
    unsigned long startMillisPZEM;              /* start counting time for LCD Display */
    unsigned long currentMillisPZEM;            /* current counting time for LCD Display */
    const unsigned long periodPZEM = 1000;      // refresh every X seconds (in seconds) in LED Display. Default 1000 = 1 second 
    int page = 1;                               /* display different pages on LCD Display*/
    

    /* 2 - LCD Display  */

    #include<LiquidCrystal.h>                   /* Load the liquid Crystal Library (by default already built-it with arduino solftware)*/
    LiquidCrystal LCD(48,49,4,5,6,7);             /* Creating the LiquidCrystal object named LCD. The pin may be varies based on LCD module that you use*/
    unsigned long startMillisLCD;               /* start counting time for LCD Display */
    unsigned long currentMillisLCD;             /* current counting time for LCD Display */
    const unsigned long periodLCD = 1000;       /* refresh every X seconds (in seconds) in LED Display. Default 1000 = 1 second */
    int ResetEnergy = 0;                        /* reset energy function */
    unsigned long startMillisEnergy;            /* start counting time for LCD Display */
    unsigned long currentMillisEnergy;          /* current counting time for LCD Display */
    const unsigned long periodEnergy = 1000;    // refresh every X seconds (in seconds) in LED Display. Default 1000 = 1 second 

void setup()
{
/0 General/

    Serial.begin(9600);                         /* to display readings in Serial Monitor at 9600 baud rates */

    /* 1- PZEM-017 DC Energy Meter */
    
     //setShunt(0x01);                          // Delete the "//" to set shunt rating (0x01) is the meter address by default
    // resetEnergy(0x01);                       // By delete the double slash symbol, the Energy value in the meter is reset. Can also be reset on the LCD Display      
    startMillisPZEM = millis();                 /* Start counting time for run code */
    Serial3.begin(9600,SERIAL_8N2);             /* To assign communication port to communicate with meter. with 2 stop bits (refer to manual)*/
                                                // By default communicate via Serial3 port: pin 14 (Tx) and pin 15 (Rx)
    node.begin(pzemSlaveAddr, Serial3);         /* Define and start the Modbus RTU communication. Communication to specific slave address and which Serial port */
    pinMode(MAX485_RE, OUTPUT);                 /* Define RE Pin as Signal Output for RS485 converter. Output pin means Arduino command the pin signal to go high or low so that signal is received by the converter*/
    pinMode(MAX485_DE, OUTPUT);                 /* Define DE Pin as Signal Output for RS485 converter. Output pin means Arduino command the pin signal to go high or low so that signal is received by the converter*/
    digitalWrite(MAX485_RE, 0);                 /* Arduino create output signal for pin RE as LOW (no output)*/
    digitalWrite(MAX485_DE, 0);                 /* Arduino create output signal for pin DE as LOW (no output)*/
                                                // both pins no output means the converter is in communication signal receiving mode
    node.preTransmission(preTransmission);      // Callbacks allow us to configure the RS485 transceiver correctly
    node.postTransmission(postTransmission);
    changeAddress(0xF8,0x01);                  // By delete the double slash symbol, the meter address will be set as 0x01. 
                                                // By default I allow this code to run every program startup. Will not have effect if you only have 1 meter
   // changeAddress(0X01, 0XF8);                   
    delay(1000);                                /* after everything done, wait for 1 second */

    /* 2 - LCD Display  */

    LCD.begin(16,2);                            /* Tell Arduino that our LCD has 16 columns and 2 rows*/
    LCD.setCursor(0,0);                         /* Set LCD to start with upper left corner of display*/  
    startMillisLCD = millis();                  /* Start counting time for display refresh time*/

}

void loop()
{

    /* 0- General */

    /* 0.1- Button Function */
    
    int buttonRead;
    buttonRead = analogRead (0);                                                                      // Read analog pin A0. Pin A0 automatically assigned for LCD Display Button function (cannot be changed)

    /*Right button is pressed */
    if (buttonRead < 60) 
      {   
         LCD.setCursor(0,0); LCD.print (" PRESS <SELECT> "); 
         LCD.setCursor(0,1); LCD.print ("TO RESET ENERGY ");
      }       
 
    /* Up button is pressed */
    else if (buttonRead < 200) 
      {   
         LCD.setCursor(0,0); LCD.print (" PRESS <SELECT> "); 
         LCD.setCursor(0,1); LCD.print ("TO RESET ENERGY ");
      }          
             
    /* Down button is pressed */
    else if (buttonRead < 400)
      {   
         LCD.setCursor(0,0); LCD.print (" PRESS <SELECT> "); 
         LCD.setCursor(0,1); LCD.print ("TO RESET ENERGY ");
      }           
 
    /* Left button is pressed */
    else if (buttonRead < 600)
      {   
        if(ResetEnergy ==0)
        {
          LCD.setCursor(0,0); LCD.print (" PRESS <SELECT> "); 
          LCD.setCursor(0,1); LCD.print ("TO RESET ENERGY ");
        }
        if(ResetEnergy ==1)                                                                           /* only to run reset energy if left button is pressed after select button*/
        {
          page = 2;
        }
      } 
 
    /* Select button is pressed */
    else if (buttonRead < 800)
      {   
          ResetEnergy = 1;                                                                            // to activate offset for power
          startMillisEnergy = millis();                                                               /* start counting time for pending response*/
      }
      
      /* After Select button is pressed */
      if(ResetEnergy ==1)
      {
        LCD.setCursor(0,0);                                                                           /* set display words starting at upper left corner*/
        LCD.print ("RESET ENERGY ?  ");
        LCD.setCursor(0,1);                                                                           /* set display words starting at lower left corner*/
        LCD.print ("PRESS < LEFT >  ");
        currentMillisEnergy = millis();
        if(( currentMillisEnergy - startMillisEnergy <= 5000) && (page==2))                           /* if within 5 seconds <left> button is pressed, do reset energy*/   
          {

            // Reset energy
            
              uint16_t u16CRC = 0xFFFF;                                                                         /* declare CRC check 16 bits*/
              static uint8_t resetCommand = 0x42;                                                               /* reset command code*/
              uint8_t slaveAddr =0X01;
              u16CRC = crc16_update(u16CRC, slaveAddr);
              u16CRC = crc16_update(u16CRC, resetCommand);
              Serial.println("Resetting Energy");
              preTransmission();                                                                                /* trigger transmission mode*/
              Serial3.write(slaveAddr);                                                                         /* send device address in 8 bit*/
              Serial3.write(resetCommand);                                                                      /* send reset command */
              Serial3.write(lowByte(u16CRC));                                                                   /* send CRC check code low byte  (1st part) */
              Serial3.write(highByte(u16CRC));                                                                  /* send CRC check code high byte (2nd part) */
              delay(10);
              postTransmission();                                                                               /* trigger reception mode*/
              delay(100);
              while (Serial3.available())                                                                       /* while receiving signal from Serial3 from meter and converter */ 
                {                                                                      
                  Serial.print(char(Serial3.read()), HEX);                                                      /* Prints the response and display on Serial Monitor (Serial)*/
                  Serial.print(" ");
                }
            ResetEnergy=0;                                                                            /* reset command switch back to default*/
            page=1;                                                                                   /* go back to page 1 after reset*/
          }
          
        if(( currentMillisEnergy - startMillisEnergy > 5000) && (page!=2))                            /* if more than 5 seconds <Left> button does not pressed, go back to main page*/     
          {
            ResetEnergy=0;                                                                            /* reset command switch back to default*/
            page=1;                                                                                   /* go back to page 1 after reset*/
          }
      }


    /* 1- PZEM-017 DC Energy Meter */

    currentMillisPZEM = millis();                                                                     /* count time for program run every second (by default)*/
    if (currentMillisPZEM - startMillisPZEM >= periodPZEM)                                            /* for every x seconds, run the codes below*/
    {    
      uint8_t result;                                                                                 /* Declare variable "result" as 8 bits */   
      result = node.readInputRegisters(0x0000, 6);                                                    /* read the 9 registers (information) of the PZEM-014 / 016 starting 0x0000 (voltage information) kindly refer to manual)*/
      if (result == node.ku8MBSuccess)                                                                /* If there is a response */
        {
          uint32_t tempdouble = 0x00000000;                                                           /* Declare variable "tempdouble" as 32 bits with initial value is 0 */ 
          PZEMVoltage = node.getResponseBuffer(0x0000) / 100.0;                                       /* get the 16bit value for the voltage value, divide it by 100 (as per manual) */
                                                                                                      // 0x0000 to 0x0008 are the register address of the measurement value
          PZEMCurrent = node.getResponseBuffer(0x0001) / 100.0;                                       /* get the 16bit value for the current value, divide it by 100 (as per manual) */
          
          tempdouble =  (node.getResponseBuffer(0x0003) << 16) + node.getResponseBuffer(0x0002);      /* get the power value. Power value is consists of 2 parts (2 digits of 16 bits in front and 2 digits of 16 bits at the back) and combine them to an unsigned 32bit */
          PZEMPower = tempdouble / 10.0;                                                              /* Divide the value by 10 to get actual power value (as per manual) */
          
          tempdouble =  (node.getResponseBuffer(0x0005) << 16) + node.getResponseBuffer(0x0004);      /* get the energy value. Energy value is consists of 2 parts (2 digits of 16 bits in front and 2 digits of 16 bits at the back) and combine them to an unsigned 32bit */
          PZEMEnergy = tempdouble;                                                                    

          Serial.print(PZEMVoltage, 1);                                                               /* Print Voltage value on Serial Monitor with 1 decimal*/
          Serial.print("V   ");
          Serial.print(PZEMCurrent, 3);
          Serial.print("A   ");
          Serial.print(PZEMPower, 1);
          Serial.print("W  ");
          Serial.print(PZEMEnergy, 0);
          Serial.print("Wh  ");
          Serial.println();
          
          if (pzemSlaveAddr==2)                                                                       /* just for checking purpose to see whether can read modbus*/
            {
              Serial.println(); 
            }
        } 
          else
            {
              Serial.println("Failed to read modbus");
            }
          startMillisPZEM = currentMillisPZEM ;                                                       /* Set the starting point again for next counting time */
    }


    /* 2 - LCD Display  */
    
    currentMillisLCD = millis();                                                                      /* Set counting time for LCD Display*/
    if (currentMillisLCD - startMillisLCD >= periodLCD)                                               /* for every x seconds, run the codes below*/  
      {
        if( page ==1)
        {
        LCD.setCursor(0,0);                                                                           /* Set cursor to first colum 0 and second row 1  */
        LCD.print(PZEMVoltage, 1);                                                                    /* Display Voltage on LCD Display with 1 decimal*/
        LCD.print("V    ");
        LCD.setCursor(9,0); 
        LCD.print(PZEMEnergy, 0);  
        LCD.print("Wh   ");
        LCD.setCursor(0,1);
        LCD.print(PZEMCurrent, 2);  
        LCD.print("A    ");
        LCD.setCursor(9,1); 
        LCD.print(PZEMPower, 1);
        LCD.print("W     ");
        startMillisLCD = currentMillisLCD ;                                                           /* Set the starting point again for next counting time */
        }
      }

}

void preTransmission() /* transmission program when triggered*/
{

    /* 1- PZEM-017 DC Energy Meter */
    
    digitalWrite(MAX485_RE, 1);                                                                       /* put RE Pin to high*/
    digitalWrite(MAX485_DE, 1);                                                                       /* put DE Pin to high*/
    delay(1);                                                                                         // When both RE and DE Pin are high, converter is allow to transmit communication

}

void postTransmission() /* Reception program when triggered*/
{

    /* 1- PZEM-017 DC Energy Meter */
    
    delay(3);                                                                                         // When both RE and DE Pin are low, converter is allow to receive communication
    digitalWrite(MAX485_RE, 0);                                                                       /* put RE Pin to low*/
    digitalWrite(MAX485_DE, 0);                                                                       /* put DE Pin to low*/

}

void setShunt(uint8_t slaveAddr) //Change the slave address of a node
{

    /* 1- PZEM-017 DC Energy Meter */
    
    static uint8_t SlaveParameter = 0x06;                                                             /* Write command code to PZEM */
    static uint16_t registerAddress = 0x0003;                                                         /* change shunt register address command code */
    
    uint16_t u16CRC = 0xFFFF;                                                                         /* declare CRC check 16 bits*/
    u16CRC = crc16_update(u16CRC, slaveAddr);                                                         // Calculate the crc16 over the 6bytes to be send
    u16CRC = crc16_update(u16CRC, SlaveParameter);
    u16CRC = crc16_update(u16CRC, highByte(registerAddress));
    u16CRC = crc16_update(u16CRC, lowByte(registerAddress));
    u16CRC = crc16_update(u16CRC, highByte(NewshuntAddr));
    u16CRC = crc16_update(u16CRC, lowByte(NewshuntAddr));
  
    Serial.println("Change shunt address");
    preTransmission();                                                                                 /* trigger transmission mode*/
  
    Serial3.write(slaveAddr);                                                                       /* these whole process code sequence refer to manual*/
    Serial3.write(SlaveParameter);
    Serial3.write(highByte(registerAddress));
    Serial3.write(lowByte(registerAddress));
    Serial3.write(highByte(NewshuntAddr));
    Serial3.write(lowByte(NewshuntAddr));
    Serial3.write(lowByte(u16CRC));
    Serial3.write(highByte(u16CRC));
    delay(10);
    postTransmission();                                                                                /* trigger reception mode*/
    delay(100);
    while (Serial3.available())                                                                        /* while receiving signal from Serial3 from meter and converter */
      {   
        Serial.print(char(Serial3.read()), HEX);                                                       /* Prints the response and display on Serial Monitor (Serial)*/
        Serial.print(" ");
      }

}

void changeAddress(uint8_t OldslaveAddr, uint8_t NewslaveAddr) //Change the slave address of a node
{

    /* 1- PZEM-017 DC Energy Meter */
    
    static uint8_t SlaveParameter = 0x06;                                                             /* Write command code to PZEM */
    static uint16_t registerAddress = 0x0002;                                                         /* Modbus RTU device address command code */
    uint16_t u16CRC = 0xFFFF;                                                                         /* declare CRC check 16 bits*/
    u16CRC = crc16_update(u16CRC, OldslaveAddr);                                                      // Calculate the crc16 over the 6bytes to be send
    u16CRC = crc16_update(u16CRC, SlaveParameter);
    u16CRC = crc16_update(u16CRC, highByte(registerAddress));
    u16CRC = crc16_update(u16CRC, lowByte(registerAddress));
    u16CRC = crc16_update(u16CRC, highByte(NewslaveAddr));
    u16CRC = crc16_update(u16CRC, lowByte(NewslaveAddr));
  
    Serial.println("Change Slave Address");
    preTransmission();                                                                                 /* trigger transmission mode*/
  
    Serial3.write(OldslaveAddr);                                                                       /* these whole process code sequence refer to manual*/
    Serial3.write(SlaveParameter);
    Serial3.write(highByte(registerAddress));
    Serial3.write(lowByte(registerAddress));
    Serial3.write(highByte(NewslaveAddr));
    Serial3.write(lowByte(NewslaveAddr));
    Serial3.write(lowByte(u16CRC));
    Serial3.write(highByte(u16CRC));
    delay(10);
    postTransmission();                                                                                /* trigger reception mode*/
    delay(100);
    while (Serial3.available())                                                                        /* while receiving signal from Serial3 from meter and converter */
      {   
        Serial.print(char(Serial3.read()), HEX);                                                       /* Prints the response and display on Serial Monitor (Serial)*/
        Serial.print(" ");
      }

}

I used above code but that is not work. And I connect between Rs485,DC commucation module and Arduino Mega as below photo.This code is shown "Change slave address and failed to read modulus" in Serial monitor.

Please edit your post, select all code and apply code tags using the </> button; next save your post. It makes it easier to read, easier to copy and makes that the forum software displays it properly.

Did you search the forum for "PZEM"? Several topics to choose from.

thank you bro

no bro

Although I find post in forum, I no see answer

You can capture your entire code with one click, find "capture for forum" or similar in the menus of the IDE. Then paste that into a new code box, preferrably in a new message(because many won't scroll back to the top to see if the initial message has been updated). That way, we can then capture your code correctly and paste it into our IDE, to work with it.
Thanks

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