Komunikasi Modbus PZEM 003 dengan arduino sebagai master (read input register tanpa library)

Modbus adalah sebuah protokol komunikasi antar perangkat. Modbus tergolong sebagai komunikasi serial dengan kelebihan mampu berkomunikasi dalam bus data (lalu lintas data),  jadi dalam sebuah jaringan modbus bisa menghubungkan lebih dari 2 alat (hingga 254 alat/perangkat). Contoh penggunaan protokol modbus adalah programmable logic controllers (PLCs) serta supervisory control and data acquisition (SCADA).

Dalam protokol modbus terdapat fungsi-fungsi diantaranya :

  • Coils (1 bit) baca/tulis
  • Discrete Inputs: (1 bit) hanya baca
  • Input Registers: (2 byte) hanya baca
  • Holding Registers: (2 byte) baca/tulis

Komunikasi antara perangkat dalam jaringan modbus digambarkan dalam diagram berikut :

RS485

rs485 adalah perangkat elektronika pengirim dan penerima data (serial) umumnya menggunakan dua kabel dengan karakteristik sinyal yang seimbang. rs485 juga mampu menghubungkan lebih dari 2 perangkat komunikasi (multipoint).

rs485 sering dimanfaatkan sebagai perangkat tambahan dalam komunikasi modbus.

Pembacaan modul PZEM modbus dengan arduino sebagai master

modul pzem dikenal sebagai modul pembaca tegangan, arus, daya, energi, frekuensi dari listrik. beberapa diantaranya mendukung protokol modbus. dalam contoh ini digunakan modul pzem 003 yaitu modul pengukuran dc.

skema komunikasi modbus berbasis arduino:

komponen yang digunakan :

  1. Arduino uno
  2. modul serial rs485

sketch/program arduino untuk pembacaan sensor pzem :

#define pinModBusTX         4

#include <SoftwareSerial.h>

SoftwareSerial pzem(2, 3); // RX, TX

byte perintah[] = {0x01, 0x04, 0x00, 0x00, 0x00, 0x08};//readInputRegisters
byte bufferDataModbus[100];
byte *ptr;

void setup() {
  pinMode(pinModBusTX, OUTPUT);

  Serial.begin(9600);
  Serial.println(F("Komunikasi Modbus dengan arduino sebagai master (read input register tanpa library)"));
  Serial.println(F("https://www.project.semesin.com"));
  Serial.println();

  pzem.begin(9600);
  ptr = bufferDataModbus;
}

void loop()
{
  uint16_t crc = calcCRC(perintah, sizeof(perintah));

  digitalWrite(pinModBusTX, HIGH);
  delay(1);
  pzem.write(perintah, sizeof(perintah));
  pzem.write(lowByte(crc));
  pzem.write(highByte(crc));
  delay(10);
  digitalWrite(pinModBusTX, LOW);

  long millisResponModbus = millis() + 1000;
  while (!pzem.available())
  {
    if (millisResponModbus < millis())
    {
      break;//timeout
    }
  }

  while (pzem.available())
  {
    byte b = pzem.read();
    *ptr++ = b;
    delay(2);
  }

  if (memcmp(bufferDataModbus, perintah, 2) == 0)
  {
    ptr = bufferDataModbus;

    float tegangan      = ((ptr[0 + 3] << 8) + ptr[1 + 3]) * 0.01;
    float arus          = ((ptr[2 + 3] << 8) + ptr[3 + 3]) * 0.01;
    float daya          = (((uint32_t)ptr[6 + 3] << 24) + ((uint32_t)ptr[7 + 3] << 16) + (ptr[4 + 3] << 8) + ptr[5 + 3]) * 0.1;
    float energi        = (((uint32_t)ptr[10 + 3] << 24) + ((uint32_t)ptr[11 + 3] << 16) + (ptr[8 + 3] << 8) + ptr[9 + 3]);
    uint16_t alarmHigh  = ((ptr[12 + 3] << 8) + ptr[13 + 3]);
    uint16_t alarmLow   = ((ptr[14 + 3] << 8) + ptr[15 + 3]);

    memset(bufferDataModbus, 0x00, sizeof(bufferDataModbus));

    Serial.println("==========");
    Serial.print("tegangan      = ");
    Serial.println(tegangan);
    Serial.print("arus          = ");
    Serial.println(arus);
    Serial.print("daya          = ");
    Serial.println(daya);
    Serial.print("energi        = ");
    Serial.println(energi);
    Serial.print("alarmHigh     = ");
    Serial.println(alarmHigh);
    Serial.print("alarmLow      = ");
    Serial.println(alarmLow);
  }

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

uint16_t calcCRC(byte *data, byte panjang)
{
  int i;
  uint16_t crc = 0xFFFF;
  for (byte p = 0; p < panjang; p++)
  {
    crc ^= data[p];
    for (i = 0; i < 8; ++i)
    {
      if (crc & 1)
        crc = (crc >> 1) ^ 0xA001;
      else
        crc = (crc >> 1);
    }
  }
  return crc;
}