How to Better Display my Results on Serial Monitor for Data Collection

Hi all,

Beginner coder here. I'm working on a project to collect data off a 12V DC battery. I need to collect Voltage, Amps, and the code will calculate Power, Watt-Hours, etc. Everything is working correctly on the hardware side and with the code as well, I just need to know how I can best display my results on serial monitor for data collection. I was copying and pasting my data into Excel, and some lines of the serial monitor switched the positions of volts and amps, and with 3000+ data points I can't manually swap all of the faulty data points.

I need my serial monitor to be impeccable when displaying my results. I've attached a copy of my serial monitor and code below.

Thanks in advance, I'm sure this is simple but I am a new programmer. Would appreciate any advice!

/* 0- General */

        int decimalPrecision = 2;                   // decimal places for all values shown in LED Display & Serial Monitor
    
/* 1- DC Voltage Measurement using Voltage Divider Method */

        int VoltageAnalogInputPin = A1;             // Which pin to measure Voltage Value (A0 is reserved for LCD Shield buttons function)
        float voltageSampleRead  = 0;               /* to read the value of a sample*/
        float voltageLastSample  = 0;               /* to count time for each sample. Technically 1 milli second 1 sample is taken */
        float voltageSampleSum   = 0;               /* accumulation of sample readings */
        float voltageSampleCount = 0;               /* to count number of sample. */
        float voltageMean ;                         /* to calculate the average value from all samples*/ 
        float moduleSupplyVoltageV = 5;             /* maximum measuring voltage , default 5V*/
        float R1 = 47000; //30000.0;                         // Input resistance value for R1 (in ohm) based on Voltage Divider Method 
        float R2 = 2200; //7500.0;                          // Input resistance value for R2 (in ohm) based on Voltage Divider Method 
        float finalVoltage =0;                      /*shows the final voltage reading*/
    

/* 2- DC Current Measurement */
   
        int CurrentAnalogInputPin = A2;             // Which pin to measure Current Value (A0 is reserved for LCD Shield buttons function)
        float mVperAmpValue = 100;                  // If using ACS712 current module : for 5A module key in 185, for 20A module key in 100, for 30A module key in 66
                                                    // If using "Hall-Effect" Current Transformer, key in value using this formula: mVperAmp = maximum voltage range (in milli volt) / current rating of CT
                                                    /* For example, a 20A Hall-Effect Current Transformer rated at 20A, 2.5V +/- 0.625V, mVperAmp will be 625 mV / 20A = 31.25mV/A */
        
        float moduleMiddleVoltage = 2500;           /* when there is no reading, the voltage is at middle Vcc. For 5V power supply, the middle voltage is 2500mV;*/
        float moduleSupplyVoltage = 5000;           /* supply voltage to current sensor module, default 5000mV*/
        float currentSampleRead  = 0;               /* to read the value of a sample*/
        float currentLastSample  = 0;               /* to count time for each sample. Technically 1 milli second 1 sample is taken */
        float currentSampleSum   = 0;               /* accumulation of sample readings */
        float currentSampleCount = 0;               /* to count number of sample. */
        float currentMean ;                         /* to calculate the average value from all samples*/ 
        float finalCurrent ;                        /* the final current reading without adding offset value*/
        float finalCurrent2 ;                       /* the final current reading*/


        /* 2.1- DC Current Offset */
        
              int OffsetRead = 0;                   /* To switch between functions for auto callibation purpose */   
              float currentOffset =-.29 ;           // to Offset deviation and accuracy. Offset any fake current when no current operates. 
                                                    // Look into serial monitor to add or minus the value.
                                                    // 0.26 means add 0.26A to all current measured value.
                                                    /* if you have LCD Display Shield, this offset can be automatically adjusted by pressing SELECT button */
              float offsetLastSample = 0;           /* to count time for each sample. Technically 1 milli second 1 sample is taken */
              float offsetSampleCount = 0;          /* to count number of sample. */

/* 3- DC Power Wattage calculation */

    float PowerValue =0;                          /* Initial calculation Power Value */
    unsigned long startMillisPower;               /* start counting time for power */
    unsigned long currentMillisPower;             /* current counting time for power */
    const unsigned long periodPower = 1000;       // refresh every X seconds (in seconds) Default 1 = 1 second 

/* 4- DC Watt-hour calculation */

    float wattHour  = 0;                           /* Initial calculation Energy Value */
    unsigned long startMillisEnergy;               /* start counting time for Energy */
    unsigned long currentMillisEnergy;             /* current counting time for Energy */
    const unsigned long periodEnergy = 1000;       // refresh every X seconds (in seconds) Default 1000 = 1 second 
    float FinalEnergyValue = 0;                    /*shows the final Energy reading*/

/* 5 - 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 */
   // 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 



void setup()                                  /* The Codes only run 1 time only when Arduino started.*/
 
  {

/* 0- General */

    Serial.begin(9600);                       /* In order to see value in serial monitor */
    
/* 3- DC Power Wattage calculation */

   startMillisPower = millis(); 

/* 4- DC Watt-hour calculation */

   startMillisEnergy = millis();  

/* 5 - LCD Display  */

//    LCD.begin(16,2);                                  /*Tell Arduino that our LCD has 16 columns and 2 rows*/
  //  LCD.setCursor(0,0);                               /*Set LCD to upper left corner of display*/  
    //startMillisLCD = millis();
    
  }

  
void loop()                                 /* The Codes run repeatly over and over again.*/

  {

        /* 0- General */


              /* 0.1- Button Function */
        
            //  int buttonRead;
             // buttonRead = analogRead (0);                                          // Read analog pin A0. Analog pin A0 automatically reserved for button function in LCD Display Shield

              /*Right button is pressed */
              //if (buttonRead < 60) 
            //  {   LCD.setCursor(0,0); LCD.print ("PRESS <SELECT>   "); }       
     
              /* Up button is pressed */
              //else if (buttonRead < 200) 
              //{   LCD.setCursor(0,0); LCD.print ("PRESS <SELECT>   "); }    
                 
              /* Down button is pressed */
              //else if (buttonRead < 400)
              //{   LCD.setCursor(0,0); LCD.print ("PRESS <SELECT>  ");  }      
     
              /* Left button is pressed */
              //else if (buttonRead < 600)
              //{   LCD.setCursor(0,0); LCD.print ("PRESS <SELECT>   "); } 
     
              /* Select button is pressed */
              //else if (buttonRead < 800)
              //{   
              //OffsetRead = 1;                                                 // to activate offset 
             // LCD.setCursor(0,0);
              //LCD.print ("INITIALIZING..... ");
              //LCD.setCursor(0,1);
              //LCD.print ("WAIT 5 SEC ..... ");
              //}

    
/* 1- DC Voltage Measurement using Voltage Divider Method */

        if(millis() >= voltageLastSample + 1 )                                                                /* every 1 milli second taking 1 reading */
          {
            voltageSampleRead = analogRead(VoltageAnalogInputPin);                                            /* read the sample value */
            voltageSampleSum = voltageSampleSum + voltageSampleRead ;                                         /* accumulate value with older sample readings*/
            voltageSampleCount = voltageSampleCount + 1;                                                      /* to move on to the next following count */
            voltageLastSample = millis();                                                                     /* to reset the time again so that next cycle can start again*/ 
          }
    
        if(voltageSampleCount == 1000)                                                                        /* after 1000 count or 1000 milli seconds (1 second), do the codes below*/
          {
            voltageMean = voltageSampleSum/voltageSampleCount;                                                /* calculate average value of all sample readings taken*/
            finalVoltage = .25+((voltageMean*moduleSupplyVoltageV)/1024) / (R2/(R1+R2));                          /*  Calculate the expected monitoring votlage */
            Serial.print("V : ");
            Serial.print( finalVoltage,decimalPrecision);
            Serial.print(" V ");
           // Serial.println();
            // Serial.print('\t');
           // Serial.print(" /  ");
            voltageSampleSum =0;                                                                              /* to reset accumulate sample values for the next cycle */
            voltageSampleCount=0;                                                                             /* to reset number of sample for the next cycle */
          }

      
/* 2- DC Current Measurement */

        if(millis() >= currentLastSample + 1 )                                                                /* every 1 milli second taking 1 reading */
          {
            currentSampleRead = analogRead(CurrentAnalogInputPin)-((moduleMiddleVoltage/moduleSupplyVoltage)*1024);      /* read the sample value */
            currentSampleSum =  (currentSampleSum + currentSampleRead) ;                                         /* accumulate value with older sample readings*/
            currentSampleCount = currentSampleCount + 1;                                                      /* to move on to the next following count */
            currentLastSample = millis();                                                                     /* to reset the time again so that next cycle can start again*/ 
          }
    
        if(currentSampleCount == 1000)                                                                        /* after 1000 count or 1000 milli seconds (1 second), do the calculation and display value*/
          {
            currentMean = currentSampleSum/currentSampleCount;                                                /* calculate average value of all sample readings taken*/
            finalCurrent = (((currentMean /1024) *5000) /mVperAmpValue);                                      /* calculate the final RMS current*/
            finalCurrent2 = -(finalCurrent + currentOffset);
        //     Serial.print('\t');
          //    Serial.print('\t');
            
           Serial.print("I : ");
            Serial.print(finalCurrent2,decimalPrecision);
            Serial.print(" A ");
             //Serial.print('\t');
            //Serial.println();
            //Serial.print(" /  ");
            currentSampleSum =0;                                                                              /* to reset accumulate sample values for the next cycle */
            currentSampleCount=0;                                                                             /* to reset number of sample for the next cycle */
          }
          

          /* 2.1 - Offset DC Current */
          
          if(OffsetRead == 1)  
            {
             currentOffset = 0;                                                              /* set back currentOffset as default*/
               if(millis() >= offsetLastSample + 1)                                          /* offset 1 - to centralise analogRead waveform*/
                {                                                                            
                  offsetSampleCount = offsetSampleCount + 1;                                                                          
                  offsetLastSample = millis();                                                                          
                }                                                                             
                  
                  if(offsetSampleCount == 2500)                                              /* need to wait first offset take into effect. Delay 2.5 seconds  */
                {                                                                            /* So this code is to delay 2.5 seconds after button pressed */
                  currentOffset = - finalCurrent;                                            /* to offset values */
                  OffsetRead = 0;                                                            /* until next offset button is pressed*/                      
                  offsetSampleCount = 0;                                                     /* to reset the time again so that next cycle can start again */ 
                }                                                                             
            } 

   
/* 3- DC Power Wattage calculation */

        currentMillisPower = millis();                                                                            /* Count the time for power */
        if (currentMillisPower - startMillisPower >= periodPower)
          {
            PowerValue = finalCurrent2 * finalVoltage;
            // Serial.print('\t');
            Serial.print("P : " );
            Serial.print(PowerValue,decimalPrecision); 
            Serial.print(" W "); 
            Serial.println();
          Serial.print(" /  ");
            startMillisPower = currentMillisPower ;                                                               /* Set the starting point again for next counting time */
          }

/* 4- DC Watt-hour calculation */

       currentMillisEnergy = millis();                                                                            /* Count the time for current */
       if (currentMillisEnergy - startMillisEnergy >= periodEnergy)
          {
            wattHour = PowerValue/3600*(periodEnergy/1000);                                                       /* for smoothing calculation*/
            FinalEnergyValue = FinalEnergyValue + wattHour;
           // Serial.print("E : " );
            //Serial.print(FinalEnergyValue,decimalPrecision); 
            //Serial.print(" Wh "); 
            //Serial.println(" /  ");
            startMillisEnergy = currentMillisEnergy ;                                                             /* Set the starting point again for next counting time */
          }

/* 5 - LCD Display  */

      //currentMillisLCD = millis();
      //if (currentMillisLCD - startMillisLCD >= periodLCD)
         // {
           // LCD.setCursor(0,0);                                                                                   /* Set cursor to first colum 0 and second row 1  */
            //LCD.print(finalVoltage,decimalPrecision);                                                             /* display voltage value in LCD in first row  */
            //LCD.print("V   ");
            //LCD.setCursor(8,0);   
            //LCD.print(PowerValue,decimalPrecision-1);                                                             /* display power value in LCD  */
            //LCD.print("W    ");
            //LCD.setCursor(0,1);                                                                                   /* set display starts at second row  */
            //LCD.print(finalCurrent2,decimalPrecision);                                                             /* display current value in LCD in first row */
            //LCD.print("A  ");  
            //LCD.setCursor(8,1);
            //LCD.print(FinalEnergyValue/1000,decimalPrecision-1);                                                  /* display energy value in LCD  */
            //LCD.print("kWh   ");
            //startMillisLCD = currentMillisLCD ;                                                                   /* Set the starting point again for next counting time */
          //}

 
  }

And now with formatting applied and cpp tag :

```cpp
[your code here]
```
/* 0- General */

int decimalPrecision = 2;  // decimal places for all values shown in LED Display & Serial Monitor

/* 1- DC Voltage Measurement using Voltage Divider Method */

int VoltageAnalogInputPin = A1;  // Which pin to measure Voltage Value (A0 is reserved for LCD Shield buttons function)
float voltageSampleRead = 0;     /* to read the value of a sample*/
float voltageLastSample = 0;     /* to count time for each sample. Technically 1 milli second 1 sample is taken */
float voltageSampleSum = 0;      /* accumulation of sample readings */
float voltageSampleCount = 0;    /* to count number of sample. */
float voltageMean;               /* to calculate the average value from all samples*/
float moduleSupplyVoltageV = 5;  /* maximum measuring voltage , default 5V*/
float R1 = 47000;                //30000.0;                         // Input resistance value for R1 (in ohm) based on Voltage Divider Method
float R2 = 2200;                 //7500.0;                          // Input resistance value for R2 (in ohm) based on Voltage Divider Method
float finalVoltage = 0;          /*shows the final voltage reading*/


/* 2- DC Current Measurement */

int CurrentAnalogInputPin = A2;  // Which pin to measure Current Value (A0 is reserved for LCD Shield buttons function)
float mVperAmpValue = 100;       // If using ACS712 current module : for 5A module key in 185, for 20A module key in 100, for 30A module key in 66
                                 // If using "Hall-Effect" Current Transformer, key in value using this formula: mVperAmp = maximum voltage range (in milli volt) / current rating of CT
                                 /* For example, a 20A Hall-Effect Current Transformer rated at 20A, 2.5V +/- 0.625V, mVperAmp will be 625 mV / 20A = 31.25mV/A */

float moduleMiddleVoltage = 2500; /* when there is no reading, the voltage is at middle Vcc. For 5V power supply, the middle voltage is 2500mV;*/
float moduleSupplyVoltage = 5000; /* supply voltage to current sensor module, default 5000mV*/
float currentSampleRead = 0;      /* to read the value of a sample*/
float currentLastSample = 0;      /* to count time for each sample. Technically 1 milli second 1 sample is taken */
float currentSampleSum = 0;       /* accumulation of sample readings */
float currentSampleCount = 0;     /* to count number of sample. */
float currentMean;                /* to calculate the average value from all samples*/
float finalCurrent;               /* the final current reading without adding offset value*/
float finalCurrent2;              /* the final current reading*/


/* 2.1- DC Current Offset */

int OffsetRead = 0;          /* To switch between functions for auto callibation purpose */
float currentOffset = -.29;  // to Offset deviation and accuracy. Offset any fake current when no current operates.
                             // Look into serial monitor to add or minus the value.
                             // 0.26 means add 0.26A to all current measured value.
                             /* if you have LCD Display Shield, this offset can be automatically adjusted by pressing SELECT button */
float offsetLastSample = 0;  /* to count time for each sample. Technically 1 milli second 1 sample is taken */
float offsetSampleCount = 0; /* to count number of sample. */

/* 3- DC Power Wattage calculation */

float PowerValue = 0;                    /* Initial calculation Power Value */
unsigned long startMillisPower;          /* start counting time for power */
unsigned long currentMillisPower;        /* current counting time for power */
const unsigned long periodPower = 1000;  // refresh every X seconds (in seconds) Default 1 = 1 second

/* 4- DC Watt-hour calculation */

float wattHour = 0;                       /* Initial calculation Energy Value */
unsigned long startMillisEnergy;          /* start counting time for Energy */
unsigned long currentMillisEnergy;        /* current counting time for Energy */
const unsigned long periodEnergy = 1000;  // refresh every X seconds (in seconds) Default 1000 = 1 second
float FinalEnergyValue = 0;               /*shows the final Energy reading*/

/* 5 - 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 */
// 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



void setup() /* The Codes only run 1 time only when Arduino started.*/
{

  /* 0- General */

  Serial.begin(9600); /* In order to see value in serial monitor */

  /* 3- DC Power Wattage calculation */

  startMillisPower = millis();

  /* 4- DC Watt-hour calculation */

  startMillisEnergy = millis();

  /* 5 - LCD Display  */

  //    LCD.begin(16,2);                                  /*Tell Arduino that our LCD has 16 columns and 2 rows*/
  //  LCD.setCursor(0,0);                               /*Set LCD to upper left corner of display*/
  //startMillisLCD = millis();
}


void loop() /* The Codes run repeatly over and over again.*/
{

  /* 0- General */


  /* 0.1- Button Function */

  //  int buttonRead;
  // buttonRead = analogRead (0);                                          // Read analog pin A0. Analog pin A0 automatically reserved for button function in LCD Display Shield

  /*Right button is pressed */
  //if (buttonRead < 60)
  //  {   LCD.setCursor(0,0); LCD.print ("PRESS <SELECT>   "); }

  /* Up button is pressed */
  //else if (buttonRead < 200)
  //{   LCD.setCursor(0,0); LCD.print ("PRESS <SELECT>   "); }

  /* Down button is pressed */
  //else if (buttonRead < 400)
  //{   LCD.setCursor(0,0); LCD.print ("PRESS <SELECT>  ");  }

  /* Left button is pressed */
  //else if (buttonRead < 600)
  //{   LCD.setCursor(0,0); LCD.print ("PRESS <SELECT>   "); }

  /* Select button is pressed */
  //else if (buttonRead < 800)
  //{
  //OffsetRead = 1;                                                 // to activate offset
  // LCD.setCursor(0,0);
  //LCD.print ("INITIALIZING..... ");
  //LCD.setCursor(0,1);
  //LCD.print ("WAIT 5 SEC ..... ");
  //}


  /* 1- DC Voltage Measurement using Voltage Divider Method */

  if (millis() >= voltageLastSample + 1) /* every 1 milli second taking 1 reading */
  {
    voltageSampleRead = analogRead(VoltageAnalogInputPin);   /* read the sample value */
    voltageSampleSum = voltageSampleSum + voltageSampleRead; /* accumulate value with older sample readings*/
    voltageSampleCount = voltageSampleCount + 1;             /* to move on to the next following count */
    voltageLastSample = millis();                            /* to reset the time again so that next cycle can start again*/
  }

  if (voltageSampleCount == 1000) /* after 1000 count or 1000 milli seconds (1 second), do the codes below*/
  {
    voltageMean = voltageSampleSum / voltageSampleCount;                                   /* calculate average value of all sample readings taken*/
    finalVoltage = .25 + ((voltageMean * moduleSupplyVoltageV) / 1024) / (R2 / (R1 + R2)); /*  Calculate the expected monitoring votlage */
    Serial.print("V : ");
    Serial.print(finalVoltage, decimalPrecision);
    Serial.print(" V ");
    // Serial.println();
    // Serial.print('\t');
    // Serial.print(" /  ");
    voltageSampleSum = 0;   /* to reset accumulate sample values for the next cycle */
    voltageSampleCount = 0; /* to reset number of sample for the next cycle */
  }


  /* 2- DC Current Measurement */

  if (millis() >= currentLastSample + 1) /* every 1 milli second taking 1 reading */
  {
    currentSampleRead = analogRead(CurrentAnalogInputPin) - ((moduleMiddleVoltage / moduleSupplyVoltage) * 1024); /* read the sample value */
    currentSampleSum = (currentSampleSum + currentSampleRead);                                                    /* accumulate value with older sample readings*/
    currentSampleCount = currentSampleCount + 1;                                                                  /* to move on to the next following count */
    currentLastSample = millis();                                                                                 /* to reset the time again so that next cycle can start again*/
  }

  if (currentSampleCount == 1000) /* after 1000 count or 1000 milli seconds (1 second), do the calculation and display value*/
  {
    currentMean = currentSampleSum / currentSampleCount;            /* calculate average value of all sample readings taken*/
    finalCurrent = (((currentMean / 1024) * 5000) / mVperAmpValue); /* calculate the final RMS current*/
    finalCurrent2 = -(finalCurrent + currentOffset);
    //     Serial.print('\t');
    //    Serial.print('\t');

    Serial.print("I : ");
    Serial.print(finalCurrent2, decimalPrecision);
    Serial.print(" A ");
    //Serial.print('\t');
    //Serial.println();
    //Serial.print(" /  ");
    currentSampleSum = 0;   /* to reset accumulate sample values for the next cycle */
    currentSampleCount = 0; /* to reset number of sample for the next cycle */
  }


  /* 2.1 - Offset DC Current */

  if (OffsetRead == 1) {
    currentOffset = 0;                    /* set back currentOffset as default*/
    if (millis() >= offsetLastSample + 1) /* offset 1 - to centralise analogRead waveform*/
    {
      offsetSampleCount = offsetSampleCount + 1;
      offsetLastSample = millis();
    }

    if (offsetSampleCount == 2500)   /* need to wait first offset take into effect. Delay 2.5 seconds  */
    {                                /* So this code is to delay 2.5 seconds after button pressed */
      currentOffset = -finalCurrent; /* to offset values */
      OffsetRead = 0;                /* until next offset button is pressed*/
      offsetSampleCount = 0;         /* to reset the time again so that next cycle can start again */
    }
  }


  /* 3- DC Power Wattage calculation */

  currentMillisPower = millis(); /* Count the time for power */
  if (currentMillisPower - startMillisPower >= periodPower) {
    PowerValue = finalCurrent2 * finalVoltage;
    // Serial.print('\t');
    Serial.print("P : ");
    Serial.print(PowerValue, decimalPrecision);
    Serial.print(" W ");
    Serial.println();
    Serial.print(" /  ");
    startMillisPower = currentMillisPower; /* Set the starting point again for next counting time */
  }

  /* 4- DC Watt-hour calculation */

  currentMillisEnergy = millis(); /* Count the time for current */
  if (currentMillisEnergy - startMillisEnergy >= periodEnergy) {
    wattHour = PowerValue / 3600 * (periodEnergy / 1000); /* for smoothing calculation*/
    FinalEnergyValue = FinalEnergyValue + wattHour;
    // Serial.print("E : " );
    //Serial.print(FinalEnergyValue,decimalPrecision);
    //Serial.print(" Wh ");
    //Serial.println(" /  ");
    startMillisEnergy = currentMillisEnergy; /* Set the starting point again for next counting time */
  }

  /* 5 - LCD Display  */

  //currentMillisLCD = millis();
  //if (currentMillisLCD - startMillisLCD >= periodLCD)
  // {
  // LCD.setCursor(0,0);                                                                                   /* Set cursor to first colum 0 and second row 1  */
  //LCD.print(finalVoltage,decimalPrecision);                                                             /* display voltage value in LCD in first row  */
  //LCD.print("V   ");
  //LCD.setCursor(8,0);
  //LCD.print(PowerValue,decimalPrecision-1);                                                             /* display power value in LCD  */
  //LCD.print("W    ");
  //LCD.setCursor(0,1);                                                                                   /* set display starts at second row  */
  //LCD.print(finalCurrent2,decimalPrecision);                                                             /* display current value in LCD in first row */
  //LCD.print("A  ");
  //LCD.setCursor(8,1);
  //LCD.print(FinalEnergyValue/1000,decimalPrecision-1);                                                  /* display energy value in LCD  */
  //LCD.print("kWh   ");
  //startMillisLCD = currentMillisLCD ;                                                                   /* Set the starting point again for next counting time */
  //}
}

Plenty of colors and nuances for ease of reading ! Especially when lots of comments and commented out code...

2 Likes

When you convert to and operate with floating point, a bit of unavoidable error can creep in. Integers can lose data to rounding but with large integers we can cleanly add places to integers to lose in scaling, keep 3 places by working to 6 or more through tiny working units. Millimeter integer is just meters to 3 places. If you need 3 places to lose to round-downs then work to micrometers, the next three places go nano. 32 bit unsigned longs deliver 9 places 0 to 9 and 64 bit ULL have 19 places.

Work with integer reads and only display or generate the human-read output at point of need. At least you don't show more places than the hardware is good for!

You have too many millis timers.

Your periodEnergy and your periodPower are the same, but they will not be printed always in the same order, since millis() can change while going through the loop() function.

I think that the goal is a single line with all the data.
That means you need a single millis timer to print all the data.

You should not use millis() like this: if (millis() >= currentLastSample + 1)
To average a value, you can take 5 to 1000 samples without delay. That will get rid of the electronic noise just as well.
If you want to capture data during 1 second with some spacing between the samples, then you could use millis(). I think it is safer to check if millis() has changed.

unsigned long previousMillisSampling;

void loop()
{
  unsigned long currentMillis = millis();

  if (currentMillis != previousMillisSampling)  // has millis() changed ?
  {
    previousMillisSampling = currentMillis;
    
    voltageSampleSum += analogRead(VoltageAnalogInputPin);
    voltageSampleCount++;    // increment number of taken samples

    currentSampleSum += analogRead(CurrentAnalogInputPin);
    currentSampleCount++;
  }
}

To print data, use a single millis timer:

unsigned long previousMillisPrint;

void loop()
{
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillisPrint >= 1000UL)
  {
    previousMillisPrint = currentMillis;

    calculate voltage and print it
    calculate current and print it
    calculate power and print it
    calculate energy and print it
  }
}
2 Likes

Since you have Excel, why are you messing about with the serial monitor?

PLX-DAQ version 2 - now with 64 bit support! (and further new features)

1 Like

Thanks for the response! I've been playing around with the code you've provided, and made good progress. My serial monitor is printing results fine, but now my current measurement is no longer accurate. It's displaying values between the range of -0.10 to .10 when there is zero current applied. I'll provide my new code per your suggestions below. Any idea how to fix this issue? Thanks again for your response very helpful.

        int decimalPrecision = 2;                   // decimal places for all values shown in LED Display & Serial Monitor
    
/* 1- DC Voltage Measurement using Voltage Divider Method */

        int VoltageAnalogInputPin = A1;             // Which pin to measure Voltage Value (A0 is reserved for LCD Shield buttons function)
        float voltageSampleRead  = 0;               /* to read the value of a sample*/
        float voltageLastSample  = 0;               /* to count time for each sample. Technically 1 milli second 1 sample is taken */
        float voltageSampleSum   = 0;               /* accumulation of sample readings */
        float voltageSampleCount = 0;               /* to count number of sample. */
        float voltageMean ;                         /* to calculate the average value from all samples*/ 
        float moduleSupplyVoltageV = 5;             /* maximum measuring voltage , default 5V*/
        float R1 = 47000; //30000.0;                         // Input resistance value for R1 (in ohm) based on Voltage Divider Method 
        float R2 = 2200; //7500.0;                          // Input resistance value for R2 (in ohm) based on Voltage Divider Method 
        float finalVoltage =0;                      /*shows the final voltage reading*/
    

/* 2- DC Current Measurement */
   
        int CurrentAnalogInputPin = A2;             // Which pin to measure Current Value (A0 is reserved for LCD Shield buttons function)
        float mVperAmpValue = 100;                  // If using ACS712 current module : for 5A module key in 185, for 20A module key in 100, for 30A module key in 66
                                                    // If using "Hall-Effect" Current Transformer, key in value using this formula: mVperAmp = maximum voltage range (in milli volt) / current rating of CT
                                                    /* For example, a 20A Hall-Effect Current Transformer rated at 20A, 2.5V +/- 0.625V, mVperAmp will be 625 mV / 20A = 31.25mV/A */
        
        float moduleMiddleVoltage = 2500;           /* when there is no reading, the voltage is at middle Vcc. For 5V power supply, the middle voltage is 2500mV;*/
        float moduleSupplyVoltage = 5000;           /* supply voltage to current sensor module, default 5000mV*/
        float currentSampleRead  = 0;               /* to read the value of a sample*/
        float currentLastSample  = 0;               /* to count time for each sample. Technically 1 milli second 1 sample is taken */
        float currentSampleSum   = 0;               /* accumulation of sample readings */
        float currentSampleCount = 0;               /* to count number of sample. */
        float currentMean ;                         /* to calculate the average value from all samples*/ 
        float finalCurrent ;                        /* the final current reading without adding offset value*/
        float finalCurrent2 ;                       /* the final current reading*/


        /* 2.1- DC Current Offset */
        
              int OffsetRead = 0;                   /* To switch between functions for auto callibation purpose */   
              float currentOffset =-12.45 ;           // to Offset deviation and accuracy. Offset any fake current when no current operates. 
                                                    // Look into serial monitor to add or minus the value.
                                                    // 0.26 means add 0.26A to all current measured value.
                                                    /* if you have LCD Display Shield, this offset can be automatically adjusted by pressing SELECT button */
              float offsetLastSample = 0;           /* to count time for each sample. Technically 1 milli second 1 sample is taken */
              float offsetSampleCount = 0;          /* to count number of sample. */

/* 3- DC Power Wattage calculation */

  float PowerValue =0;                          /* Initial calculation Power Value */
    //unsigned long startMillisPower;               /* start counting time for power */
    //unsigned long currentMillisPower;             /* current counting time for power */
    //const unsigned long periodPower = 1000;       // refresh every X seconds (in seconds) Default 1 = 1 second 

/* 4- DC Watt-hour calculation */

   float wattHour  = 0;                           /* Initial calculation Energy Value */
   const unsigned long periodEnergy = 1000;       // refresh every X seconds (in seconds) Default 1000 = 1 second 
    float FinalEnergyValue = 0;                    /*shows the final Energy reading*/


unsigned long previousMillis;
unsigned long previousMillisSampling;
//float PowerValue;
//float wattHour;
//float FinalEnergyValue;
void setup()                                  /* The Codes only run 1 time only when Arduino started.*/
 
  {

/* 0- General */

    Serial.begin(9600);                       /* In order to see value in serial monitor */
    

unsigned long previousMillisSampling;
    
  }

  
void loop()                                 /* The Codes run repeatly over and over again.*/

  {

     unsigned long currentMillis = millis();

  if (currentMillis != previousMillisSampling)     // has millis() changed ?    
{
   previousMillisSampling = currentMillis;
    
    voltageSampleSum += analogRead(A1);
    voltageSampleCount++;    // increment number of taken samples

    currentSampleSum += analogRead(A2);
    currentSampleCount++;
}

if(millis() >= voltageLastSample + 1 )                                                                /* every 1 milli second taking 1 reading */
         
          
          
          
          {
           voltageSampleRead = analogRead(A1);                                            /* read the sample value */
            voltageSampleSum = voltageSampleSum + voltageSampleRead ;                                         /* accumulate value with older sample readings*/
            voltageSampleCount = voltageSampleCount + 1;                                                      /* to move on to the next following count */
            voltageLastSample = millis();                                                                     /* to reset the time again so that next cycle can start again*/ 
          }

          
           if(millis() >= currentLastSample + 1 )                                                                /* every 1 milli second taking 1 reading */
          {
            currentSampleRead = analogRead(A2)-((moduleMiddleVoltage/moduleSupplyVoltage)*1024);      /* read the sample value */
            currentSampleSum = currentSampleSum + currentSampleRead ;                                         /* accumulate value with older sample readings*/
            currentSampleCount = currentSampleCount + 1;                                                      /* to move on to the next following count */
            currentLastSample = millis();                                                                     /* to reset the time again so that next cycle can start again*/ 
          }
    
        
 if (currentMillis - previousMillis >= 1000UL)
  {
    previousMillis = currentMillis;

    //calculate voltage and print it

     voltageMean = voltageSampleSum/voltageSampleCount;                                                /* calculate average value of all sample readings taken*/
     finalVoltage = 0.25+(((voltageMean*moduleSupplyVoltageV)/1024) / (R2/(R1+R2))); 
           Serial.print("V : ");
           Serial.print( finalVoltage,decimalPrecision);
           Serial.print(" V ");
           Serial.print('\t'); 
           voltageSampleSum =0;                                                                              /* to reset accumulate sample values for the next cycle */
           voltageSampleCount=0;   
          }    
 
  //  calculate current and print it

  
   currentMean = currentSampleSum/currentSampleCount;                                                /* calculate average value of all sample readings taken*/
   finalCurrent = (((currentMean /1024) *5000) /mVperAmpValue);                                      /* calculate the final RMS current*/
   finalCurrent2 = - (finalCurrent + currentOffset);
         
           Serial.print("I : ");
           Serial.print(finalCurrent2,decimalPrecision);
           Serial.print(" A ");
           Serial.print('\t'); 
           currentSampleSum =0;                                                                              /* to reset accumulate sample values for the next cycle */
           currentSampleCount=0;    

           
   // calculate power and print it

    PowerValue = finalCurrent2 * finalVoltage;
            Serial.print("P : " );
            Serial.print(PowerValue,decimalPrecision); 
            Serial.print(" W "); 
            
            Serial.print('\t'); 
      
         
   // calculate energy and print it

   wattHour = PowerValue * 1;                                                       /* for smoothing calculation*/
            FinalEnergyValue =  wattHour;
            Serial.print("E : " );
            Serial.print(FinalEnergyValue,decimalPrecision); 
            Serial.print(" Wh "); 
            Serial.println();
            Serial.print('\t'); 
            delay(1000);
  }

What are the raw data values you are measuring? You can always expect a little jitter in the LSbit.

Can you do all the Serial.print() for the current and enery and everything inside the millis-timer and remove the delay(1000); at the end ?

You should not use millis() like this: if (millis() >= currentLastSample + 1)
That is a bug.
Can you remove those two parts completely ? There should be one place that does the analogRead() and calculates the sum of them. If you do that in two places, then the flow of the data is disturbed.
Just add analogRead() value together (preferably in a 'unsigned long' and not a 'float') and do the calculations when you print the values.

Please right-click on the code in Arduino 2.1 and select "Format Document".
It is not possible to write good code if the layout of the text is almost not readable. Keep it nice and tidy. Use indents, commas, spaces and new lines in the right way.

If the time really matters to less than a few ms, don't use millis(), use micros() instead. The way that millis() works every read is +/- 1 ms. When you calculate elapsed time, you can get 2 ms off.

The always correct time formula is in unsigned integers: end - start = elapsed. This formula has no rollover, unsigned math is circular as a round clock.. clockwise is add, ccw is subtract.

Using millis or micro timing, salting in delays is how to make it jerk and stutter. Spend more time on simple timer demos, you don't get what goes on there and maybe think these boards are much slower than they can be.

  1. your acquisition is in integer counts. Keep your sum in integer counts, move to float only when you calculate the average(and, don't use "mean" when you're doing an average, please; I fixed that).
  2. learn to divide and conquer. Modularize your code, and execute as necessary.
  3. I broke the code up into modules that make sense. For example, adding a module to publish, for example, at a different rate from the print function, would be very simple in this structure.
  4. I probably mucked up your calculations in the process of separating it out, so check that function very carefully.
  5. when commenting, suppress the urge to state the obvious. If it isn't obvious, your first choice should be to restructure the code, and choose better variable names. Comments should reflect higher-level structure, not
    i=0 //set i to zero
  6. I left alone most of the things that seemed to be either extraneous, or 'forward-thinking', or incomplete.
    Consider the following(untested, no hardware):
//global values
const unsigned int decimalPrecision = 2;         // decimal places for all values shown in LED Display & Serial Monitor

//pins
const int VoltageAnalogInputPin = A1;             // Which pin to measure Voltage Value (A0 is reserved for LCD Shield buttons function)
const int CurrentAnalogInputPin = A2;             // Which pin to measure Current Value (A0 is reserved for LCD Shield buttons function)

// other hardware related
const float moduleSupplyVoltageV = 5;             /* maximum measuring voltage , default 5V*/
const float R1 = 47000; //30000.0;                         // Input resistance value for R1 (in ohm) based on Voltage Divider Method
const float R2 = 2200; //7500.0;                          // Input resistance value for R2 (in ohm) based on Voltage Divider Method
const float moduleMiddleVoltage = 2500;           /* when there is no reading, the voltage is at middle Vcc. For 5V power supply, the middle voltage is 2500mV;*/
const float moduleSupplyVoltage = 5000;           /* supply voltage to current sensor module, default 5000mV*/
const unsigned int ConversionCount = 1024;
const float mVperAmpValue = 100;                  // If using ACS712 current module : for 5A module key in 185, for 20A module key in 100, for 30A module key in 66

// If using "Hall-Effect" Current Transformer, key in value using this formula: mVperAmp = maximum voltage range (in milli volt) / current rating of CT
/* For example, a 20A Hall-Effect Current Transformer rated at 20A, 2.5V +/- 0.625V, mVperAmp will be 625 mV / 20A = 31.25mV/A */

//results containers
float finalVoltage;                        /* final voltage reading */
float finalCurrent;                        /* final current reading */
float PowerValue;                          /* Initial calculation Power Value */
float FinalEnergyValue;                    /* final Energy reading*/
int lastSampleCount;                       /* most recent sample count*/
//time management
unsigned long CurrentMillis;
unsigned long PreviousSampleMillis;
unsigned long PreviousCalcMillis;
unsigned long PreviousPrintMillis;
const unsigned long SampleInterval = 1;
const unsigned long CalcInterval = 1;
const unsigned long PrintInterval = 1000;

//raw data
unsigned long voltageSampleSum = 0;
unsigned long currentSampleSum = 0;
unsigned int SampleCount = 0;

void setup() {
  Serial.begin(115200); //use a better serial baud; just remember to set SerialMonitor the same!!!!!!!!!!!!
}

void loop() {
  CurrentMillis = millis();
  if (PreviousSampleMillis < CurrentMillis - SampleInterval) {//checks the interval correctly, which deals with over/underflow
    sampledata();
    PreviousSampleMillis = CurrentMillis;  //resets interval measurement
  }
  if (PreviousCalcMillis < CurrentMillis - CalcInterval)     {//checks the interval correctly, which deals with over/underflow
    calcdata();
    PreviousCalcMillis = CurrentMillis;   //resets interval measurement
  }
  if (PreviousPrintMillis < CurrentMillis - PrintInterval)   {//checks the interval correctly, which deals with over/underflow
    printdata();
    PreviousPrintMillis = CurrentMillis;  //resets interval measurement
  }
}

void sampledata() {
  voltageSampleSum += analogRead(VoltageAnalogInputPin);  //why did you create ints for the pins, then not use them?
  currentSampleSum += analogRead(CurrentAnalogInputPin);
  SampleCount++;    // increment number of taken samples
}

void printdata() {
  Serial.print('\t');
  //print sample count
  //Serial.print("C : ");  Serial.print(lastSampleCount);                    Serial.print(" S ");  Serial.print('\t');
  //print voltage
  Serial.print("V : ");  Serial.print(finalVoltage, decimalPrecision);     Serial.print(" V ");  Serial.print('\t');
  //print current
  Serial.print("I : ");  Serial.print(finalCurrent, decimalPrecision);     Serial.print(" A ");  Serial.print('\t');
  //print power
  Serial.print("P : ");  Serial.print(PowerValue, decimalPrecision);       Serial.print(" W ");  Serial.print('\t');
  //print energy
  Serial.print("E : ");  Serial.print(FinalEnergyValue, decimalPrecision); Serial.print(" Wh "); Serial.println();
}

void calcdata() {
  /* 1- DC Voltage Measurement using Voltage Divider Method */
  float voltageAvg ;                         /* to calculate the average value from all samples*/
  voltageAvg = voltageSampleSum / SampleCount;                                              /* calculate average value of all sample readings taken*/
  finalVoltage = 0.25 + (((voltageAvg * moduleSupplyVoltageV) / 1024) / (R2 / (R1 + R2)));

  /* 2- DC Current Measurement */
  float currentAvg ;                         /* to calculate the average value from all samples*/
  float rawCurrent ;                        /* the final current reading without adding offset value*/
  float finalCurrent ;                        /* the final adjusted reading*/
  currentAvg = currentSampleSum / SampleCount;                                              /* calculate average value of all sample readings taken*/
  rawCurrent = (((currentAvg / ConversionCount) * moduleSupplyVoltage) / mVperAmpValue);                                   /* calculate the final RMS current*/

  /* 2.1- DC Current Offset */
  //int OffsetRead = 0;                   /* To switch between functions for auto callibation purpose */
  float currentOffset = -12.45 ;          // to Offset deviation and accuracy. Offset any fake current when no current operates.
  // Look into serial monitor to add or minus the value.
  // 0.26 means add 0.26A to all current measured value.
  finalCurrent = - (rawCurrent + currentOffset);

  /* if you have LCD Display Shield, this offset can be automatically adjusted by pressing SELECT button */
  //float offsetLastSample = 0;           /* to count time for each sample. Technically 1 milli second 1 sample is taken */
  //float offsetSampleCount = 0;          /* to count number of sample. */

  /* 3- DC Power Wattage calculation */
  PowerValue = finalCurrent * finalVoltage;

  /* 4- DC Watt-hour calculation */
  float unidentifiedconstant = 1;
  float wattHour  = 0;                           /* Initial calculation Energy Value */
  //  const unsigned long periodEnergy = 1000;       // refresh every X seconds (in seconds) Default 1000 = 1 second
  wattHour = PowerValue * unidentifiedconstant;                                                       /* for smoothing calculation*/
  FinalEnergyValue =  wattHour;

  //----------------   WRAPUP   --------------------------------------------------------------
  lastSampleCount = SampleCount;                                                                    /* saved for printing  */
  SampleCount = 0;                                                                                  /* Reset averaging counter */
  voltageSampleSum = 0;                                                                             /* to reset accumulate sample values for the next cycle */
  currentSampleSum = 0;                                                                             /* to reset accumulate sample values for the next cycle */
}
2 Likes

About Serial baud, and Serial Monitor - setting the baud rate low means the already-printed values, etc. take a long time to get transmitted. As a result, since your output string is long, it's possible your output buffer will fill, and at that point serial printing is a blocking process; that will delay your measurement cycle. Increase the baud rate, and your buffer empties quickly. Possibly, still slowly enough that your cycle is impacted, but it should be much less.
The real solution would be to not print the entire line as a block, but rather do the printing piecemeal, but I don't think it's necessary to add that complication. I added the last sample count printout in the printout routine(but commented it out) so you could keep an eye on that; if it's low, or drops, you'll need to rethink printing.

2 Likes

Okay so after testing a few times, no current is being measured by your code. Voltage works fine, but something is happening where no current is being registered by my Arduino. I'm going to play around and try to figure it out, but otherwise the code is much better than what I was using previously. Any ideas why current isn't registering?

Thanks for taking the time to answer and type out the code for me, I really appreciate the guidance!

Try an extra print statement, printing just the raw current value.

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