0% found this document useful (0 votes)
2 views14 pages

Program Arduino Data Logger

The document outlines an Arduino program for a data logger that interfaces with various sensors and components, including a PZEM-017 DC energy meter and an LCD display. It initializes components, reads data such as power, current, voltage, and energy, and logs this information to a MicroSD card. The program also includes functions for handling Modbus communication and managing the LCD display output.

Uploaded by

Ayif Rifyal Afif
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views14 pages

Program Arduino Data Logger

The document outlines an Arduino program for a data logger that interfaces with various sensors and components, including a PZEM-017 DC energy meter and an LCD display. It initializes components, reads data such as power, current, voltage, and energy, and logs this information to a MicroSD card. The program also includes functions for handling Modbus communication and managing the LCD display output.

Uploaded by

Ayif Rifyal Afif
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

Program Arduino Data Logger

Inisiasi Sensor dan Komponen


#if defined(ESP8266)|| defined(ESP32) || defined(AVR)
#include <EEPROM.h>
#endif
#include <SPI.h>
#include <SD.h>
File myFile;

Program Utama
float PZEMPower,PZEMCurrent,PZEMVoltage,PZEMEnergy;
float flowMilliLitres;
unsigned int rpm;
void setup() {
[Link](9600);
[Link]("Data Logger Turbin");
[Link]("Open file on MicroSD card...");
if (![Link](4)) {
[Link]("Failed read open Microsd card!");
return;
}
[Link]("Success read open Microsd card!");

keceptanAirsetup();
Rpmsetup();
EnergySetup();
}

void loop(){
PressureLoop();
kecepatanAirloop(flowMilliLitres);
Rpmloop(rpm);
EnergyLoop(PZEMPower,PZEMCurrent,PZEMVoltage,PZEMEnergy);

myFile = [Link]("Data_Logger.txt", FILE_WRITE);


if (myFile) {
[Link]("\tDaya=");
[Link](PZEMPower, 1);
[Link]("\tArus=");
[Link](PZEMCurrent, 1);
[Link]("\tTegangan=");
[Link](PZEMVoltage, 1);
[Link]("\tEnergy=");
[Link](PZEMEnergy, 0);
[Link]("\tDebit=");
[Link](flowMilliLitres, 1);
[Link]("\tRPM=");
[Link](rpm);
[Link]();
[Link]();
[Link]("done!");
}
else {
[Link]("failed open [Link]");
}
}

Sub Program Watt Meter


/* 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 5 // Define DE Pin to
Arduino pin. Connect DE Pin of Max485 converter module to Pin 2
(default) Arduino board
#define MAX485_RE 6 // Define RE Pin to
Arduino pin. Connect RE Pin of Max485 converter module to Pin 3
(default) Arduino board
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 4);
// 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 = 0x0001; // 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(8,9,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 EnergySetup()
{
/*0 General*/
[Link]();
[Link](9600,SERIAL_8N2); /* To assign
communication port to communicate with meter. with 2 stop bits (refer
to manual)*/

/* 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 */
[Link](pzemSlaveAddr, Serial); /* 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
[Link](preTransmission); // Callbacks allow
us to configure the RS485 transceiver correctly
[Link](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

delay(1000); /* after everything


done, wait for 1 second */

/* 2 - LCD Display */

// [Link](16,2); /* Tell Arduino


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

void EnergyLoop(float PZEMPower,float PZEMCurrent,float


PZEMVoltage,float PZEMEnergy)
{

/* 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)
// {
// [Link](0,0); [Link] (" PRESS <SELECT> ");
// [Link](0,1); [Link] ("TO RESET ENERGY ");
// }

// /* Up button is pressed */
// else if (buttonRead < 200)
// {
// [Link](0,0); [Link] (" PRESS <SELECT> ");
// [Link](0,1); [Link] ("TO RESET ENERGY ");
// }

// /* Down button is pressed */


// else if (buttonRead < 400)
// {
// [Link](0,0); [Link] (" PRESS <SELECT> ");
// [Link](0,1); [Link] ("TO RESET ENERGY ");
// }

// /* Left button is pressed */


// else if (buttonRead < 600)
// {
// if(ResetEnergy ==0)
// {
// [Link](0,0); [Link] (" PRESS <SELECT> ");
// [Link](0,1); [Link] ("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(true)
{
// [Link](0,0);
/* set display words starting at upper left corner*/
// [Link] ("RESET ENERGY ? ");
// [Link](0,1);
/* set display words starting at lower left corner*/
// [Link] ("PRESS < LEFT > ");
currentMillisEnergy = millis();
if(( currentMillisEnergy - startMillisEnergy <= 5000) &&
(page==2)) /* if within 5 seconds <left>
button is pressed, do 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);
preTransmission();
/* trigger transmission mode*/
[Link](slaveAddr);
/* send device address in 8 bit*/
[Link](resetCommand);
/* send reset command */
[Link](lowByte(u16CRC));
/* send CRC check code low byte (1st part) */
[Link](highByte(u16CRC));
/* send CRC check code high byte (2nd part) */
delay(10);
postTransmission();
/* trigger reception mode*/
delay(100);
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 = [Link](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 = [Link](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 = [Link](0x0001) / 100.0;
/* get the 16bit value for the current value, divide it by 100 (as per
manual) */

tempdouble = ([Link](0x0003) << 16) +


[Link](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 = ([Link](0x0005) << 16) +


[Link](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;

if (pzemSlaveAddr==2)
/* just for checking purpose to see whether can read modbus*/
{
}
}
else
{
}
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)
{
// [Link](0,0);
// [Link]("TEST LCD i2C");
[Link](0,0);
/* Set cursor to first colum 0 and second row 1 */
[Link](PZEMVoltage, 1);
/* Display Voltage on LCD Display with 1 decimal*/
[Link]("V ");
[Link](9,0);
[Link](PZEMEnergy, 0);
[Link]("Wh ");
[Link](0,1);
[Link](PZEMCurrent, 2);
[Link]("A ");
[Link](9,1);
[Link](PZEMPower, 1);
[Link]("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));

preTransmission();
/* trigger transmission mode*/

[Link](slaveAddr);
/* these whole process code sequence refer to manual*/
[Link](SlaveParameter);
[Link](highByte(registerAddress));
[Link](lowByte(registerAddress));
[Link](highByte(NewshuntAddr));
[Link](lowByte(NewshuntAddr));
[Link](lowByte(u16CRC));
[Link](highByte(u16CRC));
delay(10);
postTransmission();
/* trigger reception mode*/
delay(100);
while ([Link]())
/* while receiving signal from Serial3 from meter and converter */
{
}
}

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));

preTransmission();
/* trigger transmission mode*/
[Link](OldslaveAddr);
/* these whole process code sequence refer to manual*/
[Link](SlaveParameter);
[Link](highByte(registerAddress));
[Link](lowByte(registerAddress));
[Link](highByte(NewslaveAddr));
[Link](lowByte(NewslaveAddr));
[Link](lowByte(u16CRC));
[Link](highByte(u16CRC));
delay(10);
postTransmission();
/* trigger reception mode*/
delay(100);
while ([Link]())
/* while receiving signal from Serial3 from meter and converter */
{
}
}

Sub Program Sensor Kecepatan air


int dataadc;

byte sensorInterrupt = 3;
byte sensorPin = 1;

float calibrationFactor = 4.5;

volatile byte pulseCount;

unsigned int frac;


float flowRate;
//unsigned int flowMilliLitres;
float totalMilliLitres;

unsigned long oldTimeAir;

void keceptanAirsetup() {
// [Link](9600);

pinMode(sensorInterrupt, INPUT);
digitalWrite(sensorPin, HIGH);

pulseCount = 0;
flowRate = 0.0;
flowMilliLitres = 0;
totalMilliLitres = 0;
oldTimeAir = 0;

attachInterrupt(digitalPinToInterrupt(3), pulseCounter, FALLING);

void kecepatanAirloop(unsigned int flowMilliLitres) {

if((millis() - oldTimeAir) > 1000)


{

detachInterrupt(digitalPinToInterrupt(3));
flowRate = ((1000.0 / (millis() - oldTimeAir)) * pulseCount) /
calibrationFactor;
oldTimeAir = millis();
flowMilliLitres = (flowRate / 60) * 1000;
totalMilliLitres += flowMilliLitres;

pulseCount = 0;
[Link](0,2);
/* Set cursor to first colum 0 and second row 1 */
[Link](flowMilliLitres, 1);
/* Display Voltage on LCD Display with 1 decimal*/
[Link](" ml/s ");

attachInterrupt(digitalPinToInterrupt(3), pulseCounter, FALLING);


}

// delay(200);
}

void pulseCounter()
{
// [Link]("tiup");
pulseCount++;
}

Sub Program Sensor Tekanan


float kpa;
float pressure_pascal1,pressure_pascal2,pressure_pascal3;
float pressure_bar1,pressure_bar2,pressure_bar3;
float v1,v2,v3;
float x1,x2,x3;
void PressureLoop() {
x1 = analogRead(A4);
v1 = x1*(5.0/1023.0);

pressure_pascal1 = (3.0*(v1-0.47))*1000000.0;
pressure_bar1 = pressure_pascal1/10e5;

x2 = analogRead(A5);
v2 = x2*(5.0/1023.0);

pressure_pascal2 = (3.0*(v2-0.47))*1000000.0;
pressure_bar2 = pressure_pascal2/10e5;

x3 = analogRead(A6);
v3 = x3*(5.0/1023.0);

pressure_pascal3 = (3.0*(v3-0.47))*1000000.0;
pressure_bar3 = pressure_pascal3/10e5;

if((millis() - oldTimeAir) > 1000) {

[Link](0,3);
/* Set cursor to first colum 0 and second row 1 */
[Link](pressure_bar1, 1);
/* Display Voltage on LCD Display with 1 decimal*/
[Link](" Pa ");
}
}

Sub Program Sensor RPM (Kecepatan)


volatile byte rpmcount;
//unsigned int rpm;
unsigned long timeold;

void rrpm()
{
rpmcount++;
}

void Rpmsetup() {
// [Link](9600);
pinMode(2,INPUT);
attachInterrupt(digitalPinToInterrupt(2), rrpm, FALLING);

rpmcount = 0;
rpm = 0;
timeold = 0;
}
void Rpmloop(unsigned int rpm) {
// put your main code here, to run repeatedly:
// delay(1000);
detachInterrupt(digitalPinToInterrupt(2));
if((millis() - timeold)>1000){

rpm = 30*1000/(millis() - timeold)*rpmcount;

rpmcount = 0;
// [Link]("Kecepatan = ");
// [Link](rpm);
// [Link](" rpm");
// [Link](" ");

[Link](9,2);
/* Set cursor to first colum 0 and second row 1 */
[Link](rpm);
/* Display Voltage on LCD Display with 1 decimal*/
[Link](" rpm ");

timeold = millis();

}
attachInterrupt(digitalPinToInterrupt(2), rrpm, FALLING);
}

You might also like