Arduino accurate battery level reading problem

Hello, i am new to coding and arduino
I am making nitrox analyzer for scuba diving and have problem with battery voltage readings, i have code that read battery correctly and have code that work for nitrox correctly, but when i combine them i get false readings

This is code that gives me 0.9v battery voltage

#include <Arduino.h>

#include <ADS1115.h>
#include <ClickEncoder.h>
#include <EEPROM.h>
#include <RollingAverage.h>
#include <U8g2lib.h>
#include <TimerOne.h>
#include <Wire.h>

#include "config.h"
#include "nitrox.h"
#include "state.h"

// LCD
// U8G2_SH1106_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0); // 128 bytes framebuffer
U8G2_SH1106_128X64_NONAME_2_HW_I2C u8g2(U8G2_R0); // 256 bytes framebuffer

// ADC
ADS1115 ads;

// ROLLING AVERAGE
int16_t readingsBuffer[SAMPLE_SIZE];
RollingAverage readings(SAMPLE_SIZE, readingsBuffer);

// ENCODER
ClickEncoder encoder(ENC_PIN_A, ENC_PIN_B, ENC_PIN_SW, ENC_STEPS);

int16_t encPosPrev, encPos;
int8_t encDelta;
uint8_t buttonState;

void timerIsr()
{
	encoder.service();
}

// STATE MACHINE
state_t state;
state_dialog_t stateCalibMenu;
state_ppo2_t stateModDisplay;
uint32_t displayTimer = 0;
uint32_t analyzeTimer = 0;
uint32_t calibrateTimer = 0;
uint32_t batteryTimer = 0;

// OTHER
int16_t batteryVoltage = 0;
int16_t calibrationFactor = 0; // unit is [1e-1 µV / %], value should be ~5000
int16_t oxygenConcentration = 0;
int32_t sensorMicroVolts;
char displayFooterBuffer[24];
bool batteryWarning = false;


// Main render function
void renderDisplay()
{
	u8g2.firstPage();
	do {
		if (batteryWarning) {
			u8g2.setFont(u8g2_font_6x13_tr);
			u8g2.drawBox(118,0,10,12);
			u8g2.setFontMode(1); // transparent background
			u8g2.setDrawColor(2); // XOR
			u8g2.setCursor(120,10);
			u8g2.print(F("B"));
			// reset drawing modes
			u8g2.setFontMode(0);
			u8g2.setDrawColor(1);
		}
		switch(state) {
		case STATE_START_SCREEN:
			// TODO: Add Graphics ?
			u8g2.setFont(u8g2_font_6x13_tr);
			u8g2.setCursor(0,10);
			u8g2.print(F("Nitrox Analyzer"));
			u8g2.setCursor(0,20);
			u8g2.print(F("Starting..."));
			u8g2.setCursor(0,63);
			u8g2.print(F("Battery: "));
			u8g2.print(batteryVoltage/1000);
			u8g2.print(".");
			u8g2.print((batteryVoltage % 1000) / 10);
			u8g2.print("V");
			break;
		case STATE_ANALYZE:
		case STATE_HOLD:
			u8g2.setFont(u8g2_font_6x13_tr);
			u8g2.setCursor(0,10);
			if (state == STATE_HOLD) {
				u8g2.print(F(">>> HOLD <<<"));
			}
			else {
				u8g2.print(F("Analyzing"));	
			}
			//u8g2.setFont(u8g2_font_inb30_mn);
			u8g2.setFont(u8g2_font_logisoso30_tn);
			u8g2.setCursor(20,48);
			// print O2 as a decimal percentage
			if ((oxygenConcentration / 100) < 10) {
				u8g2.print("0");
			}			
			u8g2.print(oxygenConcentration / 100);
			u8g2.print(".");
			if ((oxygenConcentration % 100) < 10) {
				u8g2.print("0");
			}
			u8g2.println(oxygenConcentration % 100);
			// print MOD
			u8g2.setFont(u8g2_font_6x13_tr);
			u8g2.drawStr(0,63,displayFooterBuffer);
			break;
		case STATE_CALIBRATE_MENU:
			u8g2.setFont(u8g2_font_6x13_tr);
			u8g2.setCursor(0,10);
			u8g2.print(F("Calibrate ?"));
			u8g2.setFont(u8g2_font_logisoso30_tn);
			u8g2.drawStr(20,48,"20.95");
			u8g2.setFont(u8g2_font_6x13_tr);
			if (stateCalibMenu == YES) {
				u8g2.drawBox(0,53,64,10);
			}
			else {
				u8g2.drawBox(63,53,64,10);
			}
			u8g2.setFontMode(1); // transparent background
			u8g2.setDrawColor(2); // XOR
			u8g2.setCursor(24,63);
			u8g2.print(F("YES"));
			u8g2.setCursor(90,63);
			u8g2.print(F("NO"));
			// reset drawing modes
			u8g2.setFontMode(0);
			u8g2.setDrawColor(1);
			break;
		case STATE_CALIBRATE:
			u8g2.setFont(u8g2_font_6x13_tr);
			u8g2.setCursor(30,10);
			u8g2.print(F("Calibration"));
			u8g2.setCursor(30,20);
			u8g2.print(F("in progress"));
			u8g2.setCursor(21,40);
			u8g2.print(F("Please wait..."));
			break;
		default: 
			;
		}
	} while ( u8g2.nextPage() );
}


void setup()
{
#ifdef DEBUG
	Serial.begin(19200);
	Serial.println(F("*\n* Nitrox Analyser - DEBUG\n*"));
#endif
	Wire.begin();

	u8g2.begin();
	u8g2.setFont(u8g2_font_6x13_tr);
	
	ads.begin();
	ads.setGain(GAIN_SIXTEEN); // +/- 256mV FSR = 7.812µV resolution
	ads.setDataRate(DR_16SPS); // 16 sps
	ads.setMux(MUX_DIFF_0_1);  // sensor is connected between AIN0 (P) and AIN1 (N)
	ads.writeConfig();
#ifdef DEBUG
	Serial.print(F("ADS config: "));
	Serial.println(ads.readConfig());
#endif
	ads.startContinuousConversion();

	// Rolling average
	readings.begin();
	
	// Input processing and debouncing
	Timer1.initialize(1000); // 1ms
	Timer1.attachInterrupt(timerIsr);

	// initialize variables
	encPosPrev = encPos;
	state = STATE_START_SCREEN;
	stateCalibMenu = NO;
	stateModDisplay = PPO2_1_6;
	displayTimer = millis();			// initialize for splash screen
	batteryTimer = -BATTERY_INTERVAL; 	// force initial reading
#ifdef EEPROM_ENABLE
	// Load last calibration factor
	EEPROM.get(EEPROM_CALIBRATION_ADDRESS, calibrationFactor);
#ifdef DEBUG
	Serial.print(F("EEPROM load: ")); Serial.println(calibrationFactor);
#endif
#endif
}


void loop()
{
	static bool updateDisplay = true;

	// Handle inputs
	buttonState = encoder.getButton();
	encPos += encoder.getValue();
	encDelta = encPos - encPosPrev;
	encPosPrev = encPos;
#ifdef DEBUG
	if (buttonState != 0) {
		Serial.print(F("Button: ")); Serial.println(buttonState);
	}
	if (encDelta != 0) {
		Serial.print(F("Encoder: ")); Serial.println(encDelta);
	}
#endif

	// ADC readings
	if (millis() - analyzeTimer >= ANALYZE_INTERVAL) {
		readings.addReading(ads.readLastConversion());
		analyzeTimer = millis();
	}

	// Battery
	if (millis() - batteryTimer >= BATTERY_INTERVAL) {
		batteryVoltage = A0;
		// convert ADC reading to mV
		// ref = 3.3V -> mV = adc * 100 / 31
		// + factor 2 from divider
		batteryVoltage *= (10 * 2);
		batteryVoltage /= 31;
		batteryVoltage *= 10;
		if (batteryVoltage <= BATTERY_THRESHOLD) {
			batteryWarning = true;
		}
		batteryTimer = millis();
	}

	// State machine
	switch (state) {
		case STATE_START_SCREEN:
			if (millis() - displayTimer >= SPLASH_DELAY) {
				state = STATE_ANALYZE;
				updateDisplay = true;
				displayTimer = millis();
#ifdef BUZZER_ENABLE
				tone(BUZZER_PIN,4000,200);
#endif
			}
			break;
		case STATE_ANALYZE:
		case STATE_HOLD:
			// handle inputs
			switch (buttonState) {
			case ClickEncoder::Clicked:
				if (state == STATE_ANALYZE) {
					state = STATE_HOLD;
				}
				else {
					state = STATE_ANALYZE;
				}
#ifdef BUZZER_ENABLE
				tone(BUZZER_PIN,2000,200);
#endif
				break;
			case ClickEncoder::Held:
				state = STATE_CALIBRATE_MENU;
				stateCalibMenu = YES;
				updateDisplay = true;
				break;
#ifdef DEBUG
			case ClickEncoder::DoubleClicked: //6
				Serial.print(F("ADC reading:      ")); Serial.println(readings.getAverage());
				Serial.print(F("Sensor µV:        ")); Serial.println(sensorMicroVolts);
				Serial.print(F("Calib. factor:    ")); Serial.println(calibrationFactor);
				Serial.print(F("O2 concentration: ")); Serial.println(oxygenConcentration);
				Serial.print(F("Battery:          ")); Serial.println(batteryVoltage);
	#ifdef BUZZER_ENABLE
				tone(BUZZER_PIN,4000,500);
	#endif
				break;
#endif
			}
			if (encDelta != 0) {
				if (encDelta > 0) {
					stateModDisplay++;
				}
				else if (encDelta < 0) {
					stateModDisplay--;
				}
			}
			if (millis() - displayTimer >= DISPLAY_REFRESH_RATE) {
				if (state == STATE_ANALYZE) {
					sensorMicroVolts = ((int32_t)readings.getAverage() * 7812L) / 1000L;
					if (sensorMicroVolts <= 0) {
						// TODO: ERROR BAD SENSOR
						// adjust threshold ? ex. 5mV ?
					}
					oxygenConcentration = (int16_t)((sensorMicroVolts * 1000L) / calibrationFactor);
					if (oxygenConcentration < 0) {
						// TODO: ask for calibration
						oxygenConcentration = 0;
					}
					else if (oxygenConcentration > 10200) {
						// TODO: ERROR MODE
					}
				}
				// MOD calculation
				uint16_t pO2_max, mod;
				if (stateModDisplay == MV) {
					sprintf_P(displayFooterBuffer, PSTR("Sensor: %d.%02d mV"), 
						(int16_t)(sensorMicroVolts / 1000L),
						(int8_t)((sensorMicroVolts % 1000L) / 10));
				}
				else {
					switch(stateModDisplay) {
					case PPO2_1_4:
						pO2_max = 1400;
						break;
					case PPO2_1_5:
						pO2_max = 1500;
						break;
					case PPO2_1_6:
						pO2_max = 1600;
						break;
					default:
						pO2_max = 1000; // you should not be here...
					}
					mod = calc_mod(oxygenConcentration, pO2_max);
					sprintf_P(displayFooterBuffer, PSTR("pO2 %d.%d > MOD %dm"),
						(uint8_t)(pO2_max / 1000),
						(uint8_t)((pO2_max % 1000) / 100),
						(uint8_t)(mod / 100) );
				}
				updateDisplay = true;
				displayTimer = millis();
			}
			break;
		case STATE_CALIBRATE_MENU:
			if (encDelta != 0) {
				if (encDelta > 0) {
					stateCalibMenu = NO;
				}
				else if (encDelta < 0) {
					stateCalibMenu = YES;
				}
				updateDisplay = true;
			}
			if (buttonState == ClickEncoder::Clicked) {
				if (stateCalibMenu == YES) {
					state = STATE_CALIBRATE;
					calibrateTimer = millis();
				}
				else {
					state = STATE_ANALYZE;
				}
				updateDisplay = true;
			} 
			break;
		case STATE_CALIBRATE:
			// TODO: handle inputs ?
			if (millis() - calibrateTimer >= CALIBRATION_TIME) {
				// TODO: check calibration sample quality (e.g. max deviation)
				// 7812 is ADS resolution in [nV / LSB] at PGA = 16
				// 2095 is calibration oxygen concentration (20.95% in air)
				int32_t sensorMicroVolts = ((int32_t)readings.getAverage() * 7812L) / 1000L;
				calibrationFactor = (int16_t)((sensorMicroVolts * 1000L) / 2095L);
#ifdef DEBUG
				Serial.println(F("Calibration complete"));
				Serial.print(F("Sensor: ")); Serial.print(sensorMicroVolts); Serial.println(F(" µV"));
				Serial.print(F("Calibration factor:")); Serial.println(calibrationFactor);
#endif
#ifdef EEPROM_ENABLE
				EEPROM.put(EEPROM_CALIBRATION_ADDRESS, calibrationFactor);
	#ifdef DEBUG
				Serial.println(F("Saved to EEPROM"));
	#endif
#endif
				state = STATE_ANALYZE;
				updateDisplay = true;
#ifdef BUZZER_ENABLE
				tone(BUZZER_PIN,3000,500);
#endif
			}
			// render
			break;
		case STATE_ERROR:
#ifdef BUZZER_ENABLE
//			tone(BUZZER_PIN,1000,1000); // would beep continuously - should be activated when entering error mode
#endif
			// TODO
			break;
	}

	if (updateDisplay) {
		renderDisplay();
		updateDisplay = false;
	}

}

and this is code that read battery accuratly

#include <Wire.h>
#include <U8g2lib.h>
#include "Vcc.h"

// Constants for VCC and battery monitoring
const float VccMin = 0.0;           // Minimum expected Vcc level, in Volts.
const float VccMax = 3.303;         // Maximum expected Vcc level, in Volts (use a multimeter to measure).
const float VccCorrection = 0.98544;  // Tweak this to match your Vcc reading with your multimeter.
const float lowBat = 2.9;           // Minimum battery voltage for "dead battery".
const float fullBat = 4.2;          // Fully charged battery voltage.

Vcc vcc(VccCorrection);  // Vcc object with correction factor

int batt_pin = A0;  // Battery is connected to pin A0

// Create U8g2 object for SH1106 OLED 128x64 display (I2C)
U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);  // I2C initialization

void setup() {
  Serial.begin(9600);   // Start serial communication for debugging
  u8g2.begin();         // Initialize OLED display
}

void loop() {
  // Read the VCC voltage by collecting 100 samples
  int j;
  float v = 0;
  for (j = 0; j < 100; j++) {
    v += vcc.Read_Volts();  // Read VCC
    delay(5);
  }

  // Average of 100 VCC voltage samples
  v = v / j;

  // Display VCC on Serial Monitor
  Serial.println();
  Serial.print("VCC: ");
  Serial.println(v, 3);  // Print VCC to 3 decimal places
  
  // Read the battery voltage by collecting 100 samples
  int i;
  float batt_volt = 0;
  for (i = 0; i < 100; i++) {
    // Using VCC as reference for battery voltage
    batt_volt += ((analogRead(batt_pin) * (v / 1023.0)) * 2);
    delay(5);
  }

  // Average of 100 battery voltage samples
  batt_volt = batt_volt / i;

  // Display Battery info on Serial Monitor
  Serial.print("Battery: ");
  Serial.print(batt_volt, 2);  // Print battery voltage to 2 decimal places
  Serial.print("V ");
  // Convert battery voltage to percentage
  Serial.print(((batt_volt - lowBat) / (fullBat - lowBat)) * 100);
  Serial.println("%");

  // Display data on OLED
  renderDisplay(v, batt_volt);

  delay(100);  // Small delay before next reading
}

void renderDisplay(float vcc, float battVolt) {
  // Clear the buffer to prepare the display for new data
  u8g2.clearBuffer();
  
  // Set font for display text
  u8g2.setFont(u8g2_font_ncenB08_tr);  

  // Display VCC voltage
  u8g2.setCursor(0, 20);
  u8g2.print("VCC: ");
  u8g2.print(vcc, 3);  // Display VCC with 3 decimal places

  // Display Battery voltage
  u8g2.setCursor(0, 40);
  u8g2.print("Battery: ");
  u8g2.print(battVolt, 2);  // Display battery voltage with 2 decimal places

  // Display Battery percentage
  float battPercentage = ((battVolt - lowBat) / (fullBat - lowBat)) * 100;
  u8g2.setCursor(0, 60);
  u8g2.print("Battery %: ");
  u8g2.print(battPercentage, 0);  // Display battery percentage with no decimals
  
  // Send the buffer to the display
  u8g2.sendBuffer();
}

Did you make any attempt to find the problem by using serial.Print() to display the intermediate values in the calculations?

I did tried, but wasn't much succssesful, this is my first project and first time programming. The value is not changed, if i power it from usb or battery, i get same readings despite different voltage. But when i use code that works it accuretly shows voltage both on usb and battery

code that doesn't work:

code that works:

See anything different?

#include <Arduino.h>

#include <ADS1115.h>
#include <ClickEncoder.h>
#include <EEPROM.h>
#include <RollingAverage.h>
#include <U8g2lib.h>
#include <TimerOne.h>
#include <Wire.h>

#include "config.h"
#include "nitrox.h"
#include "state.h"
#include "vcc.h"
const float VccMin = 0.0;           // Minimum expected Vcc level, in Volts.
const float VccMax = 3.303;         // Maximum expected Vcc level, in Volts (use a multimeter to measure).
const float VccCorrection = 0.98544;  // Tweak this to match your Vcc reading with your multimeter.
const float lowBat = 2.9;           // Minimum battery voltage for "dead battery".
const float fullBat = 4.2;          // Fully charged battery voltage.

Vcc vcc(VccCorrection);  // Vcc object with correction factor

int batt_pin = A0;  // Battery is connected to pin A0

// LCD
// U8G2_SH1106_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0); // 128 bytes framebuffer
U8G2_SH1106_128X64_NONAME_2_HW_I2C u8g2(U8G2_R0); // 256 bytes framebuffer

// ADC
ADS1115 ads;

// ROLLING AVERAGE
int16_t readingsBuffer[SAMPLE_SIZE];
RollingAverage readings(SAMPLE_SIZE, readingsBuffer);

// ENCODER
ClickEncoder encoder(ENC_PIN_A, ENC_PIN_B, ENC_PIN_SW, ENC_STEPS);

int16_t encPosPrev, encPos;
int8_t encDelta;
uint8_t buttonState;

void timerIsr()
{
	encoder.service();
}

// STATE MACHINE
state_t state;
state_dialog_t stateCalibMenu;
state_ppo2_t stateModDisplay;
uint32_t displayTimer = 0;
uint32_t analyzeTimer = 0;
uint32_t calibrateTimer = 0;
uint32_t batteryTimer = 0;

// OTHER
int16_t batteryVoltage = 0;
int16_t calibrationFactor = 0; // unit is [1e-1 µV / %], value should be ~5000
int16_t oxygenConcentration = 0;
int32_t sensorMicroVolts;
char displayFooterBuffer[24];
bool batteryWarning = false;


// Main render function
void renderDisplay()
{
	u8g2.firstPage();
	do {
		if (batteryWarning) {
			u8g2.setFont(u8g2_font_6x13_tr);
			u8g2.drawBox(118,0,10,12);
			u8g2.setFontMode(1); // transparent background
			u8g2.setDrawColor(2); // XOR
			u8g2.setCursor(120,10);
			u8g2.print(F("B"));
			// reset drawing modes
			u8g2.setFontMode(0);
			u8g2.setDrawColor(1);
		}
		switch(state) {
		case STATE_START_SCREEN:
			// TODO: Add Graphics ?
			u8g2.setFont(u8g2_font_6x13_tr);
			u8g2.setCursor(0,10);
			u8g2.print(F("Nitrox Analyzer"));
			u8g2.setCursor(0,20);
			u8g2.print(F("Starting..."));
			u8g2.setCursor(0,63);
			u8g2.print(F("Battery: "));
			u8g2.print(batteryVoltage/1000);
			u8g2.print(".");
			u8g2.print((batteryVoltage % 1000) / 10);
			u8g2.print("V");
			break;
		case STATE_ANALYZE:
		case STATE_HOLD:
			u8g2.setFont(u8g2_font_6x13_tr);
			u8g2.setCursor(0,10);
			if (state == STATE_HOLD) {
				u8g2.print(F(">>> HOLD <<<"));
			}
			else {
				u8g2.print(F("Analyzing"));	
			}
			//u8g2.setFont(u8g2_font_inb30_mn);
			u8g2.setFont(u8g2_font_logisoso30_tn);
			u8g2.setCursor(20,48);
			// print O2 as a decimal percentage
			if ((oxygenConcentration / 100) < 10) {
				u8g2.print("0");
			}			
			u8g2.print(oxygenConcentration / 100);
			u8g2.print(".");
			if ((oxygenConcentration % 100) < 10) {
				u8g2.print("0");
			}
			u8g2.println(oxygenConcentration % 100);
			// print MOD
			u8g2.setFont(u8g2_font_6x13_tr);
			u8g2.drawStr(0,63,displayFooterBuffer);
			break;
		case STATE_CALIBRATE_MENU:
			u8g2.setFont(u8g2_font_6x13_tr);
			u8g2.setCursor(0,10);
			u8g2.print(F("Calibrate ?"));
			u8g2.setFont(u8g2_font_logisoso30_tn);
			u8g2.drawStr(20,48,"20.95");
			u8g2.setFont(u8g2_font_6x13_tr);
			if (stateCalibMenu == YES) {
				u8g2.drawBox(0,53,64,10);
			}
			else {
				u8g2.drawBox(63,53,64,10);
			}
			u8g2.setFontMode(1); // transparent background
			u8g2.setDrawColor(2); // XOR
			u8g2.setCursor(24,63);
			u8g2.print(F("YES"));
			u8g2.setCursor(90,63);
			u8g2.print(F("NO"));
			// reset drawing modes
			u8g2.setFontMode(0);
			u8g2.setDrawColor(1);
			break;
		case STATE_CALIBRATE:
			u8g2.setFont(u8g2_font_6x13_tr);
			u8g2.setCursor(30,10);
			u8g2.print(F("Calibration"));
			u8g2.setCursor(30,20);
			u8g2.print(F("in progress"));
			u8g2.setCursor(21,40);
			u8g2.print(F("Please wait..."));
			break;
		default: 
			;
		}
	} while ( u8g2.nextPage() );
}


void setup()
{
  Serial.begin(9600);
//#ifdef DEBUG
	//Serial.begin(19200);
	//Serial.println(F("*\n* Nitrox Analyser - DEBUG\n*"));
//#endif
	Wire.begin();

	u8g2.begin();
	u8g2.setFont(u8g2_font_6x13_tr);
	
	ads.begin();
	ads.setGain(GAIN_SIXTEEN); // +/- 256mV FSR = 7.812µV resolution
	ads.setDataRate(DR_16SPS); // 16 sps
	ads.setMux(MUX_DIFF_0_1);  // sensor is connected between AIN0 (P) and AIN1 (N)
	ads.writeConfig();
#ifdef DEBUG
	Serial.print(F("ADS config: "));
	Serial.println(ads.readConfig());
#endif
	ads.startContinuousConversion();

	// Rolling average
	readings.begin();
	
	// Input processing and debouncing
	Timer1.initialize(1000); // 1ms
	Timer1.attachInterrupt(timerIsr);

	// initialize variables
	encPosPrev = encPos;
	state = STATE_START_SCREEN;
	stateCalibMenu = NO;
	stateModDisplay = PPO2_1_6;
	displayTimer = millis();			// initialize for splash screen
	batteryTimer = -BATTERY_INTERVAL; 	// force initial reading
#ifdef EEPROM_ENABLE
	// Load last calibration factor
	EEPROM.get(EEPROM_CALIBRATION_ADDRESS, calibrationFactor);
#ifdef DEBUG
	Serial.print(F("EEPROM load: ")); Serial.println(calibrationFactor);
#endif
#endif
}


void loop()
{

	static bool updateDisplay = true;

	// Handle inputs
	buttonState = encoder.getButton();
	encPos += encoder.getValue();
	encDelta = encPos - encPosPrev;
	encPosPrev = encPos;
#ifdef DEBUG
	if (buttonState != 0) {
		Serial.print(F("Button: ")); Serial.println(buttonState);
	}
	if (encDelta != 0) {
		Serial.print(F("Encoder: ")); Serial.println(encDelta);
	}
#endif

	// ADC readings
	if (millis() - analyzeTimer >= ANALYZE_INTERVAL) {
		readings.addReading(ads.readLastConversion());
		analyzeTimer = millis();
	}

	// Battery
   int j;
  float v = 0;
  for (j = 0; j < 100; j++) {
    v += vcc.Read_Volts();  // Read VCC
    delay(5);
  }

  // Average of 100 VCC voltage samples
  v = v / j;

  // Display VCC on Serial Monitor
  Serial.println();
  Serial.print("VCC: ");
  Serial.println(v, 3);  // Print VCC to 3 decimal places
  
  // Read the battery voltage by collecting 100 samples
  int i;
  float batteryVoltage = 0;
  for (i = 0; i < 100; i++) {
    // Using VCC as reference for battery voltage
    batteryVoltage += ((analogRead(batt_pin) * (v / 1023.0)) * 2);
    delay(5);
  }

  // Average of 100 battery voltage samples
  batteryVoltage = batteryVoltage / i;

  // Display Battery info on Serial Monitor
  Serial.print("Battery: ");
  Serial.print(batteryVoltage, 2);  // Print battery voltage to 2 decimal places
  Serial.print("V ");
  // Convert battery voltage to percentage
  Serial.print(((batteryVoltage - lowBat) / (fullBat - lowBat)) * 100);
  Serial.println("%");



  delay(100);  // Small delay before next reading


  
	// State machine
	switch (state) {
		case STATE_START_SCREEN:
			if (millis() - displayTimer >= SPLASH_DELAY) {
				state = STATE_ANALYZE;
				updateDisplay = true;
				displayTimer = millis();
#ifdef BUZZER_ENABLE
				tone(BUZZER_PIN,4000,200);
#endif
			}
			break;
		case STATE_ANALYZE:
		case STATE_HOLD:
			// handle inputs
			switch (buttonState) {
			case ClickEncoder::Clicked:
				if (state == STATE_ANALYZE) {
					state = STATE_HOLD;
				}
				else {
					state = STATE_ANALYZE;
				}
#ifdef BUZZER_ENABLE
				tone(BUZZER_PIN,2000,200);
#endif
				break;
			case ClickEncoder::Held:
				state = STATE_CALIBRATE_MENU;
				stateCalibMenu = YES;
				updateDisplay = true;
				break;
#ifdef DEBUG
			case ClickEncoder::DoubleClicked: //6
				Serial.print(F("ADC reading:      ")); Serial.println(readings.getAverage());
				Serial.print(F("Sensor µV:        ")); Serial.println(sensorMicroVolts);
				Serial.print(F("Calib. factor:    ")); Serial.println(calibrationFactor);
				Serial.print(F("O2 concentration: ")); Serial.println(oxygenConcentration);
				Serial.print(F("Battery:          ")); Serial.println(batteryVoltage);
	#ifdef BUZZER_ENABLE
				tone(BUZZER_PIN,4000,500);
	#endif
				break;
#endif
			}
			if (encDelta != 0) {
				if (encDelta > 0) {
					stateModDisplay++;
				}
				else if (encDelta < 0) {
					stateModDisplay--;
				}
			}
			if (millis() - displayTimer >= DISPLAY_REFRESH_RATE) {
				if (state == STATE_ANALYZE) {
					sensorMicroVolts = ((int32_t)readings.getAverage() * 7812L) / 1000L;
					if (sensorMicroVolts <= 0) {
						// TODO: ERROR BAD SENSOR
						// adjust threshold ? ex. 5mV ?
					}
					oxygenConcentration = (int16_t)((sensorMicroVolts * 1000L) / calibrationFactor);
					if (oxygenConcentration < 0) {
						// TODO: ask for calibration
						oxygenConcentration = 0;
					}
					else if (oxygenConcentration > 10200) {
						// TODO: ERROR MODE
					}
				}
				// MOD calculation
				uint16_t pO2_max, mod;
				if (stateModDisplay == MV) {
					sprintf_P(displayFooterBuffer, PSTR("Sensor: %d.%02d mV"), 
						(int16_t)(sensorMicroVolts / 1000L),
						(int8_t)((sensorMicroVolts % 1000L) / 10));
				}
				else {
					switch(stateModDisplay) {
					case PPO2_1_4:
						pO2_max = 1400;
						break;
					case PPO2_1_5:
						pO2_max = 1500;
						break;
					case PPO2_1_6:
						pO2_max = 1600;
						break;
					default:
						pO2_max = 1000; // you should not be here...
					}
					mod = calc_mod(oxygenConcentration, pO2_max);
					sprintf_P(displayFooterBuffer, PSTR("pO2 %d.%d > MOD %dm"),
						(uint8_t)(pO2_max / 1000),
						(uint8_t)((pO2_max % 1000) / 100),
						(uint8_t)(mod / 100) );
				}
				updateDisplay = true;
				displayTimer = millis();
			}
			break;
		case STATE_CALIBRATE_MENU:
			if (encDelta != 0) {
				if (encDelta > 0) {
					stateCalibMenu = NO;
				}
				else if (encDelta < 0) {
					stateCalibMenu = YES;
				}
				updateDisplay = true;
			}
			if (buttonState == ClickEncoder::Clicked) {
				if (stateCalibMenu == YES) {
					state = STATE_CALIBRATE;
					calibrateTimer = millis();
				}
				else {
					state = STATE_ANALYZE;
				}
				updateDisplay = true;
			} 
			break;
		case STATE_CALIBRATE:
			// TODO: handle inputs ?
			if (millis() - calibrateTimer >= CALIBRATION_TIME) {
				// TODO: check calibration sample quality (e.g. max deviation)
				// 7812 is ADS resolution in [nV / LSB] at PGA = 16
				// 2095 is calibration oxygen concentration (20.95% in air)
				int32_t sensorMicroVolts = ((int32_t)readings.getAverage() * 7812L) / 1000L;
				calibrationFactor = (int16_t)((sensorMicroVolts * 1000L) / 2095L);
#ifdef DEBUG
				Serial.println(F("Calibration complete"));
				Serial.print(F("Sensor: ")); Serial.print(sensorMicroVolts); Serial.println(F(" µV"));
				Serial.print(F("Calibration factor:")); Serial.println(calibrationFactor);
#endif
#ifdef EEPROM_ENABLE
				EEPROM.put(EEPROM_CALIBRATION_ADDRESS, calibrationFactor);
	#ifdef DEBUG
				Serial.println(F("Saved to EEPROM"));
	#endif
#endif
				state = STATE_ANALYZE;
				updateDisplay = true;
#ifdef BUZZER_ENABLE
				tone(BUZZER_PIN,3000,500);
#endif
			}
			// render
			break;
		case STATE_ERROR:
#ifdef BUZZER_ENABLE
//			tone(BUZZER_PIN,1000,1000); // would beep continuously - should be activated when entering error mode
#endif
			// TODO
			break;
	}

	if (updateDisplay) {
		renderDisplay();
		updateDisplay = false;
	
  }
}

This is my code now, i tried to combine two working parts, now i get 0.0v on arduino display and on serial monitor on arduino IDE i get 1.62v when actualy 4.6v and it rises on 1.63v when voltage drops to 4.0v in real

edit:
ok i managed to get real readings on serial monitor, but display show 0.0v

edit2:
i got it working now, the problem was in
float batteryVoltage = 0;
it was declared in loop scope, i moved it to global so that got problem solved

thank you for your help, i have been struggling with this for days

Note that this line will not do what you expected:

because batteryTimer is unsigned.

it doesn't really matter though, because batteryTimer is not used anywhere in the current code.

Note that this line will not do what you expected:

because batteryTimer is unsigned.

it doesn't really matter though, because batteryTimer is not used anywhere in the current code.

well i have copied someone elses code, so not really sure what it had to do.

well i am aware of that, this device is not to be used under water, it is used to measure percentage of oxygen in breathing gas for diving, but it is used as secondary check device.
You order at shop 35% oxygen gas, and with this device you check what you got, so both devices should show same wrong value for problem to accrue. Thanks for safety concerns

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