Output variable at time intervals

And when someone gives you some extra good advice that you didn't ask for, explain to me how that brings you any harm at all?

Even if you don't need it or want it, it was nice of @PaulRB to do that for you, and you can be appreciative of that even if you ignore the good advice.

Vaguely like that, perhaps. Consider attempting to compile what you post, it's often informative.
your int vt; has a value of zero, that's standard for any global that doesn't get an explicit value at declaration.
Your array length would therefore be zero (but in fact doesn't exist, because vt isn't a constant at compile time, so the compiler quite rightly fails).
Both setup() and loop() require void as a type when you declare them, so you might as well type those words, too, even though it's a "something like" example.
And, of course, prevTime=currentTime(); might cause issues, as the () don't belong.
So yeah, vaguely like is about it. But, I think you completely missed my point. I'm not suggesting for a minute you start out with setup and loop rewriting. I was trying to suggest you might be able to achieve what you want WITHOUT wholesale slaughter of your code, with a well-considered function call.
But the whole discussion has digressed at this point, to the point of pointlessness.

I try to learn the free advice that is given to me. I even try to implement it on occasion. Doesn't mean it takes. Sometimes I just get to much information, I need smaller bits to work on. But for the most part, I only have a few hours a week I can actually dedicate to prototyping. So I pick and choose what I try to do.

Anyway, the following function I created was able to print to Serial vTime every 15 seconds.

void getVTime() {
  if(isrunning==true){
  getCalculations();
  for (int vt = 0; vt < 39; vt++)
    intervalTime = millis() - previntervalTime;
  if (intervalTime >= 15000) {
    previntervalTime = millis();
    vTime[vt] = voltageFull;
    Serial.println(vTime[vt]);
  }

Sorry, a lot of time I am posting from my work computer and don't have a compiler on it. I just write the code into the tags on the forum. It isn't until I get a chance to get to my laptop in my dungeon that I can actually compile and test stuff.

So I had to make the following variables for my function to work. vt had to be a const int, you probably knew that, but I didn't lol. Yes, I had to mess with the timing a bit. And yes, I intended to make a function. I was just trying to post as full a code as I could for an example.

But now that this works, I have to work on sending it to my display.

const int vt = 40;
float vTime[vt];

This is where my entire code stands right now.

/*
    Code Version 1.0
    WMH Racing Battery Wizard
    Written by Andrew Sarratore
    Date: 10/28/2023
    Code Version 1.1
    Add getCurrentAverage()
    add getFVoltageAverage()
    add getCalculations()
    add Program()
    Changes to the "Run Program" Menu
    Date:12/11/2023
    Code Version 1.2
    add getPVoltageAverage
    add more readings to the dishcharge display
    Code Version 1.3
    Date:12/27/2023
    add self calibrate VCC
    add mAH reading, untested
    add PID_v1.h library, still need to write PID code for the PWM value and replace current feedback loop
    Code Version 1.4
    Date:12/30/2023
    Add IR struct - Untested
    Add getIR function - still need to write the menu and page function
    Code Version 1.4.2
    Date:1/4/2024
    Calibrate initial QOV based on VCC during setup
    Fixed averages to be floats instead of int...
    Adding IR Reading menus
    Code Version 1.5
    PID added, Kp=0.25, Ki=10, Kd=0
    Added page 6 for displaying voltage data
Date:1/15/24
Code Version 1.6
Changed where the code calls the calculations and true VCC functions from.  This made other parts of the loop faster and vcc more accurate
Added in a multiplier to voltage under load.  (Icurrent/1000)*4.  I can simplify to Icurrent/250.  
This fixes voltage under load readings at various discharge rates.  May change for each unit
Date:1/16/24
Code Version 1.7
Adding 1S support
Date:1/17/24
Code Version 1.8
Adding Struct for Time/Voltage variable
Filling the page for the Time/Voltage variable  vTime
Date: 1/17/24
Code Version1.9
Added Array for vTime for Voltage vs Time on discharge   
Voltage values every 15 seconds
Still need to send to display

 - look into graphing this, would be cool.  
   
   
*/

#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"
#include "XPT2046_Touchscreen.h"
#include "Math.h"
#include "PID_v1.h"
#include "movingAvg.h"

// Define SPI pins for both display and touch
#define TFT_CS 10
#define TFT_DC 9
#define TFT_MOSI 11
#define TFT_CLK 13
#define TFT_RST 8
#define TFT_MISO 12
#define TS_CS 7
#define ROTATION 1
#define Isens A0
#define VFsens A1
#define VPsens A2
#define PWM 3
#define K (1.0 / 30)

char currentPage;
char numberCells;

// Use hardware SPI (on Uno, #13, #12, #11) and the above for CS/DC/RST
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);
XPT2046_Touchscreen ts(TS_CS);

// calibration values
float xCalM = -0.09, yCalM = -0.06;    // gradients
float xCalC = 329.36, yCalC = 248.13;  // y axis crossing points

int8_t blockWidth = 20;  // block size
int8_t blockHeight = 20;
int16_t blockX = 0, blockY = 0;  // block position (pixels)

class ScreenPoint {
public:
  int16_t x;
  int16_t y;

  // default constructor
  ScreenPoint() {
  }

  ScreenPoint(int16_t xIn, int16_t yIn) {
    x = xIn;
    y = yIn;
  }
};

class Button {
public:

  int x;
  int y;
  int width;
  int height;
  char *text;

  Button() {
  }

  void initButtonG(int xPos, int yPos, int butWidth, int butHeight, char *butText) {
    x = xPos;
    y = yPos;
    width = butWidth;
    height = butHeight;
    text = butText;
    renderG();
  }
  void initButtonR(int xPos, int yPos, int butWidth, int butHeight, char *butText) {
    x = xPos;
    y = yPos;
    width = butWidth;
    height = butHeight;
    text = butText;
    renderR();
  }
  void initButtonB(int xPos, int yPos, int butWidth, int butHeight, char *butText) {
    x = xPos;
    y = yPos;
    width = butWidth;
    height = butHeight;
    text = butText;
    renderB();
  }
  void initButtonY(int xPos, int yPos, int butWidth, int butHeight, char *butText) {
    x = xPos;
    y = yPos;
    width = butWidth;
    height = butHeight;
    text = butText;
    renderY();
  }
  void renderG() {
    tft.fillRect(x, y, width, height, ILI9341_GREEN);
    tft.setCursor(x + 5, y + 5);
    tft.setTextSize(2);
    tft.setTextColor(ILI9341_WHITE);
    tft.print(text);
  }
  void renderR() {
    tft.fillRect(x, y, width, height, ILI9341_RED);
    tft.setCursor(x + 5, y + 5);
    tft.setTextSize(2);
    tft.setTextColor(ILI9341_WHITE);
    tft.print(text);
  }
  void renderB() {
    tft.fillRect(x, y, width, height, ILI9341_BLUE);
    tft.setCursor(x + 5, y + 5);
    tft.setTextSize(2);
    tft.setTextColor(ILI9341_WHITE);
    tft.print(text);
  }
  void renderY() {
    tft.fillRect(x, y, width, height, ILI9341_YELLOW);
    tft.setCursor(x + 5, y + 5);
    tft.setTextSize(2);
    tft.setTextColor(ILI9341_WHITE);
    tft.print(text);
  }
  bool isClicked(ScreenPoint sp) {
    if ((sp.x >= x) && (sp.x <= (x + width)) && (sp.y >= y) && (sp.y <= (y + height))) {
      return true;
    } else {
      return false;
    }
  }
};

// Struct for getIR
unsigned const int numChan = 5;
unsigned int chan;
struct ChannelData {
  float startVoltageP;
  float startVoltageF;
  float endVoltageP;
  float endVoltageF;
  float voltageDropP;
  float voltageDropF;
  float internalResistanceP;
  float internalResistanceF;
};
ChannelData Channels[numChan];


const int vt = 40;
float vTime[vt];

//Touch Screen
ScreenPoint getScreenCoords(int16_t x, int16_t y) {
  int16_t xCoord = round((x * xCalM) + xCalC);
  int16_t yCoord = round((y * yCalM) + yCalC);
  if (xCoord < 0) xCoord = 0;
  if (xCoord >= tft.width()) xCoord = tft.width() - 1;
  if (yCoord < 0) yCoord = 0;
  if (yCoord >= tft.height()) yCoord = tft.height() - 1;
  return (ScreenPoint(xCoord, yCoord));
}

// I can probably make an array of the following button variables...
Button btnIP;  // Current Selection +
Button btnIM;  // Current Selection -
Button btnVP;  // Cutoff V +
Button btnVM;  // Cutoff V -
Button btnMI;  // Main - Discharge Rate
Button btnMV;  // Main - Voltage Cutoff
Button btnMM;  // Main Menu on other pages
Button btnCT;  // Main Calibrate Touch
Button btnRP;  // Main Menu - Run Program
Button btnPN;  // Run/Running
Button btnMN;  // Discharge - Main Menu
Button btnRN;  // STOP
Button btnIR;  // Main - IR Reading
Button btnRC;  // IR Reading - Check IR
Button btnDD;  // Discharge - dischargeData
Button btnRPD;

double IV = 10;                  // Initial rate of discharge in ampres.  User changable in code
float VV = 350.00;               // Cutoff voltage*100 so ++ works to change the value
unsigned long StartTime;         // Start time to measure time of discharge
unsigned long CurrentTime;       // Will give how long the discharge is running
unsigned long mahTime;           // used for mAH
unsigned long prevmahTime;       // used for mAH
unsigned long intervalTime;      //used for vTime data
unsigned long previntervalTime;  //used for vTime data
unsigned long runTime;           // runTime of the discharge function
unsigned long lastFrame;         // used for screen flickering
unsigned long int intervalAV;
unsigned long int previntervalAV;

//PID
double Input;
double Output;
//Specify the links and initial tuning parameters
double Kp = .01, Ki = 15, Kd = 0;
PID myPID(&Input, &Output, &IV, Kp, Ki, Kd, DIRECT);

// Current Variables
float VCC = 0;         // 4.967  measure the value(Measure value not needed with the VCC calibration code)
float VCCC = 0;        // Used for Accurate Voltage
float QOV = 0;         // Calibration happens in setup
float sens = 0.04;     //sensitivity of the current sensor
float iavg;            // analogRead(Isens)/IN
float Icurrent = 0;    // Current Reading in Amps
float Icorrected = 0;  //iavg-IOFF
float voltageI = 0;    // iavg translated to voltage
float IOFF = 0.0;      // Offset to the raw read to zero current
int IN = 1000;         // Sample number to average current
float mAH;             // mAH used
float rTmAH;           // Runtime mAH used, highest value

// Battery Voltage Variables (may be able to make a struct or class here as well)
int ValueR1F = 5094;       //Measured value
int ValueR2F = 5104;       //Measured value
int ValueR1P = 5106;       //Measured value
int ValueR2P = 5082;       //Measured value
int VFN = 1000;            // Sample number for average of analogRead(VFsens) Full voltage
int VPN = 1000;            // Sample number for average of analogRead(VPsens) Partial voltage
float vfavg;               // Average of the analogRead(VFsens)/VFN      -Full Voltage
float vpavg;               // Average of the analogRead(VPsens)/VPN      -Partial Voltage
float Fvoltage = 0;        // Calculation of FV seen by MCU
float Pvoltage = 0;        // Calculation of PV seen by MCU
float voltageFull = 0;     // Calculation of Full Voltage
float voltagePartial = 0;  // Calculation of Partial Voltage
float cell1 = 0;           // Voltage of Cell 1
float cell2 = 0;           // Voltage of Cell 2
float internalResistanceAVGP = 0;
float internalResistanceAVGF = 0;
boolean isrunning = false;
boolean irRunning = false;
int zz = 0;  // variable used for analogWrite(PWM,zz)

//===================================================================SETUP=========================================================================================
void setup() {
  Serial.begin(115200);
  // avoid chip select contention
  pinMode(TS_CS, OUTPUT);
  digitalWrite(TS_CS, HIGH);
  pinMode(TFT_CS, OUTPUT);
  pinMode(Isens, INPUT);
  pinMode(VFsens, INPUT);
  pinMode(VPsens, INPUT);
  pinMode(PWM, OUTPUT);
  digitalWrite(TFT_CS, HIGH);
  tft.begin();
  tft.setRotation(ROTATION);
  tft.fillScreen(ILI9341_BLACK);
  ts.begin();
  ts.setRotation(ROTATION);
  //calibrateTouchScreen(); Leaving here for first run of the dispaly to get coordinates of touch screen
  getAccurateVoltage();
  getCurrentAverage();
  getFVoltageAverage();
  getPVoltageAverage();
  getCalculations();
  calibrateQOV();
  lastFrame = millis();
  previntervalAV = millis();
  //initialize the variables we're linked to
  Input = Icurrent;
  //turn the PID on
  myPID.SetMode(AUTOMATIC);
  currentPage = '0';  //  Indicates that we are at Home Screen
  Home();
}  //==================================================================END SETUP=====================================================================

//======================================================================LOOP======================================================================
void loop() {
  ScreenPoint sp;
  // limit frame rate
  //while((millis() - lastFrame) < 20); //(caused issues with millis function to get mAH, may need to revisit as this helped some flickering)
  //lastFrame = millis();
  intervalAV = millis() - previntervalAV;
  if (intervalAV >= 60000 && voltageFull <= 0.5) {
    previntervalAV = millis();
    getAccurateVoltage;
    Serial.println("Updated VCC!");
  }

  // Home Screen
  if (currentPage == '0') {

    if (ts.touched()) {
      TS_Point p = ts.getPoint();
      sp = getScreenCoords(p.x, p.y);
      if (btnMV.isClicked(sp)) {
        currentPage = '1';  // Go to Discharge Current
        tft.fillScreen(ILI9341_BLACK);
        discharge();
      } else if (btnMI.isClicked(sp)) {
        currentPage = '2';  // Go to Cutoff Voltage
        tft.fillScreen(ILI9341_BLACK);
        cutoff();
      }

      else if (btnCT.isClicked(sp)) {
        currentPage = '3';  // Go to Calibrate Screen
        tft.fillScreen(ILI9341_BLACK);
        calibrateTouchScreen();
      }

      else if (btnRP.isClicked(sp)) {
        currentPage = '4';  // Go to Run Program
        getCalculations();
        tft.fillScreen(ILI9341_BLACK);
        program();
      }

      else if (btnIR.isClicked(sp)) {
        currentPage = '5';  // Go to irReading
        tft.fillScreen(ILI9341_BLACK);
        irReading();
      }
    }
  }

  // Discharge Current
  if (currentPage == '1') {
    tft.setCursor(100, 150);
    tft.print(IV, 0);
    tft.setCursor(190, 150);
    tft.print("A");
    if (ts.touched()) {
      TS_Point p = ts.getPoint();
      sp = getScreenCoords(p.x, p.y);
      if (btnIP.isClicked(sp)) {
        if (IV < 45) {
          IV++;
        }
        tft.fillRect(100, 150, 125, 50, ILI9341_BLACK);
        delay(100);
      } else if (btnIM.isClicked(sp)) {
        IV--;
        tft.fillRect(100, 150, 125, 50, ILI9341_BLACK);
        delay(100);

      } else if (btnMM.isClicked(sp)) {
        currentPage = '0';
        Home();
      }
    }
  }  // End Page 1

  // Cutoff Voltage
  if (currentPage == '2') {
    tft.setCursor(100, 150);
    tft.print(VV / 100);
    tft.setCursor(210, 150);
    tft.print("V");
    if (ts.touched()) {
      TS_Point p = ts.getPoint();
      sp = getScreenCoords(p.x, p.y);
      if (btnIP.isClicked(sp)) {
        VV++;
        tft.fillRect(100, 150, 100, 50, ILI9341_BLACK);
        delay(100);
      } else if (btnIM.isClicked(sp)) {
        if (VV > 280) {
          VV--;
        }
        tft.fillRect(100, 150, 100, 50, ILI9341_BLACK);
        delay(100);
      } else if (btnMM.isClicked(sp)) {
        currentPage = '0';
        Home();
      }
    }
  }  // End Page 2

  // Run Discharge (Surely I can move some of this to the page function, but when moved it caused the screen to refresh every loop)
  if (currentPage == '4') {
    getCalculations();
    getVTime();
    SerialData();
    tft.setCursor(0, 50);
    tft.setTextSize(2);
    tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
    tft.print("Battery:");
    tft.setCursor(0, 75);
    tft.print("Cutoff ");
    tft.print(VV / 100);
    tft.print("V");
    tft.setTextSize(2);
    tft.setCursor(0, 100);
    tft.print("Actual ");
    tft.print(voltageFull, 2);
    tft.setCursor(145, 100);
    tft.print("V");
    tft.setCursor(160, 50);
    tft.print("Current:");
    tft.setCursor(160, 75);
    tft.print("Rate ");
    tft.print(IV, 0);
    tft.print("A");
    tft.setCursor(160, 100);
    tft.print("Actual ");
    tft.print(Icurrent, 1);
    tft.setCursor(305, 100);
    tft.print("A");
    tft.setTextSize(1);
    tft.setCursor(160, 120);
    tft.print("Time");
    tft.setCursor(160, 130);
    tft.fillRect(160, 130, 50, 10, ILI9341_BLACK);
    tft.print(runTime);
    tft.setCursor(240, 120);
    tft.print("mAH");
    tft.setCursor(240, 130);
    tft.print(rTmAH, 0);
    tft.setCursor(0, 150);
    tft.print("VCC");
    tft.setCursor(0, 160);
    tft.print(VCC, 3);

    if (voltageFull > 5) {
      tft.setTextSize(1);
      tft.setCursor(0, 120);
      tft.print("Cell 1  ");
      tft.setCursor(45, 120);
      tft.print(cell1, 3);
      tft.setCursor(80, 120);
      tft.print("V");
      tft.setCursor(0, 130);
      tft.print("Cell 2  ");
      tft.setCursor(45, 130);
      tft.print(cell2, 3);
      tft.setCursor(80, 130);
      tft.print("V");
    }  //

    else if (voltageFull < 5) {
      tft.setTextSize(1);
      tft.setCursor(0, 120);
      tft.print("Cell 1  ");
      tft.setCursor(45, 120);
      tft.print(cell1, 3);
      tft.setCursor(80, 120);
      tft.print("V");
      tft.setCursor(0, 130);
    }  //end if

    if (isrunning == true) {
      btnPN.initButtonR(0, 15, 140, 25, "DISCHARGE");
      RunDischarge();
    } else {
      tft.setTextColor(ILI9341_WHITE, ILI9341_GREEN);
      btnPN.initButtonG(0, 15, 140, 25, "    RUN");
    }
    if (ts.touched()) {
      TS_Point p = ts.getPoint();
      sp = getScreenCoords(p.x, p.y);
      if (btnMN.isClicked(sp)) {
        currentPage = '0';
        Home();
      } else if (btnRN.isClicked(sp)) {
        zz = 0;
        analogWrite(PWM, zz);
        isrunning = false;
      } else if (btnPN.isClicked(sp)) {
        tft.fillRect(160, 130, 320, 10, ILI9341_BLACK);
        rTmAH = 0;
        runTime = 0;
        StartTime = millis();
        prevmahTime = millis();
        previntervalTime = millis();
        isrunning = true;

      } else if (btnDD.isClicked(sp)) {
        tft.fillScreen(ILI9341_BLACK);
        currentPage = '6';
        dischargeData();
      }
    }  //end if

  }  // End Page 4

  // IR Reading
  if (currentPage == '5') {
    tft.setCursor(0, 60);
    tft.print("Cell 1");
    tft.setCursor(0, 80);
    tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
    if (numberCells == '2') {
      tft.print(internalResistanceAVGF - internalResistanceAVGP);
    } else if (numberCells == '1') {
      tft.print(internalResistanceAVGF);
    }
    tft.setCursor(80, 80);
    tft.print("m");
    tft.drawChar(90, 80, 233, ILI9341_WHITE, 2, 2);
    if (numberCells == '2') {
      tft.setCursor(0, 100);
      tft.print("Cell 2");
      tft.setCursor(0, 120);
      tft.print(internalResistanceAVGP);
      tft.setCursor(80, 120);
      tft.print("m");
      tft.drawChar(90, 120, 233, ILI9341_WHITE, 2, 2);
    }

    if (irRunning == true) {
      btnRC.initButtonR(90, 15, 140, 25, "Reading IR");
      tft.setCursor(0, 80);
      tft.fillRect(0, 40, 100, 100, ILI9341_BLACK);

      getIR();
    } else {
      tft.setTextColor(ILI9341_WHITE, ILI9341_GREEN);
      btnRC.initButtonG(90, 15, 140, 25, "  Check IR  ");
    }
    if (ts.touched()) {
      TS_Point p = ts.getPoint();
      sp = getScreenCoords(p.x, p.y);
      if (btnMM.isClicked(sp)) {
        currentPage = '0';
        Home();
      }

      else if (btnRC.isClicked(sp)) {
        irRunning = true;
      }
    }
  }  // End Page 5

  if (currentPage == '6') {
    getVTime();
    tft.setTextSize(1);
    tft.setTextColor(ILI9341_ORANGE);
    tft.setCursor(25, 45);
    tft.print(voltageFull);
    if (ts.touched()) {
      TS_Point p = ts.getPoint();
      sp = getScreenCoords(p.x, p.y);
      if (btnMM.isClicked(sp)) {
        currentPage = '0';
        Home();
      } else if (btnRPD.isClicked(sp)) {
        currentPage = '4';  // Go to Run Program
        getCalculations();
        tft.fillScreen(ILI9341_BLACK);
        program();
      }
    }
  }  // End Page 6

  delay(0);
}
//===========================================END LOOP=============================================
// Home Screen CurrentPage=0
void Home() {
  tft.fillScreen(ILI9341_BLACK);
  tft.setCursor(50, 0);
  tft.setTextColor(0x07FF);
  tft.setTextSize(4);
  tft.print("MAIN MENU");
  tft.setTextColor(0x07FF);
  tft.setTextSize(3);
  tft.setCursor(0, 40);
  tft.print("1.");
  tft.setCursor(0, 80);
  tft.print("2.");
  tft.setCursor(0, 120);
  tft.print("3.");
  tft.setCursor(0, 160);
  tft.print("4.");
  tft.setCursor(0, 200);
  tft.print("5.");
  btnMV.initButtonG(50, 40, 200, 25, "Discharge Rate");
  btnMI.initButtonG(50, 80, 200, 25, "Voltage Cutoff");
  btnCT.initButtonG(50, 120, 200, 25, "Calibrate Screen");
  btnRP.initButtonG(50, 160, 200, 25, "Run Discharge");
  btnIR.initButtonG(50, 200, 200, 25, "IR Reading");
}
// Discharge Current Selection CurrentPage=1
void discharge() {
  btnIM.initButtonR(80, 75, 80, 60, "-");
  btnIP.initButtonG(160, 75, 80, 60, "+");
  btnMM.initButtonB(90, 200, 140, 25, " Main Menu");
  tft.setCursor(50, 0);
  tft.setTextSize(4);
  tft.setTextColor(ILI9341_YELLOW);
  tft.print("DISCHARGE");
  tft.setCursor(70, 40);
  tft.print("CURRENT");
  tft.setCursor(100, 150);
  tft.print(IV, 0);
  tft.setCursor(190, 150);
  tft.print("A");
}  // End discharge

// Cutoff Voltage Selection CurrentPage=2
void cutoff() {

  btnIM.initButtonR(80, 75, 80, 60, "-");
  btnIP.initButtonG(160, 75, 80, 60, "+");
  btnMM.initButtonB(90, 200, 140, 25, " Main Menu");
  tft.setCursor(80, 0);
  tft.setTextSize(4);
  tft.setTextColor(ILI9341_YELLOW);
  tft.print("VOLTAGE");
  tft.setCursor(95, 40);
  tft.print("CUTOFF");
}  // End Cutoff

// Run Program CurrentPage=4
void program() {
  btnPN.initButtonG(0, 15, 140, 25, "    RUN");
  btnMN.initButtonB(90, 200, 140, 25, " Main Menu");
  btnRN.initButtonR(160, 15, 140, 25, "   STOP   ");
  btnDD.initButtonY(90, 150, 140, 25, "   DATA   ");
}  // End Program

// IR Reading CurrentPage=5
void irReading() {
  btnRC.initButtonG(90, 15, 140, 25, "  Check IR  ");
  btnMM.initButtonB(90, 200, 140, 25, " Main Menu");
}  // End IR Reading

void dischargeData() {
  tft.setTextSize(1);
  tft.setTextColor(ILI9341_BLUE);
  tft.setCursor(0, 45);
  tft.print("000:");
  tft.setCursor(55, 45);
  tft.print("015:");

  btnRPD.initButtonG(90, 15, 140, 25, " Discharge");
  btnMM.initButtonB(90, 200, 140, 25, " Main Menu");
}  // End dischargeData

void calibrateTouchScreen() {
  TS_Point p;
  int16_t x1, y1, x2, y2;

  tft.fillScreen(ILI9341_BLACK);
  // wait for no touch
  while (ts.touched())
    ;
  tft.drawFastHLine(10, 20, 20, ILI9341_RED);
  tft.drawFastVLine(20, 10, 20, ILI9341_RED);
  while (!ts.touched())
    ;
  delay(50);
  p = ts.getPoint();
  x1 = p.x;
  y1 = p.y;
  tft.drawFastHLine(10, 20, 20, ILI9341_BLACK);
  tft.drawFastVLine(20, 10, 20, ILI9341_BLACK);
  delay(500);
  while (ts.touched())
    ;
  tft.drawFastHLine(tft.width() - 30, tft.height() - 20, 20, ILI9341_RED);
  tft.drawFastVLine(tft.width() - 20, tft.height() - 30, 20, ILI9341_RED);
  while (!ts.touched())
    ;
  delay(50);
  p = ts.getPoint();
  x2 = p.x;
  y2 = p.y;
  tft.drawFastHLine(tft.width() - 30, tft.height() - 20, 20, ILI9341_BLACK);
  tft.drawFastVLine(tft.width() - 20, tft.height() - 30, 20, ILI9341_BLACK);

  int16_t xDist = tft.width() - 40;
  int16_t yDist = tft.height() - 40;

  // translate in form pos = m x val + c
  // x
  xCalM = (float)xDist / (float)(x2 - x1);
  xCalC = 20.0 - ((float)x1 * xCalM);
  // y
  yCalM = (float)yDist / (float)(y2 - y1);
  yCalC = 20.0 - ((float)y1 * yCalM);

  currentPage = '0';
  Home();
  /* // Serial print the actual coordinates from the touch calibrate, enter into the global variables, for first run of the screen
Serial.print("x1 = ");Serial.print(x1);
Serial.print(", y1 = ");Serial.print(y1);
Serial.print("x2 = ");Serial.print(x2);
Serial.print(", y2 = ");Serial.println(y2);
Serial.print("xCalM = ");Serial.print(xCalM);
Serial.print(", xCalC = ");Serial.print(xCalC);
Serial.print("yCalM = ");Serial.print(yCalM);
Serial.print(", yCalC = ");Serial.println(yCalC);
*/
}  // END Calibrate

//  Current Average
void getCurrentAverage() {
  int ii;
  double rawIRead;
  for (int ii = 0; ii < IN; ii++) {
    //analogRead(Isens);
    rawIRead += analogRead(Isens);
  }
  iavg = rawIRead / IN;
  Icorrected = (iavg - IOFF);
}  // end getCurrent

//   Full voltage average (2s voltage if a 2s battery or 1s voltage for a 1s battery)
void getFVoltageAverage() {
  int jj;
  float rawVFRead;
  for (int jj = 0; jj < VFN; jj++) {
    //analogRead(VFsens);
    rawVFRead += analogRead(VFsens);
  }
  vfavg = rawVFRead / VFN;
}  // end getFVoltage

//  Partial Voltage average (only applies for 2s, this is cell 2 voltage)
void getPVoltageAverage() {
  int kk;
  float rawVPRead;
  for (int kk = 0; kk < VPN; kk++) {
    // analogRead(VPsens);
    rawVPRead += analogRead(VPsens) + 1;
  }
  vpavg = rawVPRead / VPN;
}  //  end Partial Voltage

// Runs the main discharge function
void RunDischarge() {
  if (isrunning == true) {
    if (numberCells == '2') {
      if (cell1 > VV / 100 && cell2 > VV / 100) {
        Input = Icurrent;
        myPID.Compute();
        analogWrite(PWM, Output);
      }

      else if (cell1 < VV / 100 || cell2 < VV / 100) {
        zz = 0;
        analogWrite(PWM, zz);
        isrunning = false;
      }
    }

    else if (numberCells == '1') {
      if (cell1 > VV / 100) {
        Input = Icurrent;
        myPID.Compute();
        analogWrite(PWM, Output);
      }

      else if (cell1 < VV / 100) {
        zz = 0;
        analogWrite(PWM, zz);
        isrunning = false;
      }
    }
  }

}  // end runDischarge

void getCalculations() {
  getCurrentAverage();
  voltageI = Icorrected * (VCC / 1023);
  Icurrent = abs((voltageI - QOV) / sens);
  getPVoltageAverage();
  getFVoltageAverage();
  Pvoltage = vpavg * (VCC / 1023);
  Fvoltage = vfavg * (VCC / 1023);

  if (isrunning == true || irRunning == true) {
    voltagePartial = ((Pvoltage * (ValueR1P + ValueR2P)) / ValueR2P) + (Icurrent / 250);
    voltageFull = ((Fvoltage * (ValueR1F + ValueR2F)) / ValueR2F) + (Icurrent / 250);
    if (numberCells == '2') {
      cell1 = voltageFull - voltagePartial;
      cell2 = voltagePartial;
    } else if (numberCells == '1') {
      cell1 = voltageFull;
    }
  } else {
    voltagePartial = ((Pvoltage * (ValueR1P + ValueR2P)) / ValueR2P);
    voltageFull = ((Fvoltage * (ValueR1F + ValueR2F)) / ValueR2F);
    if (numberCells == '2') {
      cell1 = voltageFull - voltagePartial;
      cell2 = voltagePartial;
    } else if (numberCells == '1') {
      cell1 = voltageFull;
    }
  }
  if (voltageFull >= 5) {
    numberCells = '2';
  } else if (voltageFull < 5) {
    numberCells = '1';
  }
  VCC = VCCC / 1000;

  if (isrunning == true) {
    CurrentTime = (millis() - StartTime) / 1000;
    mahTime = (millis() - prevmahTime) / 1000;
  }
  if (CurrentTime > runTime) {
    runTime = CurrentTime;
  } else if (isrunning == false) {
    CurrentTime = 0;
  }
  if (mahTime - prevmahTime >= 1) {
    prevmahTime = mahTime;
    mAH += (Icurrent / 3.6);
  }
  if (mAH > rTmAH) {
    rTmAH = mAH;
  }
}  // end Calculations

// calibrates the VCC using the bandgap ref.  This works and doesn't work.  Probably be better to add an external vref to the design
void getAccurateVoltage() {
  int vv;
  float rawgetVoltage = 0;
  for (vv = 0; vv < 1000; vv++) {
    getVoltage();
    rawgetVoltage += getVoltage();
  }
  VCCC = rawgetVoltage / 1000;
}
// Read the voltage of the battery the Arduino is currently running on (in millivolts)
float getVoltage() {
  const long InternalReferenceVoltage = 1079;  // Adjust this value to your boards specific internal BG voltage x1000
  ADMUX = (0 << REFS1) | (1 << REFS0) | (0 << ADLAR) | (1 << MUX3) | (1 << MUX2) | (1 << MUX1) | (0 << MUX0);
  ADCSRA |= _BV(ADSC);  // Start a conversion
  while (((ADCSRA & (1 << ADSC)) != 0))
    ;                                                               // Wait for it to complete
  float results = (((InternalReferenceVoltage * 1024) / ADC) + 5);  // Scale the value; calculates for straight line value
  return results;
}  // end VCC calibration

//Internal Resistance Measurement
void getIR() {
  if (isrunning == false) {
    irRunning = true;
    for (int chan = 0; chan < (numChan - 1); chan++) {
      tft.fillRect(0, 120, 130, 40, ILI9341_BLACK);
      getCalculations();
      SerialData();
      Channels[chan].startVoltageF = voltageFull - (Icurrent / 250);     // record unloaded voltage of battery
      Channels[chan].startVoltageP = voltagePartial - (Icurrent / 250);  // record unloaded voltage of battery
      zz = 75;                                                           // Will be appx 20A with 2s
      analogWrite(PWM, zz);                                              //Turn Mosfets on
      delay(250);                                                        //delay to stabalize - may need to fine tune this delay, but the shorter the better
      getCalculations();
      SerialData();
      Channels[chan].endVoltageF = voltageFull;                                                 // record voltage of battery under load
      Channels[chan].endVoltageP = voltagePartial;                                              // record voltage of battery under load
      zz = 0;                                                                                   //
      analogWrite(PWM, zz);                                                                     //Turn off the mosfets
      Channels[chan].voltageDropF = Channels[chan].startVoltageF - Channels[chan].endVoltageF;  // Voltage drop from the load
      Channels[chan].voltageDropP = Channels[chan].startVoltageP - Channels[chan].endVoltageP;  // Voltage drop from the load
      Channels[chan].internalResistanceF = (Channels[chan].voltageDropF / Icurrent) * 1000;     //Ohms Law V=IR, R=V/I, Readings in mΩ
      Channels[chan].internalResistanceP = (Channels[chan].voltageDropP / Icurrent) * 1000;     //Ohms Law V=IR, R=V/I, Readings in mΩ
      delay(500);                                                                               // Allow for stablization between readings - may need to fine tune this delay, but start on the high side
    }
    for (int chan = 0; chan < (numChan - 1); chan++) {
      internalResistanceAVGF = +Channels[chan].internalResistanceF;  // run the readings numChan times and average the IR
      internalResistanceAVGP = +Channels[chan].internalResistanceP;  // run the readings numChan times and average the IR
    }
  }  //End if
  irRunning = false;
}  //end getIR

void getVTime() {
  if(isrunning==true){
  getCalculations();
  for (int vt = 0; vt < 39; vt++)
    intervalTime = millis() - previntervalTime;
  if (intervalTime >= 15000) {
    previntervalTime = millis();
    vTime[vt] = voltageFull;
    Serial.println(vTime[vt]);
  }
  }
}

void calibrateQOV() {
  analogRead(Isens);
  QOV = (analogRead(Isens) * VCC) / 1023;
}

void SerialData() {
  Serial.println("----------------------------------------");
  Serial.println();
  Serial.print(VCC);
  Serial.print("V VCC ");
  Serial.print(QOV);
  Serial.print(" QOV ");
  Serial.println();
  Serial.print(analogRead(Isens));
  Serial.print(" RAW Read ");
  Serial.print(Icorrected);
  Serial.print(" Corrected ");
  Serial.print(voltageI);
  Serial.print("V ");
  Serial.print(Icurrent);
  Serial.print(" Amps ");
  Serial.print(iavg);
  Serial.print(" AVG ");
  Serial.print(Output);
  Serial.println();
  Serial.print(voltageFull);
  Serial.print(" V Full  ");
  Serial.print(vfavg);
  Serial.print("  ACT  ");
  Serial.print(analogRead(VFsens));
  Serial.print(" ");
  Serial.println();
  Serial.print(voltagePartial);
  Serial.print("   ");
  Serial.print(" V Partial   ");
  Serial.print(vpavg);
  Serial.print("   ACT  ");
  Serial.print(analogRead(VPsens));
  Serial.println();
  Serial.print("Cell 1 ");
  Serial.print(cell1, 3);
  Serial.print("V   Cell 2 ");
  Serial.print(cell2, 3);
  Serial.print("V");
  Serial.println();
}

For displaying I tried the following.

tft.setTextSize(1);
    tft.setTextColor(ILI9341_ORANGE);
     for (int vt = 0; vt < 10; vt++)
     tft.setCursor(0,vt*10);
     tft.print(vTime[vt]);
    

Was hoping this would print vTime[0] - vTime[9] at coordinates (0,0) (0,10) (0,20). But it just prints the last vTime at 0,90.

Well, pretty much scrap all that. Not working at all...

That is all the time I have until next week.

Thanks

Pity. As counter intuitive as it may sound to you, if speed is an issue then clean up the code. That will help you work faster and help you get more and better help out of the forum.

Or you keep doing it the slow way and run out of time. Doesn't bother me at all.

Speed isn't the issue, time is. I have other commitments. Y'all want me to clean up my code. That will take me weeks to do. I understand everyone on here can do it in minutes, but I don't know how to do that. Even with users giving suggestions. It's Greek to me! I've told this forum before, I just mash stuff together and hope it works.

And if things went faster time would be less of an issue.

Ok, I see you think that it is a waste of your time. I am not going to convince you otherwise. You just keep doing it the hard slow way and wonder why you keep running out of time.

You know what will take even longer? Not doing it. But I guess you'll just have to learn that the hard way.

Only responses like yours are a waste of my time.
There have been a few posters in this thread that have tried to help with my question. To those posters I say thank you.

1 Like

If you properly formatted that code, it would look like

tft.setTextSize(1);
tft.setTextColor(ILI9341_ORANGE);
for (int vt = 0; vt < 10; vt++)
  tft.setCursor(0,vt*10);
tft.print(vTime[vt]);

And then you would see that only the .setCursor() call is associated with the for() loop since you did not use {} around all the code you wanted inside the for() loop.

2 Likes

not sure i'm following

something like this


struct Var {
    const byte          Pin;
    const unsigned long MsecPeriod;
    const char         *Desc;

    float               val;
    unsigned long       msec;
};

Var vars [] = {
    { A0, 500, "volt1" },
    { A1, 250, "volt2" },
    { A2, 650, "cur1" },
};
const int Nvar = sizeof(vars)/sizeof(Var);

char s [80];
char t [10];

// -----------------------------------------------------------------------------
void
loop (void)
{
    unsigned long msec = millis ();

    Var *p = vars;
    for (int n = 0; n < Nvar; n++, p++)  {
        if (msec < p->msec)  
            continue;
        
        p->msec += p->MsecPeriod;
        p->val = analogRead (p->Pin);

        dtostrf (p->val, 6, 2, t);
        sprintf (s, "  %6s %s", t, p->Desc);
        Serial.println (s);
    }
}

void
setup (void)
{
    Serial.begin (9600);
    Serial.println (Nvar);
}

Capitalize Constants

See. You would have seen the error. It would have cost you all the time it takes to press control-T

Look man I'm not trying to bust your balls, it will really help you get there faster and stop wasting the little time you seem to have.

Missed the curlies. Dang it.
When I get a chance to get back to it, I'll give that a try with the curly braces. I ripped all the code I put in for this out of my sketch. I think I posted most of it, so it shouldn't be difficult to put back in.

You've posted the "Capitalize Constants" before, is this a necessity or more like a "grammar" for coding thing?

Also, what is the above code doing. Can you explain what is happening. It looks to me like this is doing more than what I need.

This device discharges a battery. I only care about the fullVoltage variable, and I would like that output every 15 seconds during the discharge. And actually, I would like the initial time 0 fullVoltage as well, figured I would get there after getting the 15 seconds intervals. Since all these need to be printed to a tft display, I can't just use the one fullVoltage variable. So I need an array of the possible number of fullVoltage variables I could need. fullVoltage is an average of 1000 times the analogRead of one of my pins, but it is the calculated value through the voltage divider, offsets, etcetera.
This is the value that the end user wants to see... I choose 40 as the number for the array since I don't think anyone will be discharging a battery for longer than 10 minutes, but maybe they will, and I might need a higher number for the array. Most users will have a fully discharged battery in 6-7 minutes, since they will be discharging the batteries at 30+ amps.

I found the ctrl-t feature a few days ago. I do try to use it when putting code into IDE. Sometimes I forget, but I use it a lot since I found the feature.

You said it was a waste of your time when I suggested it.

Using ctrl-t is a waste of my time? We're not speaking/typing the same language. Hitting ctrl-t kind of does its own thing, and is pretty instant. I may be not using the feature correctly then. But I have noticed, that is doesn't always group stuff together right. Sometimes it requires you to move something and press it again.

Wasting my time is referring to re writing my code to "summarize" a few functions that currently work, just take up space.

So there are a couple of things to this. The first, when summarizing it takes away the uniqueness of the individual elements. When working with my code, I find the uniqueness helpful, especially if I need to edit a specific thing. So I can't write the code to be summarized in the beginning. Which then means I have to clean it up when I am done with it. But at that point it already works.

Someone on here, cleaned up one of my projects. And it is awesome, and it looks pretty, and I can't duplicate it. Well, I can duplicate parts of it... For example, the IR struct in this code was based on what that person did for my other project, and it works great. I am quite pleased with how well the IR part of this project has turned out. I've compared it to other units that test IR and it is extremely close and quite consistent. And the help given to me on that project did help me make the IR part of this project.

It boils down to if I only have a couple of hours to work on my project, I would rather it be working on advancing my project and not cleaning up areas that already work. The goal will be to go back through and clean it up, but mainly because that could help me in future projects, not with the current project.

i thought you were tracking 40 different inputs

don't understand. how many fullVoltage variables as opposed to values do you need?

battery voltage, even when being discharged should be pretty stable.

but it you really need to average, why not leaky integration (run time averaging)

avg = samp / N + avg * (N-1)/N
avg  += (samp - avg) / N

is "the value" or do you mean each value captured every 15 sec?

only Capitalizing Constants makes the code easier to read because knowing whether the symbol is a variable or not is helpful

1 Like