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