My pcb with Atmega328p-AU can't seem to run project sketch

Hello,

It’s been a while but my project pcb with a suface mounted Atmega328P has arrived from the pcd manufacturer. It’s a project to measure fluid level in a tank with a waterproof UART ultrasonic sensor. It uses a I2C 16x2 lcd screen for the readout, alarm level and pump level adjustment.

I got i working on a identical manualy build pcb without using a usb data connection but with the SPI connection (a Arduino R3 is my ISP device; with the 3 leds).

For some reason i can upload my project scetch and the example sketch ‘Hello World’ (it only works if i program as Arduino Uno, not Arduino nano although i use the surface mounted Atmega 328P version??) but only the example sketch ‘Hello World’ runs.
My project sketch seems to be hanging in the begin of the sketch where is initialises the LCD screen, lits up the backlight and clears the screen.
After that it should acces the EEPOM memory for checking EEKey to write (or not) the default papameters.

void setup() {
  //Serial.begin(9600);
  mySerial.begin(9600);
  lcd.init();
  //lcd.begin(); // I2C lcd dislplay
  lcd.backlight(); //I2C lcd backlight on
  lcd.clear(); //I2C clear screen
  delay(1000);                              //was here in LCD example sketch for unknown reason (waiting time for lcd to start up?)
  pinMode(MAINBUTTON_PIN, INPUT_PULLUP);    //set mainbutton as input with internal pullup
  pinMode(ALARMRESET_PIN, INPUT_PULLUP);    //set alarmresetbutton as input with internal pullup
  pinMode(VALVEREADOUT_PIN, INPUT_PULLUP);  //set valvereadout pin as input with internal pullup
  pinMode(LED_REFILL, OUTPUT);              //set led 'refill' as output
  pinMode(LED_ALARM, OUTPUT);               //set led 'alarm' as output
  alarmTimer = millis();                    //because the valveAlarmonoff is at startup true (safety first for un-mindfull users) the alarmtimer needs to be set (in the loop of case 0 impossible)

  //WRITING FIRMWARE VERSION TO EEPROM
  for (int i = 0; i < 3; i++) {
    EEPROM.put(eepromStart + sizeof(eeKey) + i, firmwareVersion[i]);  //unint8_t = one byte hence 'i' instead of 'i*2'
  }
  //GETTING THE VARIABLES FOR menuVariables WITH A FIRST STARTUP CHECK (with EEPROM eeKey check)
  EEPROM.get(eepromStart, readKey);
  if (eeKey != readKey) {
    EEPROM.put(eepromStart, eeKey);                                                                      //STORING eeKey at eeepromStart of EEPROM
    loadvarinEEPROM(); //STORING defaultVariables in EEPROM
  }
  //filling the menuVariables array with the content in the EEPROM
  for (int i = 0; i < 5; i++) {
    EEPROM.get(eepromStart + sizeof(eeKey) + sizeof(firmwareVersion) + (i * 2), menuVariables[i]);  //uint16_t 16bit = two bytes
    //Serial.println(menuVariables[i]);                                                               //for testing
  }
}

void loop() {

Could this have to do anything with not having a (Arduino) bootloader in the µC and accessing the EEPROM?
The other (hardware) difference with my experimental perforated board is that the AVCC pin on the pcb (from the manufacturer) is not connected but that can’t explain i.m.o. why the example sketch works and my project sketch not.

More info will follow but now i have to leave.

thx

Your example sketch does not compile, I suspect you did not post the entire sketch.

AVCC pin on the pcb (from the manufacturer) is not connected but that can’t explain i.m.o. why the example sketch works and my project sketch not.

It could. Other than the fact that it supplies power to PC[3:0], it is not clear why it need to be connected but microchip states that it must be, even if you do not use the ADC.

Have you set the fuses properly on the atmega328?

There should be no need for a bootloader, that is only used for uploading sketches via USB, although the common method for setting the fuses is to do "burn bootloader" in the Arduino IDE. If you have not already, have a look at MCUdude's MiniCore, that has an option for "no bootloader" that will let your sketch use the full flash memory of the atmega328.

The Bootloader does not touch EEPROM at all.

However, if you haven't done a "burn bootloader" or done something manually to set the chip's "fuses", it may not be in a correct state for running Arduino programs (for instance, it could be running with the default internal 1MHz clock, and I'm not sure what that would to to I2C communications with you display.)

The schematic does not show any of the required decoupling capacitors.

To be clear. The partitial code i’ve posted is part of my project code. I have also tested my new board with a example sketch for the lcd screen (the ‘Hello World’) and that one works fine (but it takes a, i.m.o., very long time to start running. Fuse settings to 1Mhz oscillator?)

The project sketch/code does compile and the upload to the µC seems to be ok (in the not-logical Arduino Uno setting instead of Arduino nano that refuses with some errors). When the scetch runs it seems to be hanging rigth after starting up the lcd (so it doesn’t work, no sensor reaction, no input reaction, only blank lit up lcd). The schematic should be ok because i can upload the ‘Hello world’ example sketch en get it running.

I’ve read some other post and it could be that i need to set the fuses. Especially the one(s) for the oscillator. The startup of the µC seems to be very slow. It starts up about 10 sec after i’ve uploaded the scetch.

I’m not uploading the whole sketch on this topic because it runs ok on my other board….and it’s 600 lines (yes it’s a very complete sketch with all functionalities and a; for me; complex one-button-adjustment).

I’ve tried burning the Arduino bootloader but i’m getting errors. Maybe having to with the AVCC pin not being connected.

I’v tried burning the Arduino bootloader on other (Arduino) boards and that works fine.

Sorry for this but i had to zoom in a bit to the relevant part (about the AVCC pin)

I though so but i’ve asked it to be shure.

That could be the problem but….burning the bootloader is not working on this virgin board (and virgin µC). The unconnected AVCC pin could be the problem and connecting that pin of a surface mounted µC…pfff thats going to be a real p in the a.
As i have mentioned, i can upload the lcd example sketch to the board and it runs fine (but starts up very slow, 1MHz?) so the I2C bus should be ok.

  1. The Nano has less flash memory available for program storage because more space is reserved for the bootloader (history lesson required) . A big program can work on a Uno but fail on a Nano.

  2. Treat your atmega328p as a Uno board throughout. The SMD chip package makes it look visually more like a Nano but that is completely irrelevant.

Thanks for the tip! I’ll try it as soon is i have some time (i don’t have a place at home where i can leave my stuff behind so it takes time to get my stuff out and get it out of the way afterwards).
It could be that the (unset) fuses are the problem but for now i can’t burn a bootloader, probably due to the unconnected AVCC pin.

I recall that my project sketch eats about almost 50% of the available flash memory.

Normaly at this point it should nog be a problem because there is no bootloader present in the µC.
Although it seems that if i choose a Nano as target that the Arduino IDE itself it the problem and limits the use of the flash memory.

If you can upload a "Hello World " sketch directly onto the chip, in the way that you are currently attempting (ICSP method) , then you should also be able to use the "burn bootloader " option in the IDE.
Post a link to the tutorial you are following to directly load sketches onto the ATmega328P.

You can simply treat a Nano as a Uno once you succeed in burning a Uno bootloader onto it and benefit from the extra flash available. Why? Sins of the past.

You get even more flash memory if you don't load a bootloader but inorder to set the fuses correctly for this you either have to use minicore or use AVRDUDE. Using the MiniCore board package linked in post #3 is the suggested method.

Could you post the output shown in the IDE when you attempt to burn the bootloader?

Ok. I’ll try it wednesday because i’ll need to get out my stuff (not much time, i’m busy with other things).
To be shure i’ll check when testing the bootloader burn if i use the Arduino Uno setting in the IDE and not the Arduino Nano setting.
Maybe some testing AVRdude or miniCore. I’v seen that miniCore is something you ‘integrate’ in the Arduino IDE (that sounds sweet with added menu items).

thx!

Great news. After re-loading the ISP sketch in the UNO R3 and burning the Arduino bootloader (with the Uno setting; and yes it workt) and loading my project sketch in the virgin µC….Tadaaa…..it finaly works! Seems that a inherently bad wire contact (hard to see) in the screw brakeout blocks was the culprit. When the program does not get the data from the sensor the lcd screen freezes blank with the backlight lit. Before this succesfull try i’ve changed the wire from the new board to my experimental board a few time and alway bad contact on the new board…till now. I need to get a workaround for this (with a sensor error on the display) but this is coding for an other topic.

Maybe by setting the fuse bits, it runs better now. It’s not so slow in the startup anymore (16Mhz external crystal insteat of 1Mhz internal oscillator?).

I need to get the manufactured pcb in a box en waterproof all the incoming cables but that’s for later.

Still need to try out miniCore and AVRdude but that also is going to be a other topic.

Thx for all the help! I’m very stoked that my first big project is running!

Code and pictures….

/*CREATED WITH ARDUINO IDE v2.3.5 & TESTED WITH ARDUINO UNO R3 & ARDUINO NANO*/
/*Code for project with waterproof ultrasonic UART distance sensor A02YYUW and I²C 16x2 LCD display*/
/*The SoftSerial lib is used to create a second UART connection because the imbedded is used to load sketches and uses the IDE serial monitor (embedded in Arduino bootloader to communicate via the USB/UART chip on the Arduino board ). */
/*This skech is al water level meter for watertanks (or other fluids that don't damage the waterproof distance sensor). The sensor is the waterproof version of ultrasonic SR04 (sonar).
Min reading distance is 4cm, max. reading distance is 400cm. Min. & max. level kan be set in a separate diplay menu. The display shows the level in % and surface distance in cm.
There is a adjutable refill function (refill setting and stoprefill setting). The refill circuit (valve circuit) needs to be commanded by the refill output led.
A refill alarm is set at a standard (no user adjustment) time of 2 hours (7.200.000ms but can be adjusted in this sketch) and the state of the refill valve (circuit) need to be read (commanded valve state needs to = read out state).
In the project circuit three leds:
-blue for power and not commanded by µController
-green led for refill ongoing
-red led (+loud high pitch buzzer) for refill alarm (valve open while AlarmTimer has counted to setting limit=alarm and/or reading 'valve open' via external readout while valve is not commanded open=alarm). Read via optocoupler at pin 5.
Two pushbuttons:
-on pin 3 for toggling the lcd screen menu's (big button prefered)
-on pin 4 for 10min alarm muting (small button prefered)
*/

//include all used libraries

#include <DistanceSensor_A02YYUW.h> //lib for ultrasonic sensor

#include <SoftwareSerial.h> //lib standard available in Arduino IDE for second UART (first UART is the embedded in the Arduino bootloader to communicatie with the USB chip on pin 0 and pin 1)

#include <LiquidCrystal_I2C.h> //lib for I²C 16x2 LCD display

#include <Wire.h> //lib standard available in Arduino IDE to enable I²C communication

#include <EEPROM.h>  //library standard available in Arduino IDE used to store the settings in the EEPROM memory


//all declarations of variables and defining of constants before void setup
//pins 0 and 1 are not used to avoid conflicts while using the serial monitor (uses the standard USB/UART connection)

#define MAINBUTTON_PIN 3  //defining main push button (Arduino)pin

#define ALARMRESET_PIN 4 //defining alarm reset button (Arduino)pin

#define VALVEREADOUT_PIN 5  //defining valve controle (Arduino)pin

#define SOFTWARE_SERIAL_PIN_RX 10 //this is where the tx (white wire) of the sensor goes (Arduino pin)!! has been changed from Arduino pin 11 to pin 10 because pin 11 is the MOSI pin from the ICSP connection used to program µC directly

#define SOFTWARE_SERIAL_PIN_TX 9 //(Arduino pin) has been changed from Arduino pin 10 to 9 because pin 10 was original pin 11 (reason above this line)

#define LED_REFILL 7  //info: the refill valve relais will be DIRECTLY COMMANDED BY THE LED PIN (optocoupler). Arduino pin!

#define LED_ALARM  8 //info: the alarm led output also needs to be connected to a high pitch buzzer (direct or indirect). Arduino pin!

//creating instances of the library objects

SoftwareSerial mySerial(SOFTWARE_SERIAL_PIN_RX, SOFTWARE_SERIAL_PIN_TX);

DistanceSensor_A02YYUW distanceSensor(&mySerial);

LiquidCrystal_I2C lcd(0x27, 16, 2); //I²C adres, 16x2 digit display

int lcdMenu = 5;  //int used to in the switch/case condition and selecting variables in the three array's. Here initial starting loop at lcdMenu 0.

char menuText[][10] = { "MinLevel", "MaxLevel", "FillStart", "FillStop", "Alarmtime" };  //this is an arry char's but these 'values' are alway the same
uint16_t menuVariables[5]; //field [0]=MinLevel; [1]=MaxLevel; [2]=FillsStart ;[3]=FillStop; [4]=Alarmtime//use of 16bit int's instead of normal(32bit) int's for minimalising EEPROM space
const uint16_t defaultVariables[5] = { 180, 30, 170, 150, 60 };  //loaded in the EEPROM at first startup (so if eeKey is not present in EEPROM)
uint8_t firmwareVersion[3] = { 1, 0, 0 };
char menuUnits[][4] = { "cm", "cm", "cm", "cm", "min" };  //3 char's + trailing 'null' character
const int eepromStart = 0;
const uint32_t eeKey = 0xDEADBEAD; //EEPROM key to flag backup creation
uint32_t readKey;
char buf[16];  //used in two void functions so global declaration

//unsigned long maxRefilltime = 5000;  //this is a variable for TESTING PURPOSE ONLY. Is used in case 1 for the alarm timer istead of menuVariables[5]
unsigned long alarmTimer;           //this variable to store the time that has passed sins the beginning of the refill command. Is limited to 72000000ms=120min=2h in case 5. unsigned long max. count is 4.294.967.295 so max time is 1.192 hours
unsigned long timeoutTime = 10000;  //When no input is given for one minute switch/case goes to case 0 and backlight goes off. Note:frist push on mainbutton 'awakes' the backlight and ables further input on the main button
unsigned long timeoutTimer;

unsigned long defaultflipTime;     //time used in lcdMenu 8 to flip lcd text on the second line
unsigned long currentdefaultTime;  //current timed time in lcdMenu 8 to flip lcd text on the second line
unsigned long defaultTime = 2000;

unsigned int dis;  //declaring variable for the distance
float percent;
bool valveAlarmonoff = true;  //false=off, true=on

//the following int's also need to be globaly declared because they are used in different functions
unsigned int highLimit;  //counter that sets set highest level in reservoir THIS VALUE NEEDS TO BE RESTRICTED TO AT LEAST 1CM ABOVE counterMin (this means counterMin -1)
unsigned int lowLimit;   //counter that sets lowest level in reservoir

//these variables need to be set once outside the various loops @ startup. With local declaration this sketch wouldn't work.
bool risingEdge = false;  //for reading a one-time rising flank (=button returning after being pushed)
int directionInt = -1;    //needs to be int instead of boolean to increase or decrease the int counter in the dimmingCounter function
bool enterLong = LOW;
bool firstLoop = true;

bool firstFlip = true;

bool firstdefaultFlip = true;
bool defaultFlag = false;  //flag to stop the risingedgeTest from detecting while pushing button to get from lcdMenu 0 to lcdMenu 8

bool firstButtonread = LOW;
bool secondButtonread = LOW;
bool buttonState = LOW;
bool risingFlag = LOW;
bool droppingFlag = LOW;
unsigned long longTimer = 0;
bool first7passFlag = false;
bool defaulttextFlip = false;  //used in lcdMenu 8 to flip lcd text on the second line


//case 'levels' for the swich condition = easier instead of using if/else statements
//const int SCREEN_LEVEL = 5;  //tanklevel needs to be displayd in % instead of cm


void setup() {
  //Serial.begin(9600);
  mySerial.begin(9600);
  lcd.init();
  //lcd.begin(); // I2C lcd dislplay
  lcd.backlight(); //I2C lcd backlight on
  lcd.clear(); //I2C clear screen
  delay(1000);                              //was here in LCD example sketch for unknown reason (waiting time for lcd to start up?)
  pinMode(MAINBUTTON_PIN, INPUT_PULLUP);    //set mainbutton as input with internal pullup
  pinMode(ALARMRESET_PIN, INPUT_PULLUP);    //set alarmresetbutton as input with internal pullup
  pinMode(VALVEREADOUT_PIN, INPUT_PULLUP);  //set valvereadout pin as input with internal pullup
  pinMode(LED_REFILL, OUTPUT);              //set led 'refill' as output
  pinMode(LED_ALARM, OUTPUT);               //set led 'alarm' as output
  alarmTimer = millis();                    //because the valveAlarmonoff is at startup true (safety first for un-mindfull users) the alarmtimer needs to be set (in the loop of case 0 impossible)

  //WRITING FIRMWARE VERSION TO EEPROM
  for (int i = 0; i < 3; i++) {
    EEPROM.put(eepromStart + sizeof(eeKey) + i, firmwareVersion[i]);  //unint8_t = one byte hence 'i' instead of 'i*2'
  }
  //GETTING THE VARIABLES FOR menuVariables WITH A FIRST STARTUP CHECK (with EEPROM eeKey check)
  EEPROM.get(eepromStart, readKey);
  if (eeKey != readKey) {
    EEPROM.put(eepromStart, eeKey);                                                                      //STORING eeKey at eeepromStart of EEPROM
    loadvarinEEPROM(); //STORING defaultVariables in EEPROM
  }
  //filling the menuVariables array with the content in the EEPROM
  for (int i = 0; i < 5; i++) {
    EEPROM.get(eepromStart + sizeof(eeKey) + sizeof(firmwareVersion) + (i * 2), menuVariables[i]);  //uint16_t 16bit = two bytes
    //Serial.println(menuVariables[i]);                                                               //for testing
  }
}

void loop() {
  switch (lcdMenu) {
    case 0:                  //SECOND DISPLAY MENU = minimum level parameter set
      if (timeoutCheck()) {  //if timeoutCheck returns true then go to timeout 'ghost menu' (=case 7)
        lcdMenu = 7;
        break;
      }
      lowLimit = 400;
      highLimit = menuVariables[2];  //MinLevel can't be higher than current FillStart
      longpushTest();                //longpushTest BEFORE risingEdgeTest in case the counterloop is activated to cancel (disrupt) the risingedgetest (after a long push the program needs to stay in this menu)
      risingedgeTest();
      if (risingEdge == true) {
        Serial.println((String) "risingEdge  " + risingEdge);
        resetFlags();
        lcdMenu = 1;
      } else {
        dis = distanceSensor.getDistance()/10;
        lcdFirstline();
        lcd.setCursor(0, 1);  //cursor set line 1, character 0//next line limit info
        lcd.print((String) "limits " + lowLimit + "-" + menuVariables[2] + "    ");
        //Serial.println(menuText[lcdMenu - 1] + menuVariables[lcdMenu - 1] + menuUnits[lcdMenu - 1]);
        alarmCheck();
      }
      break;


    case 1:                  //THIRD DISPLAY MENU = maximum level parameter set
      if (timeoutCheck()) {  //if timeoutCheck returns true then go to timeout 'ghost menu' (=case 7)
        lcdMenu = 7;
        break;
      }
      lowLimit = menuVariables[3];
      highLimit = 4; //the closest measuring distance of the sensor is advised at 3cm but i'm adding 1cm to compensate for temperature fluxuations (aproximately 3%/10°C). It seems by testing 20° is the most accurate measuring temperature
      longpushTest();  //longpushTest BEFORE risingEdgeTest in case the counterloop is activated to cancel (disrupt) the risingedgetest (after a long push the program needs to stay in this menu)
      risingedgeTest();
      if (risingEdge) {
        resetFlags();
        lcdMenu = 2;
      } else {
        dis = distanceSensor.getDistance()/10;
        lcdFirstline();
        lcd.setCursor(0, 1);  //cursor set line 1, character 0//next line limit info
        lcd.print((String) "limits " + highLimit + "-" + menuVariables[3] + "    ");
        //Serial.println(menuText[lcdMenu - 1] + menuVariables[lcdMenu - 1] + menuUnits[lcdMenu - 1]); testing
        alarmCheck();
        valveCommand();
      }
      break;

    case 2:                  //FOURTH DISPLAY MENU = refillStart level set
      if (timeoutCheck()) {  //if timeoutCheck returns true then go to timeout 'ghost menu' (=case 7)
        lcdMenu = 7;
        break;
      }
      lowLimit = menuVariables[0];       //the lowest refill start limit may go to MinLevel
      highLimit = menuVariables[3] + 1;  //the highest refill start limit needs to be at least 1cm under the refillStop so that there is minimum 1cm space between refillStart & refillSTop
      longpushTest();                    //longpushTest BEFORE risingEdgeTest in case the counterloop is activated to cancel (disrupt) the risingedgetest (after a long push the program needs to stay in this menu)
      risingedgeTest();
      if (risingEdge) {
        resetFlags();
        lcdMenu = 3;
      } else {
        dis = distanceSensor.getDistance()/10;
        lcdFirstline();
        lcd.setCursor(0, 1);  //cursor set line 1, character 0//next line limit info
        lcd.print((String) "limits " + menuVariables[0] + "-" + (menuVariables[3] + 1));
        //Serial.println(menuText[lcdMenu - 1] + menuVariables[lcdMenu - 1] + menuUnits[lcdMenu - 1]);
        alarmCheck();
        valveCommand();
      }
      break;

    case 3:                  //FIFTH DISPLAY MENU = refillStop level set
      if (timeoutCheck()) {  //if timeoutCheck returns true then go to timeout 'ghost menu' (=case 7)
        lcdMenu = 7;
        break;
      }
      lowLimit = menuVariables[2] - 1;  //the lowest refill stop limit needs to be at least 1cm above the RefillStart
      highLimit = menuVariables[1];     //the highest refill stop limit by MaxLevel
      longpushTest();                   //longpushTest BEFORE risingedgeTest in case of entering the counterloop to cancel (disrupt) the risingedgeTest (after a long push the program needs to stay in this menu)
      risingedgeTest();
      if (risingEdge) {
        resetFlags();
        lcdMenu = 4;
      } else {
        dis = distanceSensor.getDistance()/10;
        lcdFirstline();
        lcd.setCursor(0, 1);  //cursor set line 1, character 0//next line limit info
        lcd.print((String) "limits " + (menuVariables[2] - 1) + "-" + menuVariables[1]);
        //Serial.println(menuText[lcdMenu - 1] + menuVariables[lcdMenu - 1] + menuUnits[lcdMenu - 1]);
        alarmCheck();
        valveCommand();
      }
      break;

    case 4:                  //SIXTH DISPLAY MENU = alarm timer set//this is a temporary menu because the timmer check for abnormal long filling time needs to be done independent from the Arduino
      if (timeoutCheck()) {  //if timeoutCheck returns true then go to timeout 'ghost menu' (=case 7)
        lcdMenu = 7;
        break;
      }
      lowLimit = 120;  //120min in case 5 'lowLimit' is misleading but this needs to be like this because case 5 uses the same functions as case 1,2,3 & 4
      highLimit = 1;   //1min in case 5 highLimit is misleading...
      longpushTest();  //longpushTest BEFORE risingEdgeTest in case the counterloop is activated to cancel (disrupt) the risingedgetest (after a long push the program needs to stay in this menu)
      risingedgeTest();
      if (risingEdge) {
        resetFlags();
        lcdMenu = 6;
      } else {
        dis = distanceSensor.getDistance()/10;
        lcdFirstline();
        lcd.setCursor(0, 1);  //cursor set line 1, character 0//next line limit info
        lcd.print("limits 1-120min");
        //Serial.println(menuText[lcdMenu - 1] + menuVariables[lcdMenu - 1] + menuUnits[lcdMenu - 1]);
        alarmCheck();
        valveCommand();
      }
      break;

    case 5:                  //FIRST DISPLAY MENU = distance/level in percentage
      if (timeoutCheck()) {  //if timeoutCheck returns true then go to timeout 'ghost menu' (=case 7)
        lcdMenu = 7;
        break;
      }
      longpushTest();  //in longpushTest if lcdMenu 0 then make lcdMenu 8 active
      risingedgeTest();
      if (risingEdge == true) {
        //Serial.println((String) "risingEdge  " + risingEdge);
        resetFlags();
        lcdMenu = 0;
      } else {
        //dis = 160;  //this line for testing puspose instead of the next line
        //dis = sr04.Distance();//read distance
        distance();
        percent = ((menuVariables[0] - (float)dis) / (menuVariables[0] - menuVariables[1])) * 100; //percentage//dis needs to be float so a float can be devided by a float, otherwise warning that result might be wrong
        lcd.setCursor(0, 0);
        lcd.print((String) "tanklevel " + (int)percent + "%   "); //with two extra spaces after % to clear the sreen from very 120% reading at startup
        lcd.setCursor(0, 1);
        lcd.print((String) "distance " + dis + "cm    ");//with two three spaces after % to clear the sreen from very 120% reading at startup
        alarmCheck();
        valveCommand();
      }
      break;

    case 6:                  //SEVENTH DISPLAY MENU = alarm on/off set (off if there is no refill valve used)
                             //LongpushTest BEFORE risingEdgeTest in case the counterloop is activated to cancel (disrupt) the risingedgetest (after a long push the program needs to stay in this menu)
                             //There is in the longpushTest a if-statement branch to the flipSwitch function instead of the counterloop
      if (timeoutCheck()) {  //if timeoutCheck returns true then go to timeout 'ghost menu' (=case 7)
        lcdMenu = 7;
        break;
      }
      longpushTest();
      risingedgeTest();
      if (risingEdge) {
        resetFlags();
        lcdMenu = 5;
      } else {
        dis = distanceSensor.getDistance()/10;
        displayAlarmstate();
        alarmCheck();
        valveCommand();
      }
      break;

    case 7:  // EIGHT DISPLAY MENU = this is a 'ghost timeout menu' that keeps on watching parameters but shuts down LCD (backlight=I2C version, only text non-I2C version) and waits for the main button
             //to be pushed to re-light the LCD backlight and go menu 0. When a timeout occures (mainbutton not pressed) in one of the other CASEs/Menu's
             //the menu get's set to this CASE 7.
      char fields[3][7];
      alarmCheck();
      if (digitalRead(LED_ALARM) == 1) {
        if (valveAlarmonoff == true && (millis() - alarmTimer) > (menuVariables[4] * 60000)){
          strncpy(fields[0], "VlvTi ", 7); //Valve Timer
        }else {
          strncpy(fields[0], "      ", 7);
        };
        if (valveAlarmonoff == true && (digitalRead(VALVEREADOUT_PIN) == 0 && digitalRead(LED_REFILL) == 0)){
          strncpy(fields[1], "Vlv ", 7); //Valve (open or closed)
        } else {
          strncpy(fields[1], "    ", 7);
        };
        if ((menuVariables[0] < dis) || (dis < menuVariables[1])){ 
          strncpy(fields[2], "TnkLLi", 7); //Tank Level Limit
        } else {
          strncpy(fields[2], "      ", 7);
        };
        lcd.backlight();//I2C backlight on
        lcd.display(); //I2C display lighted
        lcd.setCursor(0, 0);  //cursor set line 1, character 0//next line limit info
        lcd.print(" ALARM DETAILS  ");
        lcd.setCursor(0, 1);  //cursor set line 1, character 0//next line limit info
        lcd.print((String)fields[0] + fields[1] + fields[2]);       
       } else {
        lcd.clear();      //I2C lcd clear
        lcd.noDisplay();  //I2C display no dots lighted
        lcd.noBacklight(); //I2C backlight off     
      };
      risingedgeTest();
      if (risingEdge) {
        resetFlags();
        lcd.clear(); //I2C clear screen
        lcd.backlight();//I2C backlight on
        lcd.display(); //I2C display lighted
        lcdMenu = 5;
      } else {
        distance();
        alarmCheck();
        valveCommand();
      };
      break;

    case 8:  //NINTH MENU = THE 'RESET TO DEFAULT' MENU. THIS ONE IS ONLY ACCESABLE IN lcdMenu 0 VIA THE LONGPUSHTEST
      //NO TIMEOUT CHECK IN THIS MENU

      if (defaultFlag == false) {
        if (digitalRead(MAINBUTTON_PIN) == 1) {  //if the pushbutton is not pushed next risingedgeTest needs to be disrupted otherwise the droppingFlag stays true from the last 'loop'
          droppingFlag = false; //disrupting next risingedgeTest
          defaultFlag = true;  //after setting defaultFlag to 'true' this will change ONLY at EXIT lcdMenu 8 (so after risingedge true)
          //Serial.println((String)"defaultFlag " + defaultFlag); //testing
        }
      }
      if (defaultFlag) {  //if the pushbutton is not pressed any more after switching from lcdMenu 0 to lcdMenu 8, pushbutton is ready to be used in risingedgeTest
        longpushTest();
        risingedgeTest();
      }
      if (risingEdge) {
        //Serial.println((String) "risingEdge occured");                        //testing
        defaultFlag = false;                                                  //with exit lcdMenu 8 reset condition for the next time lcdMenu 8 is entered
        //Serial.println((String) "defaultFlag at risingEdge " + defaultFlag);  //testing
        resetFlags();                                                         //needs to be here a otherwise after exeting lcdMenu 8 a immediate dorpppongFlag and risingedgeFlag are triggered
        firstdefaultFlip = !firstdefaultFlip;                                 //resetting so when entering lcdMenu 8 the next time defaultflipTime will be resetted to millis()
        lcd.clear();
        lcdMenu = 5;
      } else {
        dis = distanceSensor.getDistance()/10;

        if (firstdefaultFlip) {
          lcd.clear();
          lcd.setCursor(0, 0);  //cursor set line 1, character 0//next line limit info
          lcd.print("TO DEFAULTS?     ");
          //Serial.println((String) "first defaulttextFlip: " + defaulttextFlip);  //testing
          defaultflipTime = millis();
          firstdefaultFlip = !firstdefaultFlip;
        }
        currentdefaultTime = millis();
        if (defaulttextFlip == false && (currentdefaultTime - defaultflipTime) > defaultTime) {  //time between changing text on second line 2 seconds
          //Serial.println("entering LONG");                                                       //testing
          lcd.setCursor(0, 1);                                                                   //cursor set line 1, character 0//next line limit info
          lcd.print("LONGPUSH=CONFIRM");
          Serial.println((String) "LONGdefaulttextFlip: " + defaulttextFlip);  //testing
          defaulttextFlip = !defaulttextFlip;                                  //next cycle other text line
          //Serial.println((String) "LONGdefaulttextFlip: " + defaulttextFlip);  //testing
          //Serial.println(defaultflipTime);                                     //testing
          defaultflipTime = millis();                                          //setting timer to zero
          //Serial.println(defaultflipTime);                                     //testing
        }
        currentdefaultTime = millis();
        if (defaulttextFlip == true && (currentdefaultTime - defaultflipTime) > defaultTime) {  //time between changing text on second line 2 seconds
          Serial.println("entering SHORT");                                                     //testing
          lcd.setCursor(0, 1);                                                                  //cursor set line 1, character 0//next line limit info
          lcd.print("SHORTPUSH=EXIT  ");
          //Serial.println((String) "SHORTdefaulttextFlip: " + defaulttextFlip);  //testing
          defaulttextFlip = !defaulttextFlip;                                   //next cycle other text line
          //Serial.println((String) "SHORTdefaulttextFlip: " + defaulttextFlip);  //testing
          defaultflipTime = millis();                                           //setting timer to zero
        }
        //Serial.println(menuText[lcdMenu - 1] + menuVariables[lcdMenu - 1] + menuUnits[lcdMenu - 1]);
        alarmCheck();
      }
      break;
  }
}


void distance() {
  DistanceSensor_A02YYUW_MEASSUREMENT_STATUS meassurementStatus;
  do {
    meassurementStatus = distanceSensor.meassure(); 
    if (meassurementStatus == DistanceSensor_A02YYUW_MEASSUREMENT_STATUS_OK) {
      dis = distanceSensor.getDistance()/10;
    }
  }  while (meassurementStatus != DistanceSensor_A02YYUW_MEASSUREMENT_STATUS_OK);
}

/*void distance() {
  DistanceSensor_A02YYUW_MEASSUREMENT_STATUS meassurementStatus;
  meassurementStatus = distanceSensor.meassure();
  while (meassurementStatus != DistanceSensor_A02YYUW_MEASSUREMENT_STATUS_OK) {
    meassurementStatus = distanceSensor.meassure();
    if (meassurementStatus == DistanceSensor_A02YYUW_MEASSUREMENT_STATUS_OK) {
      dis = distanceSensor.getDistance()/10;
    };
  }
}*/

void longpushTest() {
  unsigned long delayTime = 1000;
  if (!digitalRead(MAINBUTTON_PIN)) {  //if the button is pushed then go to timercheck
    if (firstLoop == true) {
      longTimer = millis();
      firstLoop = false;
      firstFlip = true;  //resetting the condition to 'flip' one time while pushing long BEFORE entering the next if statement
      //Serial.println((String) "longTimer  " + longTimer + "second");
      //if (lcdMenu >= 1 && lcdMenu <= 5) {
      //Serial.println(menuText[lcdMenu - 1] + menuVariables[lcdMenu - 1] + menuUnits[lcdMenu - 1]);
      //};
    }
    if ((millis() - longTimer) > delayTime) {  //timercheck: if the difference reaches 1000ms it is bigger than the delaytime the counterLoop wil be called
      //Serial.println((String) "entering counterLoop or flipSwitch"); testing
      if (lcdMenu == 6) {
        //Serial.println((String) "entering flipSwitch"); testing
        flipSwitch();
      } else if (lcdMenu == 8) {                                                                               //once in the default setting menu (after 'if (defaultFlag)'!) going to default settings with a longpush
          loadvarinEEPROM(); //STORING defaultVariables in EEPROM
          size_t numBytes = sizeof(defaultVariables);
          memcpy(menuVariables, defaultVariables, numBytes );//copying default const values to the variables that can be changed in running time         
          lcd.clear();
          lcd.setCursor(0, 0);                          //cursor set line , character 0//next line limit info
          lcd.print(" DEFAULT READY ");
          delay(3000); //freezing all activity 3sec with message the device is set to default
      } else if (lcdMenu == 5) {  //going from lcdMenu (display tanklevel) to default setting menu with a longPush
        lcdMenu = 8;
      } else { //if ((lcdMenu != 6) && (lcdMenu != 0)) {
          //Serial.println((String) "entering counterLoop");//testing
          counterLoop(); // AS LONG AS THE BUTTON IS BEING PUSHED THE SKETCH KEEPS 'LOOPING' IN THE WHILE LOOP OF THE COUNTERLOOP FUNCTION
          droppingFlag = false; //disrupting the risingedgeTest after exiting the the 'long push' in the longpushtest                                                                                                      //increase counter as long as button is pushed (=low)
          EEPROM.put(eepromStart + sizeof(eeKey) + sizeof(firmwareVersion) + ((lcdMenu) * 2), menuVariables[lcdMenu]);  //saving the altered variable in the EEPROM without comparison because after certainty of change
      };
    }
      //Serial.println((String) "BUTTON PRESSED  " + (millis() - longTimer) + "ms");
  } else if (digitalRead(MAINBUTTON_PIN)) {  //if button is not pushed (=input high) reset the timer by forcing longTimer = millis() the next cycle
    firstLoop = true;
  }   
}

  void risingedgeTest() {                                     //it is no use to make this a bool fucntion. although the value can be directly returned to the calling function the parameters have to be reset after every jump to the next lcdMenu so these need to be declared globaly (so risingEdge is also globaly declared)
    firstButtonread = digitalRead(MAINBUTTON_PIN);            //reading button first time. There is no need compensate jitter in running time with 'millis()' because this takes more extra processing time (aprox 12ms and minimum 5 extra variables) and the delay(10) can't cause failures or unresponsive main pushbutton in this sketch
    delay(10);                                                //two readouts with a small delay to compensate jitter advised 50ms but 10ms works better and with a 68nF capacitor parallel in button works even better.
    secondButtonread = digitalRead(MAINBUTTON_PIN);           //reading button second time
    if (firstButtonread == LOW && secondButtonread == LOW) {  //LOW/LOW = no jitter
      buttonState = LOW;                                      //=LOW means the button is pushed!! input pulling to GND!
      timeoutTimer = millis();                                //by each press on the main button resetting the timer for the timeout. NEEDS TO BE IN RISINGEDGETEST BECAUSE RISINGEDGETEST IS THE ONLY FUCTION THAT IS CALLED IN ALL THE CASSES
    }
    if (firstButtonread == HIGH || secondButtonread == HIGH) {  //one of the two HIGH means jitter or button just released
      buttonState = HIGH;
    }
    if (buttonState == LOW) {  //testing if a dropping edge has occured
      droppingFlag = HIGH;     //the droppingEdge needs to be flaged if occurring
      //Serial.println((String) "droppingFlag  " + droppingFlag); //for testing
    }  //when the button is continuous pushed this droppingFlag STAYS HIGH!
    //if droppingFlag is high, testing if a risingEdge is occuring in the next 'loops'(droppingFlag stays HIGH no matter what!)
    if (droppingFlag == HIGH) {
      if (firstButtonread == HIGH && secondButtonread == HIGH) {
        buttonState = HIGH;
      };
      if (firstButtonread == LOW || secondButtonread == LOW) {
        buttonState = LOW;
      }
      if (buttonState == HIGH) {
        risingFlag = HIGH;
        //Serial.println((String) "risingFlag    " + risingFlag + "   ");
      }
      //if the butten has been pushed (=droppingFLag) en some cycles later been pushed (=risingFlag) the condition for toggle to the next menu is ok
      if (droppingFlag == HIGH && risingFlag == HIGH) {
        risingEdge = true;
      } else {
        risingEdge = false;
      }
    }
  }

  void counterLoop() {
    int Speed = 0;
    int counterSpeed = 1;
    while (!digitalRead(MAINBUTTON_PIN)) {
      //Serial.println("COUNTERLOOP"); // testing purpose
      //Serial.println((String) "MinLevel " + counter + " cm    inside while loop"); // testing
      valueCounter();  //increase or dercease counter one step
//DISPLAYING values of current lcdMenu 'while' adjusting limits up or down
      sprintf(buf, "%-10s%3d%-3s", menuText[lcdMenu], menuVariables[lcdMenu], menuUnits[lcdMenu]); //put everything as a string in a buffer buf
      lcd.setCursor(0, 0);
      lcd.print(buf);
      if (menuVariables[lcdMenu] == highLimit || menuVariables[lcdMenu] == lowLimit) {
        lcd.setCursor(0, 1);  //cursor set line 1, character 0//
        lcd.print("      !LIMIT!       ");
      }
      enterLong = HIGH;  //setting variable to know if the while loop has been entered
      //the next six lines adjust the toggle speed in setting a value 'while' pushing the button longer then one seconde
      if (counterSpeed >= 1 && counterSpeed < 6) {
        Speed = 400;  //250ms
      } else if (counterSpeed >= 6 && counterSpeed < 15) {
        Speed = 200;  //125ms
      } else if (counterSpeed == 15) {
        Speed = 50;  //50ms
      };
      delay(Speed);  //the toggle speed on the counter/display value. This needs to changed to 3 automatic speed levels for user friendly use
      if (counterSpeed >= 1 && counterSpeed <= 15) {
        counterSpeed++;
      };
      //Serial.println((String) "counter  " + counter + "   directionInt  " + directionInt); //testing purpose
    };
    if (enterLong == HIGH) {         //enterLong is used to make the counterdirection change AFTER from the moment the button is released
      directionInt = -directionInt;  //flip the sign/counter direction after 1sec push
      enterLong = LOW;               //re-setting to LOW so the next time directioInt can be fliped in case of going tru while loop
      //Serial.println((String) "directionInt  " + directionInt); //testing purpose
    };
  }

  //void fuction because it does not need to return a value. int counter is declared globaly
  void valueCounter() {
    if (menuVariables[lcdMenu] > highLimit && menuVariables[lcdMenu] < lowLimit) {  //THE LIMIT VALUES NEED TO BE CHANGED ACCORDING TO THE MENU!!!SO THESE VALUES (2 & 401) ARE FOR MENU 2 ONLY
      menuVariables[lcdMenu] = menuVariables[lcdMenu] - directionInt;
    }
    //the next two if functions are used to 'push' the counter in one desired direction
    //after the button has been released on highLimit or lowLimit and re-pressed; longer than a second
    //in order to get in to the if function above. So it's a special method so the counter doens't get 'outside the limits hense blocking the function above
    if (menuVariables[lcdMenu] == highLimit && enterLong == LOW) {
      menuVariables[lcdMenu] = menuVariables[lcdMenu] + 1;
    }
    if (menuVariables[lcdMenu] == lowLimit && enterLong == LOW) {
      menuVariables[lcdMenu] = menuVariables[lcdMenu] - 1;
    }
    //Serial.println((String) "directionInt  " + directionInt); // testing
  }

  void valveCommand(){
            if (dis >= menuVariables[2] && dis > menuVariables[3]) {
          digitalWrite(LED_REFILL, 1);
        } else {
          digitalWrite(LED_REFILL, 0);
        };
  }

  void resetFlags() {
    droppingFlag = LOW;  //resetting buttonreading function of rising edge after led switch
    risingFlag = LOW;    //resetting buttonreading of rising edge after led switch
    risingEdge = false;  //resetting buttonreading of rising edge after led switch
  }

  void flipSwitch() {                       //instead of a counterLoop is the function to set the alarm active (on) or inactive and is entered in the longpushTest function
    while (!digitalRead(MAINBUTTON_PIN)) {  //after experimenting there is a while loop implemented because the droppingEdge kempt going back up with random results at pushbuttonrelease
      if (firstFlip == true) {
        valveAlarmonoff = !valveAlarmonoff;
        displayAlarmstate();
        if (valveAlarmonoff == true) {
          alarmTimer = millis();
          //Serial.println("    alarm on in flipswitch"); // testing
        };
        //if (valveAlarmonoff == false) {
        //Serial.println("    alarm off in flipswitch");// testing
        //};
        firstFlip = false;  //making shure when the butting is still pushed in the second pass true the flipSwitch function that valveAlarmonoff stays the same
        //Serial.println((String) "firstFlip" + firstFlip);//for testing
        //} else {
        //Serial.println((String) "    alarm " + valveAlarmonoff + " in flipSwitch Whileloop");// testing
      };
    };
    droppingFlag = false; //disrupting next risingedgeTest when the buttom is nog pushed anymore
  }

  //these are the two alarm checks. One for detection exceeding refill time (menuVariables[4]) and one if the valve is still open while the rifill command has stoped
  //first one timecheck
  void alarmCheck() {
    //Serial.println((String) alarmTimer);//for testing
    
//when alarm is on: check the refill timer, check if the valve is closed (VALVEREADOUT_PIN) while not commanded open (LED_REFILL, this is reading a output!!but should work) and check if tank is not to 'empty' or to 'full'
//if ((millis() - alarmTimer) > maxRefilltime || digitalRead(VALVEREADOUT_PIN) == digitalRead(LED_REFILL)){ //this line is for testing purpose only. Here you can shorten the time to a few seconds instead of a one minute minimum
    if ((valveAlarmonoff == true && ((millis() - alarmTimer) > (menuVariables[4] * 60000) || (digitalRead(VALVEREADOUT_PIN) == 0 && digitalRead(LED_REFILL) == 0))) || ((menuVariables[0] < dis) || (dis < menuVariables[1]))) {  //menuVariables[4] is a value that represents minutes hense *60000 to convert to ms
      digitalWrite(LED_ALARM, 1);
    } else {
      digitalWrite(LED_ALARM, 0);
    };
    //the next is a buttonread to reset the alarm TIMER. This means the alarm timer detection is only 'delayed' but the alarms (timer and 'valve open while not commanded') stay ON.
    //note!: the button readout is done with a simple anti-jitter delay instead of the millis() readout methode because in this case some ms extra
    //processing time is not a isseu AND: the millis() readout methode also takes a minimum of 12ms extra and at least five extra unsigned long values!!
    if ((valveAlarmonoff == true) && (millis() - alarmTimer) > (menuVariables[4] * 60000)) { //only reset timer if valveAlarmonoff is on and timer alarm has reached limit
      if (!digitalRead(ALARMRESET_PIN)) {  //using analog pin A4 as digital input with internal pullup
        delay(10);
        if (!digitalRead(ALARMRESET_PIN)) {
          //Serial.println((String) alarmTimer + "  before alarmTimer()=millis()"); //for testing
          alarmTimer = millis();  //if alarmresetbutton is pushed, reset the alarmtimer
          //Serial.println((String) alarmTimer + "  after alarmTimer()=millis()");//for testing
        };
      };
      //if (valveAlarmonoff == false) {
        //digitalWrite(LED_ALARM, 0);
      //};
    };
  }

  void lcdFirstline() {
    sprintf(buf, "%-10s%3d%-3s", menuText[lcdMenu], menuVariables[lcdMenu], menuUnits[lcdMenu]);  //put the array's of chars as a string in the buffer buf
    lcd.setCursor(0, 0);
    lcd.print(buf);
  }

  void displayAlarmstate() {
    if (valveAlarmonoff == false) {
      lcd.setCursor(0, 1);                //cursor set line 1, character 0
      lcd.print("                    ");  //erasing the second line the previous (16 characters) on the lcd display
      lcd.setCursor(0, 0);
      lcd.print("Alarm off       ");
      //Serial.println((String) "    alarm off    ");
    } else if (valveAlarmonoff == true) {
      lcd.setCursor(0, 1);                //cursor set line 1, character 0
      lcd.print("                    ");  //erasing the second line the previous (16 characters) on the lcd display
      lcd.setCursor(0, 0);
      lcd.print("Alarm on        ");
      //Serial.println((String) "    alarm on     ");
    }
  }

  bool timeoutCheck() {
    if ((millis() - timeoutTimer) > timeoutTime) {
      first7passFlag = false;
      return true;
    } else {
      return false;
    };
  }

  void loadvarinEEPROM(){
      for (int i = 0; i < 5; i++) {                                                                        //STORING defaultVariables in EEPROM
      EEPROM.put(eepromStart + sizeof(eeKey) + sizeof(firmwareVersion) + (i * 2), defaultVariables[i]);  //uint16_t 16bit = two bytes
      }
  };