NaN displayed, sometimes

I am having issues with a few averages that are displaying NaN in Serial and my tft display. In the serial monitor I have the analog reads to 2 of the averages and they show up, but the average doesn't. Now here is the weird part. If I compile the code using a programmer and upload it, the values will show up when it is done. But if I power off my project and power it back on they go back to NaN. Also, if I power off my device, and plug in the battery it measures, then power it on, it will display values. But ultimately, it needs to display values when I plug the battery in. If it show NaN, and I plug a battery in, I get NaN. Also, if I have my board plugged into the programmer and hit reset, everything works fine. It is buggy somehow, just not sure how.

The 3 functions are below, and I have tried adding them to a lot of different spots. I also built another board to see if the issue persists on it, and it does.

getCurrentAverage()
getFVoltageAverage()
getPVoltageAverage()

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

    Other items still needed
    Data Return page
    Voltage values every 15 seconds - 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"
 
// 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;
 

 
// 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;
      }
    }
};

unsigned const int numChan = 5;
unsigned int chan;
struct ChannelData {
  float startVoltage;
  float endVoltage;
  float voltageDrop;
  float internalResistance;
};
ChannelData Channels[numChan]; 

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


double IV = 10;
float VV = 700.00;
unsigned long StartTime;
unsigned long CurrentTime;

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


// Current Variables
float VCC;// 4.967  measure the value(Measure value not needed with the VCC calibration code)
float QOV; // Calibration happens in setup
float sens=0.04; //sensitivity of the current sensor
float iavg; // analogRead(Isens)/IN
float Icurrent; // Current Reading in Amps
float Icorrected; //iavg-IOFF
float voltageI; // iavg translated to voltage
float IOFF=0; // Offset to the raw read to zero current
int IN=75; // Sample number to average current
int mAH;
int rTmAH;
unsigned long runTime;

// 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=100; // Sample number for average of analogRead(VFsens) Full voltage
int VPN=100;// Sample number for average of analogRead(VPsens) Partial voltage
float vfavg; // Average of the analogRead(VFsens)/VFN - Full Voltage
float vpavg;
float Fvoltage=0;
float Pvoltage=0;
float voltageFull=0;
float voltagePartial=0;
float cell1=0;
float cell2=0;
//float avgLFV; // Leaky Average Full Voltage
//float LFvoltage;//Leaky Full Voltage
//float voltageLFull;// Leaky after divider
boolean isrunning=false;
boolean irRunning=false;
int zz=0;// variable used for analogWrite(PWM,zz)
float internalResistanceAVG=0;


//===================================================================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 to add
//btnMV.initButtonP(0,50,180,25,"Discharge"); (caused issues initating buttons in the setup, so moved to the functions of the page they belong to)
//btnMI.initButtonP(0,100,180,25,"Voltage");
//btnVP.initButtonP(175,125,20,25,"+");
//btnVM.initButtonR(175,200,80,25,"Main Menu");
getAccurateVoltage();
getCurrentAverage();
getFVoltageAverage();
getPVoltageAverage();
getCalculations();
calibrateQOV();
//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();
}

//unsigned long lastFrame = millis();

//==================================================================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();
getAccurateVoltage();
getFVoltageAverage();
getPVoltageAverage();
getCurrentAverage();
getCalculations();
SerialData();

// 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
     tft.fillScreen(ILI9341_BLACK);
     program();
   }

   else if(btnIR.isClicked(sp)){
     currentPage='5'; // Go to irReading
     tft.fillScreen(ILI9341_BLACK);
     irReading();
   }
   //add menu item for getIR page ('5') - will have to adjust other buttons to make room
  }
}


// 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)){
      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(50);
      }
      else if (btnIM.isClicked(sp)){
       VV--;
       tft.fillRect(100,150,100,50,ILI9341_BLACK);
       delay(50);
     }
      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'){
    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);
    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(0,120);
    tft.print("Cell 1  ");
    tft.setCursor(45,120);
    tft.print(cell1);
    tft.setCursor(80,120);
    tft.print("V");
    tft.setCursor(0,130);
    tft.print("Cell 2  ");
    tft.setCursor(45,130);
    tft.print(cell2);
    tft.setCursor(80,130);
    tft.print("V");
    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);
    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();
     isrunning=true;
        
    }
    else if (btnDD.isClicked(sp)){
      tft.fillScreen(ILI9341_BLACK);
      currentPage='6';
      dischargeData();
    }
    }   
}// End Page 4

// IR Reading
if(currentPage=='5'){
  tft.setCursor(0,120);
  tft.setTextSize(4);
  tft.setTextColor(ILI9341_WHITE,ILI9341_BLACK);
  tft.print(internalResistanceAVG);
  if (irRunning==true) {
      btnRC.initButtonR(90,15,140,25,"Reading IR");
      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'){
  //dischargeData();
    if (ts.touched()) {
      TS_Point p = ts.getPoint();
      sp = getScreenCoords(p.x, p.y);
        if (btnMM.isClicked(sp)){
         currentPage='0';
         Home();
        }
    }
}// 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");
    // add button for getIR function page, adjust button heights to fit, or make 2 colums and adjust width...
}
// 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(){
    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; float 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

/*
void getLeakyFVoltage(){
  float sampF=analogRead(VFsens);
  avgLFV += K*(sampF-avgLFV);
}
*/

/*
void getLeakyPVoltage(){
  float sampP=analogRead(VPsens);
  avgLPV =+ K*(sampP-avgLPV);
}
*/

/*
void getLeakyCurrent(){
  float sampC=analogRead(Isens);
  avgC += K*(sampC-avgLC);
}
*/

//  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);
  }
    vpavg=rawVPRead/VPN;
}//  end Partial Voltage

// Runs the main discharge function
void RunDischarge() {
  
  if (isrunning==true) {
    if (voltageFull>VV/100)
     {
        Input = Icurrent;
        myPID.Compute();
        analogWrite(PWM, Output);
      }
    
   else if (voltageFull<VV/100)
    {
      zz=0;
      analogWrite(PWM, zz);
     isrunning=false;

    }
   
  }

} // end runDischarge





void getCalculations() {
  //getLeakyFVoltage();
  //LFvoltage=avgLFV*(VCC/1023);
  //voltageLFull=((Fvoltage*(ValueR1F+ValueR2F))/ValueR2F);
  getCurrentAverage();
  voltageI=Icorrected*(VCC/1023);
  Icurrent=abs((voltageI-QOV)/sens);
  getFVoltageAverage();
  Fvoltage=vfavg*(VCC/1023);
  voltageFull=((Fvoltage*(ValueR1F+ValueR2F))/ValueR2F)-0.01;
  getPVoltageAverage();
  Pvoltage=vpavg*(VCC/1023);
  voltagePartial=((Pvoltage*(ValueR1P+ValueR2P))/ValueR2P)+0.01;
  cell1=voltageFull-voltagePartial;
  cell2=voltagePartial;
  VCC=(getAccurateVoltage())/1000;
  //QOV=VCC/2;// in theory... QOV actually equals voltageI with no current...
  if (isrunning==true) {
  CurrentTime=(millis()-StartTime)/1000;
  }
  if (CurrentTime>runTime) {
    runTime=CurrentTime;
  }
  else if (isrunning==false) {
    CurrentTime=0;// Need to change to keep the previous runtime around, but have a reset data button to zero time
  }
mAH=((Icurrent/3.6)*CurrentTime);
if (mAH>rTmAH) {
  rTmAH=mAH;
}
}// end Calculations

// calibrates the VCC using the bandgap ref - Something is amiss though, resoltion is 30mV instead of 3mV - need to work on this
float getAccurateVoltage() {
  int vv; float rawgetVoltage;
  for (vv=0; vv<10; vv++)
  {
    getVoltage();
    rawgetVoltage+=getVoltage();
  }
  return rawgetVoltage/10;
}
// Read the voltage of the battery the Arduino is currently running on (in millivolts)
float getVoltage() {
    const long InternalReferenceVoltage = 1085; // 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 (This is untested and need menu and page written)
void getIR() {
 if (isrunning==false) {
   irRunning=true;
   for (int chan=0; chan<(numChan-1); chan++)
   {
    getCalculations();
    Channels[chan].startVoltage=voltageFull; // record unloaded voltage of battery
    zz=70; // Will be appx 20A with 2s, may split this into if statements based on current battery voltage
    analogWrite(PWM, zz);//Turn Mosfets on
    delay(10);//delay to stabalize - may need to fine tune this delay, but the shorter the better
    getCalculations();
    Channels[chan].endVoltage=voltageFull; // record voltage of battery under load
    zz=0;//
    analogWrite(PWM, zz);//Turn off the mosfets
    Channels[chan].voltageDrop=Channels[chan].startVoltage-Channels[chan].endVoltage;// Voltage drop from the load
    Channels[chan].internalResistance=(Channels[chan].voltageDrop/Icurrent)*1000;//Ohms Law V=IR, R=V/I, Readings in mΩ
    delay(2000);// 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++) {
   internalResistanceAVG=+Channels[chan].internalResistance;// run the readings numChan times and average the IR
  }
 }//End if
 irRunning=false;
}//end getIR

void calibrateQOV() {
  getCalculations();
  QOV=(iavg*VCC)/1023;
}


void SerialData() {
  getCalculations();
  Serial.println("----------------------------------------");
  Serial.println();
  Serial.print(VCC);
  Serial.print("V VCC ");
  Serial.println();
  Serial.print(Icorrected    );
  Serial.println();
  Serial.print(Icurrent);
  Serial.print(" Amps ");
  Serial.println();
  Serial.print(voltageFull);
  Serial.print(" V Full  ");
  Serial.print(vfavg);
  Serial.print("  ACT  ");
  Serial.print(analogRead(VFsens));
  //Serial.print(" Leaky AVG ");
  //Serial.print(avgLFV);
  Serial.print(" ");
  //Serial.print(voltageLFull);
  Serial.println();
  Serial.print(voltagePartial);
  Serial.print("   ");
  Serial.print(" V Partial   ");
  Serial.print(vpavg);
  Serial.print("   ACT  ");
  Serial.print(analogRead(VPsens));
  Serial.println();
  //Serial.println(internalResistanceAVG);
  Serial.println();
 }

Hello trilerian

Take a view here:

And check the FP operations in your sketch after reading.

Have a nice day and enjoy coding in C++.

So the issue lays somewhere in the getCurrentAverage or calculations with it. Any average above 1 returns NaN for all the sensors. But if I set the average to be 1, all values come through. Kind of weird, I am going to look at the calculations again, but there is no dividing by 0, adding or subtracting infinity, square roots are other craziness.

Add some print lines to show the value of variables and see if they are what you expect.
Very big numbers or very small numbers are in your code , manipulating these might easily cause strange results !
Break the code down and test individual sections

Debugging using the serial is a little difficult, because it will work part of the time. So I may think I got it, only to unplug everything then plug it back in and it doesn't work.

So an update. The problem exists in the VCC auto calibration I am doing.
I found this online and modified it slightly, I had to make the return a float and other variables a float.

But if I hard code VCC and QOV the outputs are good, even with a lot of averaging.

In the below, if I average only 1 time, I get a VCC, but the QOV still doesn't calibrate with my other function.

float getAccurateVoltage() {
  int vv; float rawgetVoltage;
  for (vv=0; vv<10; vv++)
  {
    getVoltage();
    rawgetVoltage+=getVoltage();
  }
  return rawgetVoltage/10;
}
// Read the voltage of the battery the Arduino is currently running on (in millivolts)
float getVoltage() {
    const long InternalReferenceVoltage = 1085; // 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

Try this completely untested snippet:

int vv; float rawgetVoltage=0;

Thanks for the help, but it didn't work. Although I am leaving it in the code.

I ended up fixing the issue. There were 2 things that weren't working together.

  1. Auto calibrate the VCC. I changed the function from a return to a void with a global and that started working...
  2. Calibrate the QOV. This was on me, lol. I was trying to use a function to calibrate a value got in the function. So I went straight to the source and used the analogRead instead of the function and now it works.

Out of curiosity, do nested functions not work? I would think that if you run a function, all nested functions should run and you shouldn't need to run those functions independently. yet I seem to have to.

It is good to initialize your variables. From this code:

void setup() {
  Serial.begin(115200);
}

void loop() {
  Serial.println(getAccurateVoltage());
  delay(100);
}

float getAccurateVoltage() {
  int vv; float rawgetVoltage;
  for (vv = 0; vv < 10; vv++)
  {
    rawgetVoltage += 1 ;
  }
  return rawgetVoltage / 10.0;
}

would you expect:

1.00
2.00
3.00
4.00
5.00
6.00
7.00
8.00
9.00
10.00
11.00
12.00
13.00
14.00
15.00
16.00
17.00
18.00
19.00
20.00
21.00
22.00
...

If rawgetVoltage was a static, this would be expected, but declared as dynamic without initialization you might get lucky or unlucky.

You may want to try using isnan(xxx) on whatever is displaying NaN and conditionally printing out its precursors.

if(isnan(xxx)){
  Serial.println("NaN detected by isnan(xxx)");
  Serial.println(xxx);
  Serial.println(numerator);
  Serial.println(denominator);
  delay(1000);
}
1 Like

Well that is interesting. Thanks

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