Automatic Control and User Interface for Central Tire Inflation System

If I try to change or move or put another code into then I get all errors on everything related to Liquid Crystal this is probably a bit complicated for me :confused:
Can anyone point me in straight track how I replaced Liquid Crystal LCD to use a mean WidgetLCD Blynk app.

Know I’m asking a lot but is quick to learn and now I’ve not asked a lot how to do this here so I would be grateful if to any one wanted to see the code for me and help :slight_smile:

 * Blynk is a platform with iOS and Android apps to control
 * Arduino, Raspberry Pi and the likes over the Internet.
 * You can easily build graphic interfaces for all your
 * projects by simply dragging and dropping widgets.
 *
 *   Downloads, docs, tutorials: http://www.blynk.cc
 *   Sketch generator:           http://examples.blynk.cc
 *   Blynk community:            http://community.blynk.cc
 *   Social networks:            http://www.fb.com/blynkapp
 *                               http://twitter.com/blynk_app
 *
 * Blynk library is licensed under MIT license
 * This example code is in public domain.
 *
 ************************************************
 *
 * This example shows how to use Arduino Ethernet shield (W5100)
 * to connect your project to Blynk.
 * Feel free to apply it to any other example. It's simple!
 *
 * NOTE: Pins 10, 11, 12 and 13 are reserved for Ethernet module.
 *       DON'T use them in your sketch directly!
 *
 * WARNING: If you have an SD card, you may need to disable it
 *       by setting pin 4 to HIGH. Read more here:
 *       https://www.arduino.cc/en/Main/ArduinoEthernetShield
 *
 **************************************************************/

#define BLYNK_PRINT Serial    // Comment this out to disable prints and save space
#include <SPI.h>
#include <Ethernet.h>
#include <BlynkSimpleEthernet.h>
#include <LiquidCrystal.h>
#include <EEPROM.h>
#include <inttypes.h>
#include <Wire.h>

//////////////////////////////////////
// Tire pressure : 1 bit = 0.01 PSI //
// Tank pressure : 1 bit = 0.01 PSI //
//////////////////////////////////////

//////// GLOBAL PARAMETERS /////
// Tire pressure control parameters:
const uint8_t TOLERANCE = 5;  //[Tire pressure storage unit] set point tolerance
const uint16_t ALL_WITHIN_TOL_WAIT_TIME = 8000;  //[ms]
const uint8_t TIME_BETW_MEAS = 50;  //[ms] 
const uint8_t NUM_OF_MEASUREMENTS_SHORT_FILTER = 6;  //Number of measurements averaged
const uint8_t NUM_OF_MEASUREMENTS_LONG_FILTER = 50;  //Number of measurements averaged
const uint16_t MAX_DEFLATION_TIME = 6000;  //[ms] 
const uint16_t MAX_INFLATION_TIME = 6000;  //[ms] 
const uint16_t WITHIN_TOL_SET_POINT_THRESHOLD = 10;  //[raw set point bits]
const uint8_t STAND_BY_THRESHOLD = 10; //Stand by threshold 
const uint8_t STAND_BY_MULTIPLAYER = 4;  //Stand by multiplier
const uint16_t SETTLING_TIME = 100;  //[ms] pressure settling time
const uint16_t VALVE_OPENING_TIME = 7; //[ms]
const float BITS_TO_PSIUNIT_MXP4250 = 3.8425; // 1 bit = 0,038425 psi 
const int16_t FILTER_THRESHOLD = 100;  // raw ADC value
const uint16_t FRONT_AXLE_OFFSET_ADJUST_TIME_LENGTH = 4000;
const uint16_t FRONT_AXLE_OFFSET_LOWER_POT_LIMIT = 50;
const uint16_t FRONT_AXLE_OFFSET_HIGER_POT_LIMIT = 950;
byte LCD_SYMBOLS[2][8] = { {B00100, B01110, B11111, B00100, B00100, B00100, B00100,}, {B00100, B00100, B00100, B00100, B11111, B01110, B00100,} };

// Tank parameters:
const uint16_t TANKPRESSURE_BLINK_LIMIT = 3000;  //[Tank pressure storage unit]
const uint16_t TANK_PRESS_BLINK_DELAY = 700;  //[ms]
const float BITS_TO_PSIUNIT_MXP5700 = 11.0135;  // 1 bit = 0,110135 psi
const uint16_t OFFSET_MPX5700 = 35;  // 0 - 1024, raw ADC unit

// Front panel parameters:
const uint16_t POT_NONLINEAR_THRES = 700;  // range (0-1023)
const uint16_t FRONT_PANEL_TIME_THRES_PERIOD = 250;
uint16_t MAX_POT_COUNT = 1020;  //(Not constant) Max output from POT  ATH hĂ©r ĂŸarf aĂ° lĂĄta lesa Ășr EEPROM
uint16_t MIN_POT_COUNT = 0;  //(Not constant) Min output from POT  ATH hĂ©r ĂŸarf aĂ° lĂĄta lesa Ășr EEPROM
const uint8_t SETPOINT_MAXIMUM_PSI = 35;
char LCD_INIT_STRING1[] = "thorhalb    v1.0";
char LCD_INIT_STRING2[] = "                ";
char LCD_INIT_STRING3[] = "       -.-   -.-";
char LCD_INIT_STRING4[] = "       -.-   -.-";
char LCD_INIT_STRING5[] = "Enter front axle";
char LCD_INIT_STRING6[] = "offset:       psi";
const int LCD_X[] = {6, 12, 6, 12};  // The position coordinates of the tire pressure on the screen
const int LCD_Y[] = {0,  0, 1,  1};          
const uint8_t PIN_GREEN_LED = A3;
const uint8_t PIN_ALL_INDI = 0;
const uint8_t PIN_POT = A5;

// Control pins deceleration
const uint8_t PIN_VALVE0 = 9;
const uint8_t PIN_VALVE1 = 3;
const uint8_t PIN_VALVE2 = 5;
const uint8_t PIN_VALVE3 = 6;
const uint8_t PIN_VALVE4 = 7;
const uint8_t PIN_VALVE5 = 8;
const uint8_t PIN_PUMP = 1;

// Sensors
const uint8_t PIN_MPX4250 = A2; 
const uint8_t PIN_MPX5700 = A1;

// EEPROM and control parameters
const uint8_t SINGLE_CHANNEL_DEFLATION_PARAM_ADDRESS = 0;
const uint8_t SINGLE_CHANNEL_INFLATION_PARAM_ADDRESS = 4;
const uint8_t FRONT_CHANNELS_DEFLATION_PARAM_ADDRESS = 8;
const uint8_t FRONT_CHANNELS_INFLATION_PARAM_ADDRESS = 12;
const uint8_t REAR_CHANNELS_DEFLATION_PARAM_ADDRESS = 16;
const uint8_t REAR_CHANNELS_INFLATION_PARAM_ADDRESS = 20;
const uint8_t ALL_CHANNELS_DEFLATION_PARAM_ADDRESS = 24;
const uint8_t ALL_CHANNELS_INFLATION_PARAM_ADDRESS = 28;

// Other constants:
const uint16_t SERIAL_BAUDRATE = 9600;

////////// GLOBAL VARIABLES /////    
// Enum:
enum valveControlCommand {CLOSE_ALL, MEASURE, INFLATE, DEFLATE, CALIBRATION};
enum tireControlState {firstMeasurementOngoing, allWithinTolWaiting, firstMeasurementDone, inflationDeflationDone, secondMeasurementOngoing, secondMeasurementDone};
enum LCD_SYMBOL {ARROW_UP, ARROW_DOWN};

// Tire pressure control - global variables:
uint8_t activeTire = 0;  //Four tires: 0-3
tireControlState tireState = allWithinTolWaiting;  //Enum
uint16_t tireSensorOffset = 0;  //Raw ADC value
int16_t setPoint = 0;  //[Tire pressure storage unit]
uint16_t currentPotRaw = 0;  //Current set point POT raw value 
int16_t withinTolSetPoint = 0;  //[Tire pressure storage unit]
int16_t summedPressure = 0;  //Temp variable - used to accumulate measurements
boolean isAllWithinTol = false;  //Are all channels within tolerance
uint8_t allWithinTolCounter = 0;  //How many channels have been found in row within tolerance
uint8_t numOfMeasCounter = 0;  //Current number of measurements taken
uint32_t TireTimeThres = 0;  //Tire control time threshold
boolean isChBelow10PSI[4] = {true, true, true, true};
uint16_t firstMeasurementPressure = 0;
uint16_t secondMeasurementPressure = 0;
boolean isDeflating = false;
boolean isInflating = true;
uint16_t deflationTime = 0;
uint16_t inflationTime = 0; 
boolean isSetPointChanged = true;
uint16_t numberOfMeasurementsInUse = NUM_OF_MEASUREMENTS_SHORT_FILTER;
int8_t frontAxleOffset = 0;  // [psi*100] Range -4 to 4 psi ( -400 to 400)
int16_t maxPressureReading = 0;
int16_t minPressureReading = 1023;
uint8_t isShortFilterActive = true;

// Tank pressure control - global variables:
boolean isValve5Closed = true;
int16_t tankPress = 0;  //[Tank pressure storage unit] Current tank pressure
uint32_t tankPressureLCDTimeThres = 0;  //Tank pressure blink time threshold
uint32_t calibrationTankTimeThres = 0;
boolean tankBlink = false; 

// EEPROM and control parameters - global variables:
uint16_t singleChannelDeflationParam = 11000; 
uint16_t singleChannelInflationParam = 1200; 
uint16_t frontChannelsDeflationParam = 11000; 
uint16_t frontChannelsInflationParam = 1200; 
uint16_t rearChannelsDeflationParam = 11000; 
uint16_t rearChannelsInflationParam = 1200; 
uint16_t allChannelsDeflationParam = 11000; 
uint16_t allChannelsInflationParam = 1200; 
uint32_t EEPROMTimeThres = 20000;

// Other - global variables:
uint32_t backgroundTasksTimeThres = 0;  //Front panel time threshold
uint32_t blinkLEDTimeThres = 0;  //Front panel LED blink time threshold
boolean isIndependentEnabled = true;  //Independent channels enabled
uint16_t counter = 0;  //Temp variable for performance test

uint16_t channel0 = 0;
uint16_t channel1 = 0;
uint16_t channel2 = 0;
uint16_t channel3 = 0;

// Global objects:
LiquidCrystal lcd(2, 3, 5, 6, 7); //Can not use this pin now because they are used by others now and so I need to use Blynk LCD
 

// You should get Auth Token in the Blynk App.
// Go to the Project Settings (nut icon).
char auth[] = "3295d2122335428a8a8877a04a64367b";

#define W5100_CS  10
#define SDCARD_CS 4

void setup()
{
  Serial.begin(SERIAL_BAUDRATE);
  
  pinMode(PIN_ALL_INDI, INPUT);
  pinMode(PIN_GREEN_LED, OUTPUT);
  pinMode(PIN_VALVE0, OUTPUT);
  pinMode(PIN_VALVE1, OUTPUT);
  pinMode(PIN_VALVE2, OUTPUT);
  pinMode(PIN_VALVE3, OUTPUT);
  pinMode(PIN_VALVE4, OUTPUT);
  pinMode(PIN_VALVE5, OUTPUT);
  pinMode(PIN_PUMP, OUTPUT);
  
  lcdInit1();
  tireSensorOffset = tireOffsetCalibration();
  lcdInit2();
  loadParamFromEEPROM();

  pinMode(SDCARD_CS, OUTPUT);
  digitalWrite(SDCARD_CS, HIGH); // Deselect the SD card
  Blynk.begin(auth, IPAddress(192,168,10,3)); // For more options, see Boards_Ethernet/Arduino_Ethernet_Manual example
}

void loop()
{
  if(backgroundTasksTimeThres < millis())
  {
    backgroundTasks();
  } 
  if(TireTimeThres < millis())
  { 
    tirePressureControl();      
  }
  if(tankPressureLCDTimeThres < millis())
  {
    printTankPressureLCD();
  }
  Blynk.run();
}

/////////////////////////////////////////////////////////////////////////////////////////////////
void backgroundTasks()
{
  backgroundTasksTimeThres = millis() + FRONT_PANEL_TIME_THRES_PERIOD;
  readTankPress();
  updatingSetPoint();
  updatingALLOrIndividualSwitch();
  updatingFrontPanelLED();

  // Method to capture set point changes in all-within-tolerance mode where the period is very slow
  if (isAllWithinTol && (abs(setPoint - withinTolSetPoint) > WITHIN_TOL_SET_POINT_THRESHOLD))
  {
    TireTimeThres = 0; // Measure the next channel immediately
    withinTolSetPoint = setPoint; // So that this is only caught once - not four times
  }

  // Tank functions - only read sensor when tankValve is closed
  if (isValve5Closed == true)
  {
    readTankPress();
  }
}

void tirePressureControl()
{
  switch (tireState)
  {
    case firstMeasurementOngoing:
      takeOneMoreMeasurement();
      if (numOfMeasCounter >= numberOfMeasurementsInUse)
      {
        tireState = firstMeasurementDone;
      }
      break;

    case firstMeasurementDone:
      if (maxPressureReading - minPressureReading > FILTER_THRESHOLD && isShortFilterActive == true)
      {
        isShortFilterActive = false;
        tireState = firstMeasurementOngoing;
        numberOfMeasurementsInUse = NUM_OF_MEASUREMENTS_LONG_FILTER;
      }
      else
      {
        valveControl(CLOSE_ALL);
        isShortFilterActive = true;
        maxPressureReading = 0;
        minPressureReading = 1023;
        firstMeasurementPressure = calcAverage();
        numberOfMeasurementsInUse = NUM_OF_MEASUREMENTS_SHORT_FILTER;
        displayTirePress(firstMeasurementPressure);
        decideWhatToDo(firstMeasurementPressure);
        updateAllWithinTol();
      }
      break;

    case allWithinTolWaiting:
      valveControl(MEASURE);
      TireTimeThres = millis() + SETTLING_TIME;
      tireState = firstMeasurementOngoing;
      break;

    case inflationDeflationDone:


      if (activeTire == 60)
      {
        tireState = firstMeasurementOngoing;
      }
      else
      {
        tireState = secondMeasurementOngoing;
      }
      valveControl(MEASURE);
      TireTimeThres = millis() + SETTLING_TIME;
      break;

    case secondMeasurementOngoing:
      takeOneMoreMeasurement();
      if (numOfMeasCounter >= numberOfMeasurementsInUse)
      {
        tireState = secondMeasurementDone;
      }
      break;

    case secondMeasurementDone:
      if (maxPressureReading - minPressureReading > FILTER_THRESHOLD && isShortFilterActive == true)
      {
        isShortFilterActive = false;
        tireState = secondMeasurementOngoing;
        numberOfMeasurementsInUse = NUM_OF_MEASUREMENTS_LONG_FILTER;
      }
      else
      {
        isShortFilterActive = true;
        maxPressureReading = 0;
        minPressureReading = 1023;
        secondMeasurementPressure = calcAverage();
        numberOfMeasurementsInUse = NUM_OF_MEASUREMENTS_SHORT_FILTER;
        displayTirePress(secondMeasurementPressure);
        changeToNextChannel();
        updatingControlParameters();
        valveControl(MEASURE);
        TireTimeThres = millis() + SETTLING_TIME;
        tireState = firstMeasurementOngoing;
      }
      break;
  }
}

////////////// Support functions: ///////////////////////////
void readTankPress()
{
  tankPress = (float)(analogRead(PIN_MPX5700) - OFFSET_MPX5700) * BITS_TO_PSIUNIT_MXP5700;
}

void changeToNextChannel()
{
  // 0 - 3 = independent channels, 4 = front (0-1 ch), 5 rear (2-3 ch), 6 all channels
  if (isIndependentEnabled == true)
  {
    activeTire = (activeTire + 1) % 4;
  }
  else if (frontAxleOffset == 0)
  {
    activeTire = 6;
  }
  else
  {
    if (activeTire == 5)
    {
      activeTire = 4;
    }
    else
    {
      activeTire = 5;
    }
  }
}

void printTankPressureLCD()
{
  tankPressureLCDTimeThres = millis() + TANK_PRESS_BLINK_DELAY;

  lcd.setCursor(0, 1);
  if (tankPress > TANKPRESSURE_BLINK_LIMIT || tankBlink == false)
  {
    //Printing space if needed
    if (tankPress < 995)
    {
      lcd.print("  ");
    }
    else if (tankPress < 9995)
    {
      lcd.print(" ");
    }

    // Print number
    lcd.print((tankPress + 5) / 100); // 5 is so the rounding will be correct and 100 is because of the way the pressure is stored
    tankBlink = true;
  }
  else
  {
    tankBlink = false;
    lcd.print("     ");
  }
}

void clearAllArrowsAndM()
{
  for (int i = 0; i < 4; i++)
  {
    lcd.setCursor(LCD_X[i] - 1, LCD_Y[i]);
    if (isChBelow10PSI[i])
    {
      lcd.print("  ");
    }
    else
    {
      lcd.print(" ");
    }
  }
}

void printArrowsAndM(int command)
{
  clearAllArrowsAndM();
  uint8_t startChannel = 0;
  uint8_t endChannel = 0;
  switch (activeTire)
  {
    case 0:
    case 1:
    case 2:
    case 3:
      startChannel = activeTire;
      endChannel = activeTire;
      break;
    case 4:
      startChannel = 0;
      endChannel = 1;
      break;
    case 5:
      startChannel = 2;
      endChannel = 3;
      break;
    case 6:
      startChannel = 0;
      endChannel = 3;
      break;
  }

  for (uint8_t i = startChannel; i < endChannel + 1; i++)
  {
    lcd.setCursor(LCD_X[i] - 1, LCD_Y[i]);
    if (isChBelow10PSI[i])
    {
      lcd.print(" ");
    }

    switch (command)
    {
      case MEASURE:
        lcd.write("M");
        break;
      case INFLATE:
        lcd.write(byte(ARROW_UP));
        break;
      case DEFLATE:
        lcd.write(byte(ARROW_DOWN));
        break;
    }
  }
}

void updatingSetPoint()
{
  uint16_t newPotRaw = analogRead(PIN_POT);

  if (abs(newPotRaw - currentPotRaw) > 10 ) // POT hysteresis
  {
    uint16_t newSetPoint = potToPSI(newPotRaw);
    if ( newSetPoint != setPoint)
    {
      setPoint = newSetPoint;
      currentPotRaw = newPotRaw;
      isSetPointChanged = true;
      lcd.setCursor(0, 0);
      if (setPoint < 995)
      {
        lcd.print(" "); // This is for alignment of decimal point on screen
      }
      lcd.print(((float)setPoint) / 100, 1);
    }
  }
}

uint16_t potToPSI(uint16_t potRaw)
{
  uint16_t output = 0;

  if (potRaw < POT_NONLINEAR_THRES)
  {
    output = map(potRaw, MIN_POT_COUNT, POT_NONLINEAR_THRES - 1, 0, 499);
  }
  else
  {
    output = map(potRaw, POT_NONLINEAR_THRES, MAX_POT_COUNT, 500, SETPOINT_MAXIMUM_PSI * 100);
  }
  // Round of numbers higher than 500 (5 PSI)
  if (output > 500)
  {
    output = (output / (int)100) * (int)100;
  }
  else
  {
    output = (output / (int)50) * (int)50;
  }

  if (output < 50)
  {
    output = 25;
  }
  return output;
}

void updatingALLOrIndividualSwitch()
{
  boolean allIndiSwitchEnabled = digitalRead(PIN_ALL_INDI);
  if (allIndiSwitchEnabled && !isIndependentEnabled)
  {
    activeTire = 0;
    isIndependentEnabled = true;
    TireTimeThres = 0;
    allWithinTolCounter = 0;
    isAllWithinTol = 0;
    valveControl(CLOSE_ALL);
  }
  else if (!allIndiSwitchEnabled && isIndependentEnabled)
  {
    activeTire = 6;
    isIndependentEnabled = false;
    TireTimeThres = 0;
    allWithinTolCounter = 0;
    isAllWithinTol = 0;
    valveControl(CLOSE_ALL);
  }
}

void updatingFrontPanelLED()
{
  if (isAllWithinTol)
  {
    digitalWrite(PIN_GREEN_LED, 1);
  }
  else
  {
    digitalWrite(PIN_GREEN_LED, 0);
  }
}

void takeOneMoreMeasurement()
{
  uint16_t temp = analogRead(PIN_MPX4250) - tireSensorOffset;
  if (temp > maxPressureReading)
  {
    maxPressureReading = temp;
  }
  if (temp < minPressureReading)
  {
    minPressureReading = temp;
  }
  summedPressure = summedPressure + temp;
  numOfMeasCounter += 1;
  TireTimeThres = millis() + TIME_BETW_MEAS;
}

uint16_t calcAverage()
{

  numOfMeasCounter = 0;
  int16_t currentPressure = (float)(summedPressure / numberOfMeasurementsInUse) * BITS_TO_PSIUNIT_MXP4250;
  if ( currentPressure < 0 )
  {
    currentPressure = 0;
  }
  summedPressure = 0;
  return currentPressure;
}

void displayTirePress(uint16_t currentPressure)
{
  float printOutPress = (float)currentPressure / (float)100;

  if (currentPressure > 37000) // This is to eliminate "negative" pressure
  {
    currentPressure = 0;
  }

  uint8_t isCurrentPressBelow10psi = currentPressure < 995;
  uint8_t startChannel = 0;
  uint8_t endChannel = 0;
  switch (activeTire)
  {
    case 0:
      channel0 = currentPressure;
      startChannel = activeTire;
      endChannel = activeTire;
      isChBelow10PSI[activeTire] = isCurrentPressBelow10psi;
      break;
    case 1:
      channel1 = currentPressure;
      startChannel = activeTire;
      endChannel = activeTire;
      isChBelow10PSI[activeTire] = isCurrentPressBelow10psi;
      break;
    case 2:
      channel2 = currentPressure;
      startChannel = activeTire;
      endChannel = activeTire;
      isChBelow10PSI[activeTire] = isCurrentPressBelow10psi;
      break;
    case 3:
      channel3 = currentPressure;
      startChannel = activeTire;
      endChannel = activeTire;
      isChBelow10PSI[activeTire] = isCurrentPressBelow10psi;
      break;
    case 4:
      channel0 = currentPressure;
      channel1 = currentPressure;
      startChannel = 0;
      endChannel = 1;
      isChBelow10PSI[0] = isCurrentPressBelow10psi;
      isChBelow10PSI[1] = isCurrentPressBelow10psi;
      break;
    case 5:
      channel2 = currentPressure;
      channel3 = currentPressure;
      startChannel = 2;
      endChannel = 3;
      isChBelow10PSI[2] = isCurrentPressBelow10psi;
      isChBelow10PSI[3] = isCurrentPressBelow10psi;
      break;
    case 6:
      channel0 = currentPressure;
      channel1 = currentPressure;
      channel2 = currentPressure;
      channel3 = currentPressure;
      startChannel = 0;
      endChannel = 3;
      isChBelow10PSI[0] = isCurrentPressBelow10psi;
      isChBelow10PSI[1] = isCurrentPressBelow10psi;
      isChBelow10PSI[2] = isCurrentPressBelow10psi;
      isChBelow10PSI[3] = isCurrentPressBelow10psi;
      break;
  }

  for (uint8_t i = startChannel; i < endChannel + 1; i++)
  {
    lcd.setCursor(LCD_X[i], LCD_Y[i]);
    if (printOutPress < 9.95) // This is for alignment of decimal point on screen
    {
      lcd.print(" ");
    }
    lcd.print(abs(printOutPress), 1);
  }
}

void updateAllWithinTol()
{
  uint8_t numberOfChannelsInUse = 0;
  switch (activeTire)
  {
    case 0:
    case 1:
    case 2:
    case 3:
      numberOfChannelsInUse = 3;
      break;
    case 4:
    case 5:
      numberOfChannelsInUse = 2;
      break;
    case 6:
      numberOfChannelsInUse = 1;
      break;
  }
  if (allWithinTolCounter >= numberOfChannelsInUse && !isAllWithinTol)
  {
    isAllWithinTol = true;
    withinTolSetPoint = setPoint;
    isSetPointChanged = false;
  }
  else if (allWithinTolCounter < numberOfChannelsInUse)
  {
    isAllWithinTol = false;
  }
}

uint16_t calculateDeflationTime(uint16_t currentPressure)
{
  uint16_t deflationParamInUse = 0;
  switch (activeTire)
  {
    case 0:
    case 1:
    case 2:
    case 3:
      deflationParamInUse = singleChannelDeflationParam;
      break;
    case 4:
      deflationParamInUse = frontChannelsDeflationParam;
      break;
    case 5:
      deflationParamInUse = rearChannelsDeflationParam;
      break;
    case 6:
      deflationParamInUse = allChannelsDeflationParam;
      break;
  }

  uint16_t timeMilliSec = ((deflationParamInUse * 10) / log( (float)currentPressure / (float)setPoint )) + VALVE_OPENING_TIME;
  if (timeMilliSec > MAX_DEFLATION_TIME)
  {
    timeMilliSec =  MAX_DEFLATION_TIME;
  }
  return timeMilliSec;
}

uint16_t calculateInflationTimeMS(uint16_t currentPressure)
{
  uint16_t inflationParamInUse = 0;
  switch (activeTire)
  {
    case 0:
    case 1:
    case 2:
    case 3:
      inflationParamInUse = singleChannelInflationParam;
      break;
    case 4:
      inflationParamInUse = frontChannelsInflationParam;
      break;
    case 5:
      inflationParamInUse = rearChannelsInflationParam;
      break;
    case 6:
      inflationParamInUse = allChannelsInflationParam;
      break;
  }

  uint16_t timeMilliSec = ((float)( setPoint - currentPressure ) * ( inflationParamInUse / 100 ) ) + VALVE_OPENING_TIME;
  if (timeMilliSec > MAX_INFLATION_TIME)
  {
    timeMilliSec =  MAX_INFLATION_TIME;
  }
  return timeMilliSec;
}

void decideWhatToDo(int16_t currentPressure)
{
  int16_t difference = currentPressure - setPoint;
  if (activeTire == 0 || activeTire == 1 || activeTire == 4)
  {
    difference = difference - frontAxleOffset;
  }
  if (abs(difference) > TOLERANCE) // Last measurement not within tolerance
  {
    allWithinTolCounter = 0;
    if (difference > 0)
    {
      valveControl(DEFLATE);
      deflationTime = calculateDeflationTime(currentPressure);
      TireTimeThres = millis() + deflationTime;
    }
    else if (1)  //tankPress > 3000) // inflation only performed if tank press > 30 psi
    {
      valveControl(INFLATE);
      inflationTime = calculateInflationTimeMS(currentPressure);
      TireTimeThres = millis() + inflationTime;
    }
    tireState = inflationDeflationDone;
  }
  else // Last measurement within tolerance
  {
    allWithinTolCounter += 1;
    changeToNextChannel();

    if (isAllWithinTol && allWithinTolCounter > STAND_BY_THRESHOLD)
    {
      closeAllValves();
      TireTimeThres = millis() + (STAND_BY_MULTIPLAYER * ALL_WITHIN_TOL_WAIT_TIME);
      tireState = allWithinTolWaiting;
    }
    else if (isAllWithinTol)
    {
      closeAllValves();
      if (activeTire == 6)
      {
        openActiveTireValve();
      }
      TireTimeThres = millis() + ALL_WITHIN_TOL_WAIT_TIME;
      tireState = allWithinTolWaiting;
    }
    else
    {
      valveControl(MEASURE);
      TireTimeThres = millis() + SETTLING_TIME;
      tireState = firstMeasurementOngoing;
    }
  }
}

void openActiveTireValve()
{
  switch (activeTire)
  {
    case 0:
      digitalWrite(PIN_VALVE1, HIGH);
      break;
    case 1:
      digitalWrite(PIN_VALVE2, HIGH);
      break;
    case 2:
      digitalWrite(PIN_VALVE3, HIGH);
      break;
    case 3:
      digitalWrite(PIN_VALVE4, HIGH);
      break;
    case 4:
      digitalWrite(PIN_VALVE1, HIGH);
      digitalWrite(PIN_VALVE2, HIGH);
      break;
    case 5:
      digitalWrite(PIN_VALVE3, HIGH);
      digitalWrite(PIN_VALVE4, HIGH);
      break;
    case 6:
      digitalWrite(PIN_VALVE1, HIGH);
      digitalWrite(PIN_VALVE2, HIGH);
      digitalWrite(PIN_VALVE3, HIGH);
      digitalWrite(PIN_VALVE4, HIGH);
      break;
  }
}

void closeAllValves()
{
  digitalWrite(PIN_VALVE0, LOW);
  digitalWrite(PIN_VALVE1, LOW);
  digitalWrite(PIN_VALVE2, LOW);
  digitalWrite(PIN_VALVE3, LOW);
  digitalWrite(PIN_VALVE4, LOW);
  digitalWrite(PIN_VALVE5, LOW);
}

void valveControl(int command)
{
  printArrowsAndM(command);
  closeAllValves();
  isValve5Closed = true;
  switch (command)
  {
    case CLOSE_ALL:
      // Empty on purpose
      break;
    case MEASURE:
      openActiveTireValve();
      break;
    case INFLATE:
      isInflating = true;
      openActiveTireValve();
      digitalWrite(PIN_VALVE5, HIGH);
      isValve5Closed = false;
      break;
    case DEFLATE:
      isDeflating = true;
      openActiveTireValve();
      digitalWrite(PIN_VALVE0, HIGH);
      break;
    case CALIBRATION:
      digitalWrite(PIN_VALVE0, HIGH);
      break;
  }
}

uint16_t tireOffsetCalibration()
{
  valveControl(CALIBRATION);
  writeToLCD(LCD_INIT_STRING1, LCD_INIT_STRING2);
  delay(2 * SETTLING_TIME);
  uint16_t temp = 0;
  for (int8_t i = 0; i < NUM_OF_MEASUREMENTS_SHORT_FILTER; i = i + 1)
  {
    temp = temp + analogRead(PIN_MPX4250);
    delay(TIME_BETW_MEAS);
  }
  uint16_t tireSensorOffset = (temp / NUM_OF_MEASUREMENTS_SHORT_FILTER);
  valveControl(CLOSE_ALL);
  writeToLCD(LCD_INIT_STRING1, LCD_INIT_STRING2);
  delay(2 * SETTLING_TIME);
  return tireSensorOffset;
}

void lcdInit1()
{
  lcd.begin(16, 2);
  lcd.createChar(0, LCD_SYMBOLS[0]);
  lcd.createChar(1, LCD_SYMBOLS[1]);
  lcd.clear();
  writeToLCD(LCD_INIT_STRING1, LCD_INIT_STRING2);
}

void lcdInit2()
{
  writeToLCD(LCD_INIT_STRING3, LCD_INIT_STRING4);
}

void writeToLCD(char string1[], char string2[])
{
  lcd.setCursor(0, 0);
  lcd.print(string1);
  lcd.setCursor(0, 1);
  lcd.print(string2);
}

void writeParamToEEPROM()
{
  // Unfinished function
}

void loadParamFromEEPROM()
{
  singleChannelDeflationParam = EEPROM.read(SINGLE_CHANNEL_DEFLATION_PARAM_ADDRESS);
  singleChannelInflationParam = EEPROM.read(SINGLE_CHANNEL_INFLATION_PARAM_ADDRESS);
  frontChannelsDeflationParam = EEPROM.read(FRONT_CHANNELS_DEFLATION_PARAM_ADDRESS);
  frontChannelsInflationParam = EEPROM.read(FRONT_CHANNELS_DEFLATION_PARAM_ADDRESS);
  rearChannelsDeflationParam = EEPROM.read(REAR_CHANNELS_DEFLATION_PARAM_ADDRESS);
  rearChannelsInflationParam = EEPROM.read(REAR_CHANNELS_DEFLATION_PARAM_ADDRESS);
  allChannelsDeflationParam = EEPROM.read(ALL_CHANNELS_DEFLATION_PARAM_ADDRESS);
  allChannelsInflationParam = EEPROM.read(ALL_CHANNELS_DEFLATION_PARAM_ADDRESS);
}

void updatingControlParameters()
{
  if (isDeflating && isInflating)
  {
    // Error: should not happen
  }
  else if (isDeflating && deflationTime > 0 && (firstMeasurementPressure - secondMeasurementPressure) > 0)
  {
    uint16_t newDeflationParam = deflationTime / log( (float)firstMeasurementPressure / (float)secondMeasurementPressure) / 10;

    switch (activeTire)
    {
      case 0:
      case 1:
      case 2:
      case 3:
        singleChannelDeflationParam = newDeflationParam;
        break;
      case 4:
        frontChannelsDeflationParam = newDeflationParam;
        break;
      case 5:
        rearChannelsDeflationParam = newDeflationParam;
        break;
      case 6:
        allChannelsDeflationParam = newDeflationParam;
        break;
    }

  }
  else if (isInflating && inflationTime > 0 && (secondMeasurementPressure > firstMeasurementPressure))
  {
    uint16_t newInflationParam = inflationTime / (float)(secondMeasurementPressure - firstMeasurementPressure) * 100;

    switch (activeTire)
    {
      case 0:
      case 1:
      case 2:
      case 3:
        singleChannelInflationParam = newInflationParam;
        break;
      case 4:
        frontChannelsInflationParam = newInflationParam;
        break;
      case 5:
        rearChannelsInflationParam = newInflationParam;
        break;
      case 6:
        allChannelsInflationParam = newInflationParam;
        break;
    }
  }
  isDeflating = false;
  isInflating = false;
  if ( EEPROMTimeThres < millis() )
  {
    EEPROMTimeThres = millis() + 5000;
    writeParamToEEPROM();
  }
}

int16_t updateFrontAxleOffset()
{
  closeAllValves();
  writeToLCD(LCD_INIT_STRING5,LCD_INIT_STRING6);
  int16_t offset = 0;
  for (uint8_t i = 0; i < 20; i++)
  {
    offset = map(analogRead(PIN_POT), 0, 1023, -8, 8) * 50; // range from -4 to 4 psi with 0,5 psi resolution
    lcd.setCursor(8, 1);
    if (offset >= 0)
    {
      lcd.print(" ");
    }
    lcd.print((float)offset / 100, 1);
    delay(250);
  }
  return offset;
}

I have no time now for digging into your code, but you have to understand differences between a real, physical LCD, and a widget (i.e a software code) emulating a look of a real LCD.A Blynk LCD widget has two modes (you need to read the docs at http://docs.blynk.cc) Because you try to adopt an existing code working with a real LCD my thoughts are you shoud try with an “advanced” mode, which is closer to the method the real LCD works. As you are not connecting physically a LCD display, the #include <LiquidCrystal.h> is not needed. Also the definitions in LCD_SYMBOLS will NOT work-it is for a real LCD. on the other hand the char LCD_INITSTRING[] = are ok, as long as they are kept within 16 chars long.

The LiquidCrystal lcd(2, 3, 5, 6, 7); as you noted will not be used - so comment it out or delete
instead you need to define the virtual LCD the way shown in examples:

WidgetLCD lcd(V1);

where V1 is a virtual pin number used in smartphone’s app

To control the display you have:

lcd.print(x, y, "Your Message");

Where x is a symbol position (0-15), y is a line number (0 or 1),
and a

lcd.clear();

it is slightly different than lcd.setCursor(); and lcd.print(); used with hardware lcd’s

1 Like

is starting to see data in blynk app lcd but there are some errors because it is to connect and disconnect.
Error that is:
Trouble detected: http://docs.blynk.cc/#troubleshooting-flood-error

Here is the code after conversion and cleaning, can quite be that I have too much cleaned

/**************************************************************
 * Blynk is a platform with iOS and Android apps to control
 * Arduino, Raspberry Pi and the likes over the Internet.
 * You can easily build graphic interfaces for all your
 * projects by simply dragging and dropping widgets.
 *
 *   Downloads, docs, tutorials: http://www.blynk.cc
 *   Sketch generator:           http://examples.blynk.cc
 *   Blynk community:            http://community.blynk.cc
 *   Social networks:            http://www.fb.com/blynkapp
 *                               http://twitter.com/blynk_app
 *
 * Blynk library is licensed under MIT license
 * This example code is in public domain.
 *
 **************************************************************
 *
 * This example shows how to use Arduino Ethernet shield (W5100)
 * to connect your project to Blynk.
 * Feel free to apply it to any other example. It's simple!
 *
 * NOTE: Pins 10, 11, 12 and 13 are reserved for Ethernet module.
 *       DON'T use them in your sketch directly!
 *
 * WARNING: If you have an SD card, you may need to disable it
 *       by setting pin 4 to HIGH. Read more here:
 *       https://www.arduino.cc/en/Main/ArduinoEthernetShield
 *
 **************************************************************/

#define BLYNK_PRINT Serial    // Comment this out to disable prints and save space
#include <SPI.h>
#include <Ethernet.h>
#include <BlynkSimpleEthernet.h>
//#include <LiquidCrystal.h>
#include <EEPROM.h>
#include <inttypes.h>
#include <Wire.h>

//////////////////////////////////////
// Tire pressure : 1 bit = 0.01 PSI //
// Tank pressure : 1 bit = 0.01 PSI //
//////////////////////////////////////

//////// GLOBAL PARAMETERS /////
// Tire pressure control parameters:
const uint8_t TOLERANCE = 5;  //[Tire pressure storage unit] set point tolerance
const uint16_t ALL_WITHIN_TOL_WAIT_TIME = 8000;  //[ms]
const uint8_t TIME_BETW_MEAS = 50;  //[ms] 
const uint8_t NUM_OF_MEASUREMENTS_SHORT_FILTER = 6;  //Number of measurements averaged
const uint8_t NUM_OF_MEASUREMENTS_LONG_FILTER = 50;  //Number of measurements averaged
const uint16_t MAX_DEFLATION_TIME = 6000;  //[ms] 
const uint16_t MAX_INFLATION_TIME = 6000;  //[ms] 
const uint16_t WITHIN_TOL_SET_POINT_THRESHOLD = 10;  //[raw set point bits]
const uint8_t STAND_BY_THRESHOLD = 10; //Stand by threshold 
const uint8_t STAND_BY_MULTIPLAYER = 4;  //Stand by multiplier
const uint16_t SETTLING_TIME = 100;  //[ms] pressure settling time
const uint16_t VALVE_OPENING_TIME = 7; //[ms]
const float BITS_TO_PSIUNIT_MXP4250 = 3.8425; // 1 bit = 0,038425 psi 
const int16_t FILTER_THRESHOLD = 100;  // raw ADC value
const uint16_t FRONT_AXLE_OFFSET_ADJUST_TIME_LENGTH = 4000;
const uint16_t FRONT_AXLE_OFFSET_LOWER_POT_LIMIT = 50;
const uint16_t FRONT_AXLE_OFFSET_HIGER_POT_LIMIT = 950;
//byte LCD_SYMBOLS[2][8] = { {B00100, B01110, B11111, B00100, B00100, B00100, B00100,}, {B00100, B00100, B00100, B00100, B11111, B01110, B00100,} };

// Tank parameters:
const uint16_t TANKPRESSURE_BLINK_LIMIT = 3000;  //[Tank pressure storage unit]
const uint16_t TANK_PRESS_BLINK_DELAY = 700;  //[ms]
const float BITS_TO_PSIUNIT_MXP5700 = 11.0135;  // 1 bit = 0,110135 psi
const uint16_t OFFSET_MPX5700 = 35;  // 0 - 1024, raw ADC unit

// Front panel parameters:
const uint16_t POT_NONLINEAR_THRES = 700;  // range (0-1023)
const uint16_t FRONT_PANEL_TIME_THRES_PERIOD = 250;
uint16_t MAX_POT_COUNT = 1020;  //(Not constant) Max output from POT  ATH hĂ©r ĂŸarf aĂ° lĂĄta lesa Ășr EEPROM
uint16_t MIN_POT_COUNT = 0;  //(Not constant) Min output from POT  ATH hĂ©r ĂŸarf aĂ° lĂĄta lesa Ășr EEPROM
const uint8_t SETPOINT_MAXIMUM_PSI = 35;
const uint8_t PIN_GREEN_LED = A3;
const uint8_t PIN_ALL_INDI = 0;
const uint8_t PIN_POT = A5;

// Control pins deceleration
const uint8_t PIN_VALVE0 = 9;
const uint8_t PIN_VALVE1 = 3;
const uint8_t PIN_VALVE2 = 5;
const uint8_t PIN_VALVE3 = 6;
const uint8_t PIN_VALVE4 = 7;
const uint8_t PIN_VALVE5 = 8;
const uint8_t PIN_PUMP = 1;

// Sensors
const uint8_t PIN_MPX4250 = A2; 
const uint8_t PIN_MPX5700 = A1;

// EEPROM and control parameters
const uint8_t SINGLE_CHANNEL_DEFLATION_PARAM_ADDRESS = 0;
const uint8_t SINGLE_CHANNEL_INFLATION_PARAM_ADDRESS = 4;
const uint8_t FRONT_CHANNELS_DEFLATION_PARAM_ADDRESS = 8;
const uint8_t FRONT_CHANNELS_INFLATION_PARAM_ADDRESS = 12;
const uint8_t REAR_CHANNELS_DEFLATION_PARAM_ADDRESS = 16;
const uint8_t REAR_CHANNELS_INFLATION_PARAM_ADDRESS = 20;
const uint8_t ALL_CHANNELS_DEFLATION_PARAM_ADDRESS = 24;
const uint8_t ALL_CHANNELS_INFLATION_PARAM_ADDRESS = 28;

// Other constants:
const uint16_t SERIAL_BAUDRATE = 9600;

////////// GLOBAL VARIABLES /////    
// Enum:
enum valveControlCommand {CLOSE_ALL, MEASURE, INFLATE, DEFLATE, CALIBRATION};
enum tireControlState {firstMeasurementOngoing, allWithinTolWaiting, firstMeasurementDone, inflationDeflationDone, secondMeasurementOngoing, secondMeasurementDone};
enum LCD_SYMBOL {ARROW_UP, ARROW_DOWN};

// Tire pressure control - global variables:
uint8_t activeTire = 0;  //Four tires: 0-3
tireControlState tireState = allWithinTolWaiting;  //Enum
uint16_t tireSensorOffset = 0;  //Raw ADC value
int16_t setPoint = 0;  //[Tire pressure storage unit]
uint16_t currentPotRaw = 0;  //Current set point POT raw value 
int16_t withinTolSetPoint = 0;  //[Tire pressure storage unit]
int16_t summedPressure = 0;  //Temp variable - used to accumulate measurements
boolean isAllWithinTol = false;  //Are all channels within tolerance
uint8_t allWithinTolCounter = 0;  //How many channels have been found in row within tolerance
uint8_t numOfMeasCounter = 0;  //Current number of measurements taken
uint32_t TireTimeThres = 0;  //Tire control time threshold
boolean isChBelow10PSI[4] = {true, true, true, true};
uint16_t firstMeasurementPressure = 0;
uint16_t secondMeasurementPressure = 0;
boolean isDeflating = false;
boolean isInflating = true;
uint16_t deflationTime = 0;
uint16_t inflationTime = 0; 
boolean isSetPointChanged = true;
uint16_t numberOfMeasurementsInUse = NUM_OF_MEASUREMENTS_SHORT_FILTER;
int8_t frontAxleOffset = 0;  // [psi*100] Range -4 to 4 psi ( -400 to 400)
int16_t maxPressureReading = 0;
int16_t minPressureReading = 1023;
uint8_t isShortFilterActive = true;

// Tank pressure control - global variables:
boolean isValve5Closed = true;
int16_t tankPress = 0;  //[Tank pressure storage unit] Current tank pressure
uint32_t tankPressureLCDTimeThres = 0;  //Tank pressure blink time threshold
uint32_t calibrationTankTimeThres = 0;
boolean tankBlink = false; 

// EEPROM and control parameters - global variables:
uint16_t singleChannelDeflationParam = 11000; 
uint16_t singleChannelInflationParam = 1200; 
uint16_t frontChannelsDeflationParam = 11000; 
uint16_t frontChannelsInflationParam = 1200; 
uint16_t rearChannelsDeflationParam = 11000; 
uint16_t rearChannelsInflationParam = 1200; 
uint16_t allChannelsDeflationParam = 11000; 
uint16_t allChannelsInflationParam = 1200; 
uint32_t EEPROMTimeThres = 20000;

// Other - global variables:
uint32_t backgroundTasksTimeThres = 0;  //Front panel time threshold
uint32_t blinkLEDTimeThres = 0;  //Front panel LED blink time threshold
boolean isIndependentEnabled = true;  //Independent channels enabled
uint16_t counter = 0;  //Temp variable for performance test

uint16_t channel0 = 0;
uint16_t channel1 = 0;
uint16_t channel2 = 0;
uint16_t channel3 = 0;

// Global objects:
 WidgetLCD lcd(V1);

// You should get Auth Token in the Blynk App.
// Go to the Project Settings (nut icon).
char auth[] = "3295d2122335428a8a8877a04a64367b";

#define W5100_CS  10
#define SDCARD_CS 4

void setup()
{
  Serial.begin(SERIAL_BAUDRATE);
  
  pinMode(PIN_ALL_INDI, INPUT);
  pinMode(PIN_GREEN_LED, OUTPUT);
  pinMode(PIN_VALVE0, OUTPUT);
  pinMode(PIN_VALVE1, OUTPUT);
  pinMode(PIN_VALVE2, OUTPUT);
  pinMode(PIN_VALVE3, OUTPUT);
  pinMode(PIN_VALVE4, OUTPUT);
  pinMode(PIN_VALVE5, OUTPUT);
  pinMode(PIN_PUMP, OUTPUT);
  
  pinMode(SDCARD_CS, OUTPUT);
  digitalWrite(SDCARD_CS, HIGH); // Deselect the SD card
  Blynk.begin(auth, IPAddress(192,168,10,2)); // For more options, see Boards_Ethernet/Arduino_Ethernet_Manual example

  tireSensorOffset = tireOffsetCalibration();
  loadParamFromEEPROM();
}

void loop()
{
  if(backgroundTasksTimeThres < millis())
  {
    backgroundTasks();
  } 
  if(TireTimeThres < millis())
  { 
    tirePressureControl();      
  }
  if(tankPressureLCDTimeThres < millis())
  {
    printTankPressureLCD();
  }
  Blynk.run();
}
/////////////////////////////////////////////////////////////////////////////////////////////////
void backgroundTasks()
{
  backgroundTasksTimeThres = millis() + FRONT_PANEL_TIME_THRES_PERIOD;
  readTankPress();
  updatingSetPoint();
  updatingALLOrIndividualSwitch();
  updatingFrontPanelLED();

  // Method to capture set point changes in all-within-tolerance mode where the period is very slow
  if (isAllWithinTol && (abs(setPoint - withinTolSetPoint) > WITHIN_TOL_SET_POINT_THRESHOLD))
  {
    TireTimeThres = 0; // Measure the next channel immediately
    withinTolSetPoint = setPoint; // So that this is only caught once - not four times
  }

  // Tank functions - only read sensor when tankValve is closed
  if (isValve5Closed == true)
  {
    readTankPress();
  }
}

void tirePressureControl()
{
  switch (tireState)
  {
    case firstMeasurementOngoing:
      takeOneMoreMeasurement();
      if (numOfMeasCounter >= numberOfMeasurementsInUse)
      {
        tireState = firstMeasurementDone;
      }
      break;

    case firstMeasurementDone:
      if (maxPressureReading - minPressureReading > FILTER_THRESHOLD && isShortFilterActive == true)
      {
        isShortFilterActive = false;
        tireState = firstMeasurementOngoing;
        numberOfMeasurementsInUse = NUM_OF_MEASUREMENTS_LONG_FILTER;
      }
      else
      {
        valveControl(CLOSE_ALL);
        isShortFilterActive = true;
        maxPressureReading = 0;
        minPressureReading = 1023;
        firstMeasurementPressure = calcAverage();
        numberOfMeasurementsInUse = NUM_OF_MEASUREMENTS_SHORT_FILTER;
        displayTirePress(firstMeasurementPressure);
        decideWhatToDo(firstMeasurementPressure);
        updateAllWithinTol();
      }
      break;

    case allWithinTolWaiting:
      valveControl(MEASURE);
      TireTimeThres = millis() + SETTLING_TIME;
      tireState = firstMeasurementOngoing;
      break;

    case inflationDeflationDone:


      if (activeTire == 60)
      {
        tireState = firstMeasurementOngoing;
      }
      else
      {
        tireState = secondMeasurementOngoing;
      }
      valveControl(MEASURE);
      TireTimeThres = millis() + SETTLING_TIME;
      break;

    case secondMeasurementOngoing:
      takeOneMoreMeasurement();
      if (numOfMeasCounter >= numberOfMeasurementsInUse)
      {
        tireState = secondMeasurementDone;
      }
      break;

    case secondMeasurementDone:
      if (maxPressureReading - minPressureReading > FILTER_THRESHOLD && isShortFilterActive == true)
      {
        isShortFilterActive = false;
        tireState = secondMeasurementOngoing;
        numberOfMeasurementsInUse = NUM_OF_MEASUREMENTS_LONG_FILTER;
      }
      else
      {
        isShortFilterActive = true;
        maxPressureReading = 0;
        minPressureReading = 1023;
        secondMeasurementPressure = calcAverage();
        numberOfMeasurementsInUse = NUM_OF_MEASUREMENTS_SHORT_FILTER;
        displayTirePress(secondMeasurementPressure);
        changeToNextChannel();
        updatingControlParameters();
        valveControl(MEASURE);
        TireTimeThres = millis() + SETTLING_TIME;
        tireState = firstMeasurementOngoing;
      }
      break;
  }
}

////////////// Support functions: ///////////////////////////
void readTankPress()
{
  tankPress = (float)(analogRead(PIN_MPX5700) - OFFSET_MPX5700) * BITS_TO_PSIUNIT_MXP5700;
}

void changeToNextChannel()
{
  // 0 - 3 = independent channels, 4 = front (0-1 ch), 5 rear (2-3 ch), 6 all channels
  if (isIndependentEnabled == true)
  {
    activeTire = (activeTire + 1) % 4;
  }
  else if (frontAxleOffset == 0)
  {
    activeTire = 6;
  }
  else
  {
    if (activeTire == 5)
    {
      activeTire = 4;
    }
    else
    {
      activeTire = 5;
    }
  }
}

void printTankPressureLCD()
{
  tankPressureLCDTimeThres = millis() + TANK_PRESS_BLINK_DELAY;

  if (tankPress > TANKPRESSURE_BLINK_LIMIT || tankBlink == false)
  {
    // Print number
    lcd.print(0, 1, (tankPress + 5)); // 5 is so the rounding will be correct and 100 is because of the way the pressure is stored
    tankBlink = true;
  }
  else
  {
    tankBlink = false;
    lcd.print(0, 1, "  -  ");
  }
}

void updatingSetPoint()
{
  uint16_t newPotRaw = analogRead(PIN_POT);

  if (abs(newPotRaw - currentPotRaw) > 10 ) // POT hysteresis
  {
    uint16_t newSetPoint = potToPSI(newPotRaw);
    if ( newSetPoint != setPoint)
    {
      setPoint = newSetPoint;
      currentPotRaw = newPotRaw;
      isSetPointChanged = true;
      if (setPoint < 995)
      lcd.print(0, 0 ,((float)setPoint));
    }
  }
}

uint16_t potToPSI(uint16_t potRaw)
{
  uint16_t output = 0;

  if (potRaw < POT_NONLINEAR_THRES)
  {
    output = map(potRaw, MIN_POT_COUNT, POT_NONLINEAR_THRES - 1, 0, 499);
  }
  else
  {
    output = map(potRaw, POT_NONLINEAR_THRES, MAX_POT_COUNT, 500, SETPOINT_MAXIMUM_PSI * 100);
  }
  // Round of numbers higher than 500 (5 PSI)
  if (output > 500)
  {
    output = (output / (int)100) * (int)100;
  }
  else
  {
    output = (output / (int)50) * (int)50;
  }

  if (output < 50)
  {
    output = 25;
  }
  return output;
}

void updatingALLOrIndividualSwitch()
{
  boolean allIndiSwitchEnabled = digitalRead(PIN_ALL_INDI);
  if (allIndiSwitchEnabled && !isIndependentEnabled)
  {
    activeTire = 0;
    isIndependentEnabled = true;
    TireTimeThres = 0;
    allWithinTolCounter = 0;
    isAllWithinTol = 0;
    valveControl(CLOSE_ALL);
  }
  else if (!allIndiSwitchEnabled && isIndependentEnabled)
  {
    activeTire = 6;
    isIndependentEnabled = false;
    TireTimeThres = 0;
    allWithinTolCounter = 0;
    isAllWithinTol = 0;
    valveControl(CLOSE_ALL);
  }
}

void updatingFrontPanelLED()
{
  if (isAllWithinTol)
  {
    digitalWrite(PIN_GREEN_LED, 1);
  }
  else
  {
    digitalWrite(PIN_GREEN_LED, 0);
  }
}

void takeOneMoreMeasurement()
{
  uint16_t temp = analogRead(PIN_MPX4250) - tireSensorOffset;
  if (temp > maxPressureReading)
  {
    maxPressureReading = temp;
  }
  if (temp < minPressureReading)
  {
    minPressureReading = temp;
  }
  summedPressure = summedPressure + temp;
  numOfMeasCounter += 1;
  TireTimeThres = millis() + TIME_BETW_MEAS;
}

uint16_t calcAverage()
{

  numOfMeasCounter = 0;
  int16_t currentPressure = (float)(summedPressure / numberOfMeasurementsInUse) * BITS_TO_PSIUNIT_MXP4250;
  if ( currentPressure < 0 )
  {
    currentPressure = 0;
  }
  summedPressure = 0;
  return currentPressure;
}

void displayTirePress(uint16_t currentPressure)
{
  float printOutPress = (float)currentPressure / (float)100;

  if (currentPressure > 37000) // This is to eliminate "negative" pressure
  {
    currentPressure = 0;
  }

  uint8_t isCurrentPressBelow10psi = currentPressure < 995;
  uint8_t startChannel = 0;
  uint8_t endChannel = 0;
  switch (activeTire)
  {
    case 0:
      channel0 = currentPressure;
      startChannel = activeTire;
      endChannel = activeTire;
      isChBelow10PSI[activeTire] = isCurrentPressBelow10psi;
      break;
    case 1:
      channel1 = currentPressure;
      startChannel = activeTire;
      endChannel = activeTire;
      isChBelow10PSI[activeTire] = isCurrentPressBelow10psi;
      break;
    case 2:
      channel2 = currentPressure;
      startChannel = activeTire;
      endChannel = activeTire;
      isChBelow10PSI[activeTire] = isCurrentPressBelow10psi;
      break;
    case 3:
      channel3 = currentPressure;
      startChannel = activeTire;
      endChannel = activeTire;
      isChBelow10PSI[activeTire] = isCurrentPressBelow10psi;
      break;
    case 4:
      channel0 = currentPressure;
      channel1 = currentPressure;
      startChannel = 0;
      endChannel = 1;
      isChBelow10PSI[0] = isCurrentPressBelow10psi;
      isChBelow10PSI[1] = isCurrentPressBelow10psi;
      break;
    case 5:
      channel2 = currentPressure;
      channel3 = currentPressure;
      startChannel = 2;
      endChannel = 3;
      isChBelow10PSI[2] = isCurrentPressBelow10psi;
      isChBelow10PSI[3] = isCurrentPressBelow10psi;
      break;
    case 6:
      channel0 = currentPressure;
      channel1 = currentPressure;
      channel2 = currentPressure;
      channel3 = currentPressure;
      startChannel = 0;
      endChannel = 3;
      isChBelow10PSI[0] = isCurrentPressBelow10psi;
      isChBelow10PSI[1] = isCurrentPressBelow10psi;
      isChBelow10PSI[2] = isCurrentPressBelow10psi;
      isChBelow10PSI[3] = isCurrentPressBelow10psi;
      break;
  }

  for (uint8_t i = startChannel; i < endChannel + 1; i++)
  {
    
    if (printOutPress < 9.95) // This is for alignment of decimal point on screen
    lcd.print(6, 0,  printOutPress);
    lcd.print(12, 0, printOutPress);
    lcd.print(6, 1, printOutPress);
    lcd.print(12, 1, printOutPress);
  }
}

void updateAllWithinTol()
{
  uint8_t numberOfChannelsInUse = 0;
  switch (activeTire)
  {
    case 0:
    case 1:
    case 2:
    case 3:
      numberOfChannelsInUse = 3;
      break;
    case 4:
    case 5:
      numberOfChannelsInUse = 2;
      break;
    case 6:
      numberOfChannelsInUse = 1;
      break;
  }
  if (allWithinTolCounter >= numberOfChannelsInUse && !isAllWithinTol)
  {
    isAllWithinTol = true;
    withinTolSetPoint = setPoint;
    isSetPointChanged = false;
  }
  else if (allWithinTolCounter < numberOfChannelsInUse)
  {
    isAllWithinTol = false;
  }
}

uint16_t calculateDeflationTime(uint16_t currentPressure)
{
  uint16_t deflationParamInUse = 0;
  switch (activeTire)
  {
    case 0:
    case 1:
    case 2:
    case 3:
      deflationParamInUse = singleChannelDeflationParam;
      break;
    case 4:
      deflationParamInUse = frontChannelsDeflationParam;
      break;
    case 5:
      deflationParamInUse = rearChannelsDeflationParam;
      break;
    case 6:
      deflationParamInUse = allChannelsDeflationParam;
      break;
  }

  uint16_t timeMilliSec = ((deflationParamInUse * 10) / log( (float)currentPressure / (float)setPoint )) + VALVE_OPENING_TIME;
  if (timeMilliSec > MAX_DEFLATION_TIME)
  {
    timeMilliSec =  MAX_DEFLATION_TIME;
  }
  return timeMilliSec;
}

uint16_t calculateInflationTimeMS(uint16_t currentPressure)
{
  uint16_t inflationParamInUse = 0;
  switch (activeTire)
  {
    case 0:
    case 1:
    case 2:
    case 3:
      inflationParamInUse = singleChannelInflationParam;
      break;
    case 4:
      inflationParamInUse = frontChannelsInflationParam;
      break;
    case 5:
      inflationParamInUse = rearChannelsInflationParam;
      break;
    case 6:
      inflationParamInUse = allChannelsInflationParam;
      break;
  }

  uint16_t timeMilliSec = ((float)( setPoint - currentPressure ) * ( inflationParamInUse / 100 ) ) + VALVE_OPENING_TIME;
  if (timeMilliSec > MAX_INFLATION_TIME)
  {
    timeMilliSec =  MAX_INFLATION_TIME;
  }
  return timeMilliSec;
}

void decideWhatToDo(int16_t currentPressure)
{
  int16_t difference = currentPressure - setPoint;
  if (activeTire == 0 || activeTire == 1 || activeTire == 4)
  {
    difference = difference - frontAxleOffset;
  }
  if (abs(difference) > TOLERANCE) // Last measurement not within tolerance
  {
    allWithinTolCounter = 0;
    if (difference > 0)
    {
      valveControl(DEFLATE);
      deflationTime = calculateDeflationTime(currentPressure);
      TireTimeThres = millis() + deflationTime;
    }
    else if (1)  //tankPress > 3000) // inflation only performed if tank press > 30 psi
    {
      valveControl(INFLATE);
      inflationTime = calculateInflationTimeMS(currentPressure);
      TireTimeThres = millis() + inflationTime;
    }
    tireState = inflationDeflationDone;
  }
  else // Last measurement within tolerance
  {
    allWithinTolCounter += 1;
    changeToNextChannel();

    if (isAllWithinTol && allWithinTolCounter > STAND_BY_THRESHOLD)
    {
      closeAllValves();
      TireTimeThres = millis() + (STAND_BY_MULTIPLAYER * ALL_WITHIN_TOL_WAIT_TIME);
      tireState = allWithinTolWaiting;
    }
    else if (isAllWithinTol)
    {
      closeAllValves();
      if (activeTire == 6)
      {
        openActiveTireValve();
      }
      TireTimeThres = millis() + ALL_WITHIN_TOL_WAIT_TIME;
      tireState = allWithinTolWaiting;
    }
    else
    {
      valveControl(MEASURE);
      TireTimeThres = millis() + SETTLING_TIME;
      tireState = firstMeasurementOngoing;
    }
  }
}

void openActiveTireValve()
{
  switch (activeTire)
  {
    case 0:
      digitalWrite(PIN_VALVE1, HIGH);
      break;
    case 1:
      digitalWrite(PIN_VALVE2, HIGH);
      break;
    case 2:
      digitalWrite(PIN_VALVE3, HIGH);
      break;
    case 3:
      digitalWrite(PIN_VALVE4, HIGH);
      break;
    case 4:
      digitalWrite(PIN_VALVE1, HIGH);
      digitalWrite(PIN_VALVE2, HIGH);
      break;
    case 5:
      digitalWrite(PIN_VALVE3, HIGH);
      digitalWrite(PIN_VALVE4, HIGH);
      break;
    case 6:
      digitalWrite(PIN_VALVE1, HIGH);
      digitalWrite(PIN_VALVE2, HIGH);
      digitalWrite(PIN_VALVE3, HIGH);
      digitalWrite(PIN_VALVE4, HIGH);
      break;
  }
}

void closeAllValves()
{
  digitalWrite(PIN_VALVE0, LOW);
  digitalWrite(PIN_VALVE1, LOW);
  digitalWrite(PIN_VALVE2, LOW);
  digitalWrite(PIN_VALVE3, LOW);
  digitalWrite(PIN_VALVE4, LOW);
  digitalWrite(PIN_VALVE5, LOW);
}

void valveControl(int command)
{
  closeAllValves();
  isValve5Closed = true;
  switch (command)
  {
    case CLOSE_ALL:
      // Empty on purpose
      break;
    case MEASURE:
      openActiveTireValve();
      break;
    case INFLATE:
      isInflating = true;
      openActiveTireValve();
      digitalWrite(PIN_VALVE5, HIGH);
      isValve5Closed = false;
      break;
    case DEFLATE:
      isDeflating = true;
      openActiveTireValve();
      digitalWrite(PIN_VALVE0, HIGH);
      break;
    case CALIBRATION:
      digitalWrite(PIN_VALVE0, HIGH);
      break;
  }
}

uint16_t tireOffsetCalibration()
{
  valveControl(CALIBRATION);
  delay(2 * SETTLING_TIME);
  uint16_t temp = 0;
  for (int8_t i = 0; i < NUM_OF_MEASUREMENTS_SHORT_FILTER; i = i + 1)
  {
    temp = temp + analogRead(PIN_MPX4250);
    delay(TIME_BETW_MEAS);
  }
  uint16_t tireSensorOffset = (temp / NUM_OF_MEASUREMENTS_SHORT_FILTER);
  valveControl(CLOSE_ALL);
  delay(2 * SETTLING_TIME);
  return tireSensorOffset;
}



void writeParamToEEPROM()
{
  // Unfinished function
}

void loadParamFromEEPROM()
{
  singleChannelDeflationParam = EEPROM.read(SINGLE_CHANNEL_DEFLATION_PARAM_ADDRESS);
  singleChannelInflationParam = EEPROM.read(SINGLE_CHANNEL_INFLATION_PARAM_ADDRESS);
  frontChannelsDeflationParam = EEPROM.read(FRONT_CHANNELS_DEFLATION_PARAM_ADDRESS);
  frontChannelsInflationParam = EEPROM.read(FRONT_CHANNELS_DEFLATION_PARAM_ADDRESS);
  rearChannelsDeflationParam = EEPROM.read(REAR_CHANNELS_DEFLATION_PARAM_ADDRESS);
  rearChannelsInflationParam = EEPROM.read(REAR_CHANNELS_DEFLATION_PARAM_ADDRESS);
  allChannelsDeflationParam = EEPROM.read(ALL_CHANNELS_DEFLATION_PARAM_ADDRESS);
  allChannelsInflationParam = EEPROM.read(ALL_CHANNELS_DEFLATION_PARAM_ADDRESS);
}

void updatingControlParameters()
{
  if (isDeflating && isInflating)
  {
    // Error: should not happen
  }
  else if (isDeflating && deflationTime > 0 && (firstMeasurementPressure - secondMeasurementPressure) > 0)
  {
    uint16_t newDeflationParam = deflationTime / log( (float)firstMeasurementPressure / (float)secondMeasurementPressure) / 10;

    switch (activeTire)
    {
      case 0:
      case 1:
      case 2:
      case 3:
        singleChannelDeflationParam = newDeflationParam;
        break;
      case 4:
        frontChannelsDeflationParam = newDeflationParam;
        break;
      case 5:
        rearChannelsDeflationParam = newDeflationParam;
        break;
      case 6:
        allChannelsDeflationParam = newDeflationParam;
        break;
    }

  }
  else if (isInflating && inflationTime > 0 && (secondMeasurementPressure > firstMeasurementPressure))
  {
    uint16_t newInflationParam = inflationTime / (float)(secondMeasurementPressure - firstMeasurementPressure) * 100;

    switch (activeTire)
    {
      case 0:
      case 1:
      case 2:
      case 3:
        singleChannelInflationParam = newInflationParam;
        break;
      case 4:
        frontChannelsInflationParam = newInflationParam;
        break;
      case 5:
        rearChannelsInflationParam = newInflationParam;
        break;
      case 6:
        allChannelsInflationParam = newInflationParam;
        break;
    }
  }
  isDeflating = false;
  isInflating = false;
  if ( EEPROMTimeThres < millis() )
  {
    EEPROMTimeThres = millis() + 5000;
    writeParamToEEPROM();
  }
}

int16_t updateFrontAxleOffset()
{
  closeAllValves();
  int16_t offset = 0;
  for (uint8_t i = 0; i < 20; i++)
  {
    offset = map(analogRead(PIN_POT), 0, 1023, -8, 8) * 50; // range from -4 to 4 psi with 0,5 psi resolution
    if (offset >= 0)
    lcd.print(12, 0, (float)offset);
    delay(250);
  }
  return offset;
}

wow, man, i didn’t seen sooo much variables in a single sketch in my whole life :fearful:

are you sure they are REALLY needed?
for me, this sketch is very confusing. however, just by random, i have some observations:

there is no really needed to assign 0 to variables. if you write only this:

uint16_t currentPotRaw;  //Current set point POT raw value 
int16_t withinTolSetPoint;  //[Tire pressure storage unit]
int16_t summedPressure;

they will have the value of 0 anyway. also, i like to declare variables the same types in same places, in increasing order of memory footprint. so, i would declare first all global bools, then all global bytes, ints, floats, longs, etc. for me it is more logical and maintainable.

afaik, this is not (very) correct. every switch case should have at least a break; statement, and it is recommended to have a default case. read on here if you mind.

instead constants, i like it better to use #defines (yes, the arduino docs aren’t recommend them, but if one understands how are they working, i think they are actually better to use)

this could be:

#define FILTER_THRESHOLD 100  // raw ADC value

in some cases they could use less memory and it seems more cleaner to me

for cases like this, you just should use a for cycle.

for overall code organisation and control, in arduino ide i highly recommend for everyone to use tabs. short explanation here:

@wanek
Have you read the first post?
If not then the question to read it :sunglasses:

should I change all like const int16_t in #define or?

But yes this is good and valid questions with you and the worst is that I do not know the answers :slight_smile:

I did not write this, and this is set up for other equipment but still Arduino in the base.

Have not learn this programming language and know little and that’s why I ask for help and what can be done better in this code to use with Blynk app, and one you can see I’ve got pretty far :slight_smile:

okay, i have read the first post, and just run through really fast the attached pdf.
:slight_smile:

this is a big project, and as i understand you’re not a coder?
it is always difficult task (even for experienced programmers) to take over and fully understand an existing code


regarding this: “should I change all like const int16_t in #define”, i would say yes, BUT only after you read some detailed explanation what #define does. anyway, this is only my opinion, and i’m not an experienced coder. you should ask others, like @Costas, what they recommend.

based on the experience i have so far, if i were you, i would begin with trying to understand and analyse what the existing code is doing and how it works. no matter what you’re trying to do in the future, this is essential.

then, i would organise the code, in your case, learning and using the ide tabs, it would be really really usefull. read the article in my link. then make a backup copy of the current code, then begin to tear apart in functions. put every function into individual tabs.

maybe you’re a bit impatient right now, to make the code working with blynk and see results. but just take your time to analyse and organise the old code, it will payback in the long run - for you and even for people who will try to help you on forums. (if someone sees that you have a clean organised code and at least a basic idea what it is doing, will be favourably inclined towards helping you)

1 Like

yes this is all coming :slight_smile: and thanks for taking the time and everyone here.

I know what this equipment does and how it should work because I have seen him work in a car in Iceland, have constructed other equipment he was using manual valves :slight_smile:

Is beginning to see that it works most with me now, I’m reading and learning :relaxed:
This is not new in Iceland than using Blynk app is new.
the person who wrote this code would not help and would not help with these changes :unamused:
Has been going over this above thanks from you.
the issue completely send me osteomalacia ideas hehehe :smile:

My idea would be to start fro scratch. As @wanek more or less indicated, this is a somewhat complex piece of code. I see a lot of room for improvement and efficiency increase.

The first thing that comes to mind is to get rid of all the millis() things and instead switch to SimpleTimer. This is easier said than done because I can’t really make heads or tail from what the timed things do.

I’m going to read the thesis form your friend because it’s a very interesting project and I want to know more about it. I’ll then come up with some suggestions, hopefully, to create something usable.

But as I said, it may be easier to start from scratch and implement this code directly in a “Blynk” approved manner using SImpleTimer and other neat tricks like the LCD.

1 Like

@Lichtsignaal thanks
Yes this is interesting project.

@Lichtsignaal I’m using direct milis() for timing quite often, and sometimes it is easier to use than SimpleTimer (which I’m using either). My thoughts are, that this code flow is not that bad and for beginner @Eyberg it would be really easier to track and modify existing code - especially if it is tested and confirmed to work at least properly. Don’t give up @Eyberg! I must admit I’m not a professional coder at all, hence a lot of my project arose from modified existing examples, libraries, etc

Why @Lichtsignaal you think a Simple timer would work better here? Correct me IF WRONG, but It’s based on the same principle, I mean in library there is “hidden” exactly the same method as used here So:

  • Register the time at some point - a milis() is used here too,
  • Do things

  • check if a preset amount of time had passed by comparing millis() with registered value
1 Like

SimpleTImer is, well honestly, more simple to use than figuring out all the millis() stuff. I agree that it is the same principle and the mentioned code is pretty well written, but not optimized for Blynk. When I say “start from scratch” I actually mean setup a simple Blynk project and copy function by function into the new sketch and thus confirm everything keeps working. For example, there is something with the added LCD widget now which causes a flood error, so there is definitely something not Blynk optimized :slight_smile:

I don’t have much time at this moment (and the thesis is not in my native tongue and it’s very technical, so that will take some time).

1 Like

Then I solved the flood error, measurements of tire were 50ms and I put it in the 250m and then acts void loop () and do not crash:sunglasses:

have not found a solution to reduce the zero occurring on the screen?
For example, it comes from the pressure gauge 0.0000 but I prefer 0.0 in LCD.
Any ideas?

Now I need me a little coda to use Slider or Step Control to send from Blynk app to A5 (analog5) to install SetPoint from 2PSI to 35PSI max.
The original program is used manual Potentiometer 10k!

Has been read to me about writing and reading in virtual but did not manage to finish this but to try me on, but good to get tips here from you guys :grinning:

Yes, the flooding here is or will be a problem. Certainly calling to vLCD requires timing to avoid that. All reporting to APP could (or perhaps even should) be moved to a separate timed function, where indeed SimpleTimer can be proper choice. Or check, if it cannot be done “in place”, and analyze the proper position in the code to “refresh” the vLCD. Then again, using function you need to pass arguments to that function where with SimpleTimer you need to do that by globals (?). Aaargh
! It must be easy, but not when not watching at the code! :slight_smile:
But as most of the code is timed and a lot variables are involved the rest (i.e control from app side) should be as easy as adding proper BLYNK_WRITE() handlers. Personally would use the existing code as I’m “the lazy one”, but feel free to create it from scratch. :slight_smile:
@Eyberg: I must admit, that beginning a joy with Blynk (and coding at all) with this project was a brave decision :wink: But there’s nothing more flexible in this world than human’s brain, so sooner or later YOU WILL DO THAT if you want to.

1 Like

@marvin7 thanks :slight_smile:

when someone says to me that you can not do this because you know nothing of the program and has never worked with this then I just learn and implement what I want :slight_smile:

so are you here quite great help :slight_smile:

Here is the latest version of the code.

But is not managing to write the value from the Slider to void updatingSetPoint ()

/**************************************************************
 * Blynk is a platform with iOS and Android apps to control
 * Arduino, Raspberry Pi and the likes over the Internet.
 * You can easily build graphic interfaces for all your
 * projects by simply dragging and dropping widgets.
 *
 *   Downloads, docs, tutorials: http://www.blynk.cc
 *   Sketch generator:           http://examples.blynk.cc
 *   Blynk community:            http://community.blynk.cc
 *   Social networks:            http://www.fb.com/blynkapp
 *                               http://twitter.com/blynk_app
 *
 * Blynk library is licensed under MIT license
 * This example code is in public domain.
 *
 **************************************************************
 *
 * This example shows how to use Arduino Ethernet shield (W5100)
 * to connect your project to Blynk.
 * Feel free to apply it to any other example. It's simple!
 *
 * NOTE: Pins 10, 11, 12 and 13 are reserved for Ethernet module.
 *       DON'T use them in your sketch directly!
 *
 * WARNING: If you have an SD card, you may need to disable it
 *       by setting pin 4 to HIGH. Read more here:
 *       https://www.arduino.cc/en/Main/ArduinoEthernetShield
 *
 **************************************************************/

#define BLYNK_PRINT Serial    // Comment this out to disable prints and save space
#include <SPI.h>
#include <Ethernet.h>
#include <BlynkSimpleEthernet.h>
#include <EEPROM.h>
#include <inttypes.h>
#include <Wire.h>

//////////////////////////////////////
// Tire pressure : 1 bit = 0.01 PSI //
// Tank pressure : 1 bit = 0.01 PSI //
//////////////////////////////////////

//////// GLOBAL PARAMETERS /////
// Tire pressure control parameters:
const uint8_t TOLERANCE = 5;  //[Tire pressure storage unit] set point tolerance
const uint16_t ALL_WITHIN_TOL_WAIT_TIME = 8000;  //[ms]
const uint8_t TIME_BETW_MEAS = 250;  //[ms] 
const uint8_t NUM_OF_MEASUREMENTS_SHORT_FILTER = 6;  //Number of measurements averaged
const uint8_t NUM_OF_MEASUREMENTS_LONG_FILTER = 50;  //Number of measurements averaged
const uint16_t MAX_DEFLATION_TIME = 6000;  //[ms] 
const uint16_t MAX_INFLATION_TIME = 6000;  //[ms] 
const uint16_t WITHIN_TOL_SET_POINT_THRESHOLD = 10;  //[raw set point bits]
const uint8_t STAND_BY_THRESHOLD = 10; //Stand by threshold 
const uint8_t STAND_BY_MULTIPLAYER = 4;  //Stand by multiplier
const uint16_t SETTLING_TIME = 1000;  //[ms] pressure settling time
const uint16_t VALVE_OPENING_TIME = 70; //[ms]
const float BITS_TO_PSIUNIT_MXP4250 = 3.8425; // 1 bit = 0,038425 psi 
const int16_t FILTER_THRESHOLD = 100;  // raw ADC value
const uint16_t FRONT_AXLE_OFFSET_ADJUST_TIME_LENGTH = 4000;
const uint16_t FRONT_AXLE_OFFSET_LOWER_POT_LIMIT = 50;
const uint16_t FRONT_AXLE_OFFSET_HIGER_POT_LIMIT = 950;

// Tank parameters:
const uint16_t TANKPRESSURE_BLINK_LIMIT = 3000;  //[Tank pressure storage unit]
const uint16_t TANK_PRESS_BLINK_DELAY = 700;  //[ms]
const float BITS_TO_PSIUNIT_MXP5700 = 11.0135;  // 1 bit = 0,110135 psi
const uint16_t OFFSET_MPX5700 = 35;  // 0 - 1024, raw ADC unit

// Front panel parameters:
const uint16_t POT_NONLINEAR_THRES = 700;  // range (0-1023)
const uint16_t FRONT_PANEL_TIME_THRES_PERIOD = 1000;
uint16_t MAX_POT_COUNT = 1020;  //(Not constant) Max output from POT  ATH hĂ©r ĂŸarf aĂ° lĂĄta lesa Ășr EEPROM
uint16_t MIN_POT_COUNT = 0;  //(Not constant) Min output from POT  ATH hĂ©r ĂŸarf aĂ° lĂĄta lesa Ășr EEPROM
const uint8_t SETPOINT_MAXIMUM_PSI = 35;      
const uint8_t PIN_GREEN_LED = A3;
const uint8_t PIN_ALL_INDI = 0;
const uint8_t pinValue = V5;

// Control pins deceleration
const uint8_t PIN_VALVE0 = 9;
const uint8_t PIN_VALVE1 = 3;
const uint8_t PIN_VALVE2 = 5;
const uint8_t PIN_VALVE3 = 6;
const uint8_t PIN_VALVE4 = 7;
const uint8_t PIN_VALVE5 = 8;
const uint8_t PIN_PUMP = 1;

// Sensors
const uint8_t PIN_MPX4250 = A2; 
const uint8_t PIN_MPX5700 = A1;

// EEPROM and control parameters
const uint8_t SINGLE_CHANNEL_DEFLATION_PARAM_ADDRESS = 0;
const uint8_t SINGLE_CHANNEL_INFLATION_PARAM_ADDRESS = 4;
const uint8_t FRONT_CHANNELS_DEFLATION_PARAM_ADDRESS = 8;
const uint8_t FRONT_CHANNELS_INFLATION_PARAM_ADDRESS = 12;
const uint8_t REAR_CHANNELS_DEFLATION_PARAM_ADDRESS = 16;
const uint8_t REAR_CHANNELS_INFLATION_PARAM_ADDRESS = 20;
const uint8_t ALL_CHANNELS_DEFLATION_PARAM_ADDRESS = 24;
const uint8_t ALL_CHANNELS_INFLATION_PARAM_ADDRESS = 28;

// Other constants:
const uint16_t SERIAL_BAUDRATE = 9600;

////////// GLOBAL VARIABLES /////    
// Enum:
enum valveControlCommand {CLOSE_ALL, MEASURE, INFLATE, DEFLATE, CALIBRATION};
enum tireControlState {firstMeasurementOngoing, allWithinTolWaiting, firstMeasurementDone, inflationDeflationDone, secondMeasurementOngoing, secondMeasurementDone};

// Tire pressure control - global variables:
uint8_t activeTire = 0;  //Four tires: 0-3
tireControlState tireState = allWithinTolWaiting;  //Enum
uint16_t tireSensorOffset;  //Raw ADC value
int16_t setPoint = 0;  //[Tire pressure storage unit]
uint16_t currentPotRaw;  //Current set point POT raw value 
int16_t withinTolSetPoint;  //[Tire pressure storage unit]
int16_t summedPressure;  //Temp variable - used to accumulate measurements
boolean isAllWithinTol = false;  //Are all channels within tolerance
uint8_t allWithinTolCounter = 0;  //How many channels have been found in row within tolerance
uint8_t numOfMeasCounter = 0;  //Current number of measurements taken
uint32_t TireTimeThres = 0;  //Tire control time threshold
boolean isChBelow10PSI[4] = {true, true, true, true};
uint16_t firstMeasurementPressure = 0;
uint16_t secondMeasurementPressure = 0;
boolean isDeflating = false;
boolean isInflating = true;
uint16_t deflationTime = 0;
uint16_t inflationTime = 0; 
boolean isSetPointChanged = true;
uint16_t numberOfMeasurementsInUse = NUM_OF_MEASUREMENTS_SHORT_FILTER;
int8_t frontAxleOffset = 0;  // [psi*100] Range -4 to 4 psi ( -400 to 400)
int16_t maxPressureReading = 0;
int16_t minPressureReading = 1023;
uint8_t isShortFilterActive = true;

// Tank pressure control - global variables:
boolean isValve5Closed = true;
int16_t tankPress = 0;  //[Tank pressure storage unit] Current tank pressure
uint32_t tankPressureLCDTimeThres = 0;  //Tank pressure blink time threshold
uint32_t calibrationTankTimeThres = 0;
boolean tankBlink = false; 

// EEPROM and control parameters - global variables:
uint16_t singleChannelDeflationParam = 11000; 
uint16_t singleChannelInflationParam = 1200; 
uint16_t frontChannelsDeflationParam = 11000; 
uint16_t frontChannelsInflationParam = 1200; 
uint16_t rearChannelsDeflationParam = 11000; 
uint16_t rearChannelsInflationParam = 1200; 
uint16_t allChannelsDeflationParam = 11000; 
uint16_t allChannelsInflationParam = 1200; 
uint32_t EEPROMTimeThres = 20000;

// Other - global variables:
uint32_t backgroundTasksTimeThres = 0;  //Front panel time threshold
uint32_t blinkLEDTimeThres = 0;  //Front panel LED blink time threshold
boolean isIndependentEnabled = true;  //Independent channels enabled
uint16_t counter = 0;  //Temp variable for performance test

uint16_t channel0 = 0;
uint16_t channel1 = 0;
uint16_t channel2 = 0;
uint16_t channel3 = 0;

// Global objects:
WidgetLCD lcd(V1);

// You should get Auth Token in the Blynk App.
// Go to the Project Settings (nut icon).
char auth[] = "3295d2122335428a8a8877a04a64367b";

#define W5100_CS  10
#define SDCARD_CS 4

void setup()
{
  Serial.begin(SERIAL_BAUDRATE);
  
  pinMode(PIN_ALL_INDI, INPUT);
  pinMode(pinValue, INPUT);
  pinMode(PIN_GREEN_LED, OUTPUT);
  pinMode(PIN_VALVE0, OUTPUT);
  pinMode(PIN_VALVE1, OUTPUT);
  pinMode(PIN_VALVE2, OUTPUT);
  pinMode(PIN_VALVE3, OUTPUT);
  pinMode(PIN_VALVE4, OUTPUT);
  pinMode(PIN_VALVE5, OUTPUT);
  pinMode(PIN_PUMP, OUTPUT);
  pinMode(SDCARD_CS, OUTPUT);

  digitalWrite(SDCARD_CS, HIGH); // Deselect the SD card
  Blynk.begin(auth, IPAddress(192,168,10,2)); // For more options, see Boards_Ethernet/Arduino_Ethernet_Manual example

tireSensorOffset = tireOffsetCalibration();
  loadParamFromEEPROM();
}
  BLYNK_CONNECTED() {
    Blynk.syncAll();
}

BLYNK_WRITE(V5)
{
  int pinValue = param.asInt(); // assigning incoming value from pin V5 to a variable
  // You can also use:
  // String i = param.asStr();
  // double d = param.asDouble();
  Serial.print("V5 Slider value is: ");
  Serial.println(pinValue);
}

void loop()
{
  if(backgroundTasksTimeThres < millis())
  {
    backgroundTasks();
  } 
  if(TireTimeThres < millis())
  { 
    tirePressureControl();      
  }
  if(tankPressureLCDTimeThres < millis())
  {
    printTankPressureLCD();
  }
  Blynk.run();
}
/////////////////////////////////////////////////////////////////////////////////////////////////
void backgroundTasks()
{
  backgroundTasksTimeThres = millis() + FRONT_PANEL_TIME_THRES_PERIOD;
  readTankPress();
  updatingSetPoint();
  updatingALLOrIndividualSwitch();
  updatingFrontPanelLED();

  // Method to capture set point changes in all-within-tolerance mode where the period is very slow
  if (isAllWithinTol && (abs(setPoint - withinTolSetPoint) > WITHIN_TOL_SET_POINT_THRESHOLD))
  {
    TireTimeThres = 0; // Measure the next channel immediately
    withinTolSetPoint = setPoint; // So that this is only caught once - not four times
  }

  // Tank functions - only read sensor when tankValve is closed
  if (isValve5Closed == true)
  {
    readTankPress();
  }
}

void tirePressureControl()
{
  switch (tireState)
  {
    case firstMeasurementOngoing:
      takeOneMoreMeasurement();
      if (numOfMeasCounter >= numberOfMeasurementsInUse)
      {
        tireState = firstMeasurementDone;
      }
      break;

    case firstMeasurementDone:
      if (maxPressureReading - minPressureReading > FILTER_THRESHOLD && isShortFilterActive == true)
      {
        isShortFilterActive = false;
        tireState = firstMeasurementOngoing;
        numberOfMeasurementsInUse = NUM_OF_MEASUREMENTS_LONG_FILTER;
      }
      else
      {
        valveControl(CLOSE_ALL);
        isShortFilterActive = true;
        maxPressureReading = 0;
        minPressureReading = 1023;
        firstMeasurementPressure = calcAverage();
        numberOfMeasurementsInUse = NUM_OF_MEASUREMENTS_SHORT_FILTER;
        displayTirePress(firstMeasurementPressure);
        decideWhatToDo(firstMeasurementPressure);
        updateAllWithinTol();
      }
      break;

    case allWithinTolWaiting:
      valveControl(MEASURE);
      TireTimeThres = millis() + SETTLING_TIME;
      tireState = firstMeasurementOngoing;
      break;

    case inflationDeflationDone:


      if (activeTire == 60)
      {
        tireState = firstMeasurementOngoing;
      }
      else
      {
        tireState = secondMeasurementOngoing;
      }
      valveControl(MEASURE);
      TireTimeThres = millis() + SETTLING_TIME;
      break;

    case secondMeasurementOngoing:
      takeOneMoreMeasurement();
      if (numOfMeasCounter >= numberOfMeasurementsInUse)
      {
        tireState = secondMeasurementDone;
      }
      break;

    case secondMeasurementDone:
      if (maxPressureReading - minPressureReading > FILTER_THRESHOLD && isShortFilterActive == true)
      {
        isShortFilterActive = false;
        tireState = secondMeasurementOngoing;
        numberOfMeasurementsInUse = NUM_OF_MEASUREMENTS_LONG_FILTER;
      }
      else
      {
        isShortFilterActive = true;
        maxPressureReading = 0;
        minPressureReading = 1023;
        secondMeasurementPressure = calcAverage();
        numberOfMeasurementsInUse = NUM_OF_MEASUREMENTS_SHORT_FILTER;
        displayTirePress(secondMeasurementPressure);
        changeToNextChannel();
        updatingControlParameters();
        valveControl(MEASURE);
        TireTimeThres = millis() + SETTLING_TIME;
        tireState = firstMeasurementOngoing;
      }
      break;
  }
}

////////////// Support functions: ///////////////////////////
void readTankPress()
{
  tankPress = (float)(analogRead(PIN_MPX5700) - OFFSET_MPX5700) * BITS_TO_PSIUNIT_MXP5700;
}

void changeToNextChannel()
{
  // 0 - 3 = independent channels, 4 = front (0-1 ch), 5 rear (2-3 ch), 6 all channels
  if (isIndependentEnabled == true)
  {
    activeTire = (activeTire + 1) % 4;
  }
  else if (frontAxleOffset == 0)
  {
    activeTire = 6;
  }
  else
  {
    if (activeTire == 5)
    {
      activeTire = 4;
    }
    else
    {
      activeTire = 5;
    }
  }
}

void printTankPressureLCD()
{
  tankPressureLCDTimeThres = millis() + TANK_PRESS_BLINK_DELAY;

  if (tankPress > TANKPRESSURE_BLINK_LIMIT || tankBlink == false)
  {
    //Printing space if needed
    if(tankPress < 9)
    
    // Print number
    lcd.print(0, 1, (tankPress + 5)/100); // 5 is so the rounding will be correct and 100 is because of the way the pressure is stored
    tankBlink = true;
  }
  else
  {
    tankBlink = false;
    lcd.print(0, 1, "E");
  }
}

void updatingSetPoint()
{
  uint16_t newPotRaw = pinValue;

  if (abs(newPotRaw - currentPotRaw) ) // POT hysteresis
  {
    uint16_t newSetPoint = potToPSI(newPotRaw);
    if ( newSetPoint != setPoint)
    {
      setPoint = newSetPoint;
      currentPotRaw = newPotRaw;
      isSetPointChanged = true;
      //lcd.print(0, 0, setPoint);
      if (setPoint < 995)
      {
        lcd.print(0, 0, setPoint); // This is for alignment of decimal point on screen
        Serial.println(setPoint);
      }
      lcd.print(0, 0,((float)setPoint) /100);
      Serial.println(setPoint);
    }
  }
}

uint16_t potToPSI(uint16_t potRaw)
{
  uint16_t output = 0;

  if (potRaw < POT_NONLINEAR_THRES)
  {
    output = map(potRaw, MIN_POT_COUNT, POT_NONLINEAR_THRES - 1, 0, 499);
  }
  else
  {
    output = map(potRaw, POT_NONLINEAR_THRES, MAX_POT_COUNT, 500, SETPOINT_MAXIMUM_PSI * 100);
  }
  // Round of numbers higher than 500 (5 PSI)
  if (output > 500)
  {
    output = (output / (int)100) * (int)100;
  }
  else
  {
    output = (output / (int)50) * (int)50;
  }

  if (output < 50)
  {
    output = 25;
  }
  return output;
}

void updatingALLOrIndividualSwitch()
{
  boolean allIndiSwitchEnabled = digitalRead(PIN_ALL_INDI);
  if (allIndiSwitchEnabled && !isIndependentEnabled)
  {
    activeTire = 0;
    isIndependentEnabled = true;
    TireTimeThres = 0;
    allWithinTolCounter = 0;
    isAllWithinTol = 0;
    valveControl(CLOSE_ALL);
  }
  else if (!allIndiSwitchEnabled && isIndependentEnabled)
  {
    activeTire = 6;
    isIndependentEnabled = false;
    TireTimeThres = 0;
    allWithinTolCounter = 0;
    isAllWithinTol = 0;
    valveControl(CLOSE_ALL);
  }
}

void updatingFrontPanelLED()
{
  if (isAllWithinTol)
  {
    digitalWrite(PIN_GREEN_LED, 1);
  }
  else
  {
    digitalWrite(PIN_GREEN_LED, 0);
  }
}

void takeOneMoreMeasurement()
{
  uint16_t temp = analogRead(PIN_MPX4250) - tireSensorOffset;
  if (temp > maxPressureReading)
  {
    maxPressureReading = temp;
  }
  if (temp < minPressureReading)
  {
    minPressureReading = temp;
  }
  summedPressure = summedPressure + temp;
  numOfMeasCounter += 1;
  TireTimeThres = millis() + TIME_BETW_MEAS;
}

uint16_t calcAverage()
{

  numOfMeasCounter = 0;
  int16_t currentPressure = (float)(summedPressure / numberOfMeasurementsInUse) * BITS_TO_PSIUNIT_MXP4250;
  if ( currentPressure < 0 )
  {
    currentPressure = 0;
  }
  summedPressure = 0;
  return currentPressure;
}

void displayTirePress(uint16_t currentPressure)
{
  float printOutPress = (float)currentPressure / (float)100;

  if (currentPressure > 37000) // This is to eliminate "negative" pressure
  {
    currentPressure = 0;
  }

  uint8_t isCurrentPressBelow10psi = currentPressure < 9.95;
  uint8_t startChannel = 0;
  uint8_t endChannel = 0;
  switch (activeTire)
  {
    case 0:
      channel0 = currentPressure;
      startChannel = activeTire;
      endChannel = activeTire;
      isChBelow10PSI[activeTire] = isCurrentPressBelow10psi;
      break;
    case 1:
      channel1 = currentPressure;
      startChannel = activeTire;
      endChannel = activeTire;
      isChBelow10PSI[activeTire] = isCurrentPressBelow10psi;
      break;
    case 2:
      channel2 = currentPressure;
      startChannel = activeTire;
      endChannel = activeTire;
      isChBelow10PSI[activeTire] = isCurrentPressBelow10psi;
      break;
    case 3:
      channel3 = currentPressure;
      startChannel = activeTire;
      endChannel = activeTire;
      isChBelow10PSI[activeTire] = isCurrentPressBelow10psi;
      break;
    case 4:
      channel0 = currentPressure;
      channel1 = currentPressure;
      startChannel = 0;
      endChannel = 1;
      isChBelow10PSI[0] = isCurrentPressBelow10psi;
      isChBelow10PSI[1] = isCurrentPressBelow10psi;
      break;
    case 5:
      channel2 = currentPressure;
      channel3 = currentPressure;
      startChannel = 2;
      endChannel = 3;
      isChBelow10PSI[2] = isCurrentPressBelow10psi;
      isChBelow10PSI[3] = isCurrentPressBelow10psi;
      break;
    case 6:
      channel0 = currentPressure;
      channel1 = currentPressure;
      channel2 = currentPressure;
      channel3 = currentPressure;
      startChannel = 0;
      endChannel = 3;
      isChBelow10PSI[0] = isCurrentPressBelow10psi;
      isChBelow10PSI[1] = isCurrentPressBelow10psi;
      isChBelow10PSI[2] = isCurrentPressBelow10psi;
      isChBelow10PSI[3] = isCurrentPressBelow10psi;
      break;
  }

  for (uint8_t i = startChannel; i < endChannel + 1; i++)
  {
    
    if (printOutPress < 95) // This is for alignment of decimal point on screen
    
    lcd.print(6, 0, printOutPress);
    lcd.print(12, 0, printOutPress);
    lcd.print(6, 1, printOutPress);
    lcd.print(12, 1, printOutPress);
  }
}

void updateAllWithinTol()
{
  uint8_t numberOfChannelsInUse = 0;
  switch (activeTire)
  {
    case 0:
    case 1:
    case 2:
    case 3:
      numberOfChannelsInUse = 3;
      break;
    case 4:
    case 5:
      numberOfChannelsInUse = 2;
      break;
    case 6:
      numberOfChannelsInUse = 1;
      break;
  }
  if (allWithinTolCounter >= numberOfChannelsInUse && !isAllWithinTol)
  {
    isAllWithinTol = true;
    withinTolSetPoint = setPoint;
    isSetPointChanged = false;
  }
  else if (allWithinTolCounter < numberOfChannelsInUse)
  {
    isAllWithinTol = false;
  }
}

uint16_t calculateDeflationTime(uint16_t currentPressure)
{
  uint16_t deflationParamInUse = 0;
  switch (activeTire)
  {
    case 0:
    case 1:
    case 2:
    case 3:
      deflationParamInUse = singleChannelDeflationParam;
      break;
    case 4:
      deflationParamInUse = frontChannelsDeflationParam;
      break;
    case 5:
      deflationParamInUse = rearChannelsDeflationParam;
      break;
    case 6:
      deflationParamInUse = allChannelsDeflationParam;
      break;
  }

  uint16_t timeMilliSec = ((deflationParamInUse * 10) / log( (float)currentPressure / (float)setPoint )) + VALVE_OPENING_TIME;
  if (timeMilliSec > MAX_DEFLATION_TIME)
  {
    timeMilliSec =  MAX_DEFLATION_TIME;
  }
  return timeMilliSec;
}

uint16_t calculateInflationTimeMS(uint16_t currentPressure)
{
  uint16_t inflationParamInUse = 0;
  switch (activeTire)
  {
    case 0:
    case 1:
    case 2:
    case 3:
      inflationParamInUse = singleChannelInflationParam;
      break;
    case 4:
      inflationParamInUse = frontChannelsInflationParam;
      break;
    case 5:
      inflationParamInUse = rearChannelsInflationParam;
      break;
    case 6:
      inflationParamInUse = allChannelsInflationParam;
      break;
  }

  uint16_t timeMilliSec = ((float)( setPoint - currentPressure ) * ( inflationParamInUse / 100 ) ) + VALVE_OPENING_TIME;
  if (timeMilliSec > MAX_INFLATION_TIME)
  {
    timeMilliSec =  MAX_INFLATION_TIME;
  }
  return timeMilliSec;
}

void decideWhatToDo(int16_t currentPressure)
{
  int16_t difference = currentPressure - setPoint;
  if (activeTire == 0 || activeTire == 1 || activeTire == 4)
  {
    difference = difference - frontAxleOffset;
  }
  if (abs(difference) > TOLERANCE) // Last measurement not within tolerance
  {
    allWithinTolCounter = 0;
    if (difference > 0)
    {
      valveControl(DEFLATE);
      deflationTime = calculateDeflationTime(currentPressure);
      TireTimeThres = millis() + deflationTime;
    }
    else if (1)  //tankPress > 3000) // inflation only performed if tank press > 30 psi
    {
      valveControl(INFLATE);
      inflationTime = calculateInflationTimeMS(currentPressure);
      TireTimeThres = millis() + inflationTime;
    }
    tireState = inflationDeflationDone;
  }
  else // Last measurement within tolerance
  {
    allWithinTolCounter += 1;
    changeToNextChannel();

    if (isAllWithinTol && allWithinTolCounter > STAND_BY_THRESHOLD)
    {
      closeAllValves();
      TireTimeThres = millis() + (STAND_BY_MULTIPLAYER * ALL_WITHIN_TOL_WAIT_TIME);
      tireState = allWithinTolWaiting;
    }
    else if (isAllWithinTol)
    {
      closeAllValves();
      if (activeTire == 6)
      {
        openActiveTireValve();
      }
      TireTimeThres = millis() + ALL_WITHIN_TOL_WAIT_TIME;
      tireState = allWithinTolWaiting;
    }
    else
    {
      valveControl(MEASURE);
      TireTimeThres = millis() + SETTLING_TIME;
      tireState = firstMeasurementOngoing;
    }
  }
}

void openActiveTireValve()
{
  switch (activeTire)
  {
    case 0:
      digitalWrite(PIN_VALVE1, HIGH);
      break;
    case 1:
      digitalWrite(PIN_VALVE2, HIGH);
      break;
    case 2:
      digitalWrite(PIN_VALVE3, HIGH);
      break;
    case 3:
      digitalWrite(PIN_VALVE4, HIGH);
      break;
    case 4:
      digitalWrite(PIN_VALVE1, HIGH);
      digitalWrite(PIN_VALVE2, HIGH);
      break;
    case 5:
      digitalWrite(PIN_VALVE3, HIGH);
      digitalWrite(PIN_VALVE4, HIGH);
      break;
    case 6:
      digitalWrite(PIN_VALVE1, HIGH);
      digitalWrite(PIN_VALVE2, HIGH);
      digitalWrite(PIN_VALVE3, HIGH);
      digitalWrite(PIN_VALVE4, HIGH);
      break;
  }
}

void closeAllValves()
{
  digitalWrite(PIN_VALVE0, LOW);
  digitalWrite(PIN_VALVE1, LOW);
  digitalWrite(PIN_VALVE2, LOW);
  digitalWrite(PIN_VALVE3, LOW);
  digitalWrite(PIN_VALVE4, LOW);
  digitalWrite(PIN_VALVE5, LOW);
}

void valveControl(int command)
{
  closeAllValves();
  isValve5Closed = true;
  switch (command)
  {
    case CLOSE_ALL:
      // Empty on purpose
      break;
    case MEASURE:
      openActiveTireValve();
      break;
    case INFLATE:
      isInflating = true;
      openActiveTireValve();
      digitalWrite(PIN_VALVE5, HIGH);
      isValve5Closed = false;
      break;
    case DEFLATE:
      isDeflating = true;
      openActiveTireValve();
      digitalWrite(PIN_VALVE0, HIGH);
      break;
    case CALIBRATION:
      digitalWrite(PIN_VALVE0, HIGH);
      break;
  }
}

uint16_t tireOffsetCalibration()
{
  valveControl(CALIBRATION);
  delay(2 * SETTLING_TIME);
  uint16_t temp = 0;
  for (int8_t i = 0; i < NUM_OF_MEASUREMENTS_SHORT_FILTER; i = i + 1)
  {
    temp = temp + analogRead(PIN_MPX4250);
    delay(TIME_BETW_MEAS);
  }
  uint16_t tireSensorOffset = (temp / NUM_OF_MEASUREMENTS_SHORT_FILTER);
  valveControl(CLOSE_ALL);
  delay(2 * SETTLING_TIME);
  return tireSensorOffset;
}

void writeParamToEEPROM()
{
  // Unfinished function
}

void loadParamFromEEPROM()
{
  singleChannelDeflationParam = EEPROM.read(SINGLE_CHANNEL_DEFLATION_PARAM_ADDRESS);
  singleChannelInflationParam = EEPROM.read(SINGLE_CHANNEL_INFLATION_PARAM_ADDRESS);
  frontChannelsDeflationParam = EEPROM.read(FRONT_CHANNELS_DEFLATION_PARAM_ADDRESS);
  frontChannelsInflationParam = EEPROM.read(FRONT_CHANNELS_DEFLATION_PARAM_ADDRESS);
  rearChannelsDeflationParam = EEPROM.read(REAR_CHANNELS_DEFLATION_PARAM_ADDRESS);
  rearChannelsInflationParam = EEPROM.read(REAR_CHANNELS_DEFLATION_PARAM_ADDRESS);
  allChannelsDeflationParam = EEPROM.read(ALL_CHANNELS_DEFLATION_PARAM_ADDRESS);
  allChannelsInflationParam = EEPROM.read(ALL_CHANNELS_DEFLATION_PARAM_ADDRESS);
}

void updatingControlParameters()
{
  if (isDeflating && isInflating)
  {
    // Error: should not happen
  }
  else if (isDeflating && deflationTime > 0 && (firstMeasurementPressure - secondMeasurementPressure) > 0)
  {
    uint16_t newDeflationParam = deflationTime / log( (float)firstMeasurementPressure / (float)secondMeasurementPressure) / 10;

    switch (activeTire)
    {
      case 0:
      case 1:
      case 2:
      case 3:
        singleChannelDeflationParam = newDeflationParam;
        break;
      case 4:
        frontChannelsDeflationParam = newDeflationParam;
        break;
      case 5:
        rearChannelsDeflationParam = newDeflationParam;
        break;
      case 6:
        allChannelsDeflationParam = newDeflationParam;
        break;
    }

  }
  else if (isInflating && inflationTime > 0 && (secondMeasurementPressure > firstMeasurementPressure))
  {
    uint16_t newInflationParam = inflationTime / (float)(secondMeasurementPressure - firstMeasurementPressure) * 100;

    switch (activeTire)
    {
      case 0:
      case 1:
      case 2:
      case 3:
        singleChannelInflationParam = newInflationParam;
        break;
      case 4:
        frontChannelsInflationParam = newInflationParam;
        break;
      case 5:
        rearChannelsInflationParam = newInflationParam;
        break;
      case 6:
        allChannelsInflationParam = newInflationParam;
        break;
    }
  }
  isDeflating = false;
  isInflating = false;
  if ( EEPROMTimeThres < millis() )
  {
    EEPROMTimeThres = millis() + 5000;
    writeParamToEEPROM();
  }
}

int16_t updateFrontAxleOffset()
{
  closeAllValves();
  int16_t offset = 0;
  for (uint8_t i = 0; i < 20; i++)
  {
    offset = map((pinValue), 0, 1023, -8, 8) * 50; // range from -4 to 4 psi with 0,5 psi resolution
    if (offset >= 0)
    lcd.print(3, 1, (float)offset);
    //delay(250);
  }
  return offset;
}

Actually you don’t need this function. Try to “replace” it with something like this:

BLYNK_WRITE(V11) { // Blynk press SET slider, where V11 is MY virtual pin (copy/paste)
	int pinValue = param.asInt();
	pinValue = constrain(pinValue, 100, 500); //this is where you put your limits of psi, multiplied by 10 for increased resolution
	setPoint = (float)pinValue / 10.0;
	delay(100);  //you can omit this one - was needed in my specific case
	lcd.print (x,y, setPoint);   //here you can send your setPoint to vLCD
	Serial.print(F("new preset setPoint: "));
	Serial.println(setPoint, 1);
}

You can try and report. This one was for my temperature settings, though I’m not using vLCD

The slider should be “send on release”

@marvin7 thanks for this, I am getin data from this but not in to right place :slight_smile:

neat thia to read ( analogRead(PIN_POT) ) from this ( pinValue = constrain(pinValue, 100, 500) ) !

Has been looking at this back and forth and get no sense in this, lacking ideas?

void updatingSetPoint()
{
  uint16_t newPotRaw = analogRead(PIN_POT); // 
  
  if(abs(newPotRaw - currentPotRaw) > 10 ) // POT hysteresis
  {
    uint16_t newSetPoint = potToPSI(newPotRaw);
    if( newSetPoint != setPoint) 
    {
      setPoint = newSetPoint;
      currentPotRaw = newPotRaw;
      isSetPointChanged = true;
      if(setPoint < 995)
      {
        lcd.print(0, 0, " "); // This is for alignment of decimal point on screen
      } 
      lcd.print(0, 0, ((float)setPoint));
      Serial.println(setPoint, 3);
    }
  }
}

Found a solution to this problem :slight_smile:
Before

= missing or ?
Now and works

:relaxed:

first is assignment, the latter comparison operator. Read about them them here: https://www.arduino.cc/en/Reference/HomePage

1 Like

That will not work in the way I think you think it will work :stuck_out_tongue_winking_eye:

There is different syntax between Arithmetic/Assignment Operator ( = ) and Comparison Operator ( == )

example:

if (a == b)   // Use of the DOUBLE == COMPARES If variable a is the same as variable b...
{ 
  then c = 1   // ...and if it is, the SINGLE = ASSIGNS variable c the value of 1.
} 
  else c = 0  // If variable a is not the same as variable b, then variable c is assigned the value of 0.
}

EDIT @marvin7 - I don’t know how I missed your comment
 I know I am slow typer, but 13min slow?? :stuck_out_tongue: Your answer was short and sweet = better :+1:

1 Like