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]("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);
}