Arduino stopped working when I2C LCD disconected

Hi,
I'm using I2C LCD in my program and when I disconnect it, everything stops working. And when I connect it back again, it still doesn't works. I think that the library is trying to send data to disconected device and crashes because of no response or what. So propably add some if statement to check if the display is connected. I tried to google it, but II couldn't find anything.

If you need, here is the sketch. Display is being initialized in switchFunc()

void switchFunc() {
  lcd.init();
  //delay(100);
  
  lcd.backlight();
  if(counterActive) {
    counterActive = false;
    lcd.setCursor(0,0);
    lcd.print("Stopky");
  } else {
    counterActive = true;
    lcd.setCursor(0,0);
    lcd.print("Pocitadlo");
  }
  refreshDisplay();
  delay(btnDelay*0.8);
  
}

and it's being used only in showDisplay() function.

void showDisplay(String text) {
  for(byte i = 0; i < 16; i++) {
    if(text[i] != lastText[i]) {
      lcd.setCursor(i,1);
      lcd.print(text[i]);
    }
  }
  
}

And the complete sketch:

#include <StopWatch.h>
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

#define LCDaddress 0x38

//IIC IO expanders for each digit of 7segment display (pcf8574)
int digitAddresses[4] = {34,33,36,35}; 

#define buttonaddress 39

//values sended to IO expander to show digit
int numbers[11]  = {126,20,109,117,23,115,123,84,127,119,0};

StopWatch stopwatch;

int score1 = 0;
int score2 = 0;
int tonePin = 7;
bool counterActive = true;

int btnDelay = 200;

String lastText;

long stopwatchToggle;


LiquidCrystal_I2C lcd(LCDaddress, 16, 2);

void setup() {
  Serial.begin(9600);
  
  Wire.begin();

  //clear all digits
  for(byte i = 0; i <4; i++) {
  Wire.beginTransmission(digitAddresses[i]);
  Wire.write(0);
  Wire.endTransmission();
  }

  pinMode(4, OUTPUT);
  digitalWrite(4, HIGH); //power for button)

  
 
  animate();
  switchFunc();
  tone(tonePin, 1050, 500);
 
  
  attachInterrupt(0, switchStopwatch, RISING);
  attachInterrupt(1, switchStopwatch, RISING);


 

}

void loop() {
  
  //read inputs from buttons on IO expander
  readButtons();
  
  refreshDisplay();
  

}


void readButtons() {
  Wire.requestFrom(buttonaddress, 1);
  if(Wire.available()) {
    byte readBtn =255- Wire.read();
    String readed;
    for(byte i = 0; i < 8; i++) {
      readed+= String(bitRead(readBtn,i));
    }
    
    Serial.println(readed);
    if(String(readed[0])=="1") { minus1Btn(); }
    else if(String(readed[1])=="1") { rst1Btn(); }
    else if(String(readed[2])=="1") { plus1Btn(); }
    else if(String(readed[3])=="1") { rstAllBtn(); }
    else if(String(readed[4])=="1") { switchFunc(); }
    else if(String(readed[5])=="1") { minus2Btn(); }
    else if(String(readed[6])=="1") { rst2Btn(); }
    else if(String(readed[7])=="1") { plus2Btn(); }
   
    
  }
}


void refreshDisplay() {
  if(counterActive) {
    String line;
    if(score1 < 10) {line="0"+String(score1);}
    else {line=String(score1);}
    line+="            ";
    if(score2 < 10) {line+="0"+String(score2);}
    else {line+=String(score2);}
    showDisplay(line);
    String toSegment;
    if(score1 < 10) {toSegment="-"+String(score1);}
    else {toSegment=String(score1);}
    if(score2 < 10) {toSegment+="-"+String(score2);}
    else {toSegment+=String(score2);}
    showSegments(toSegment);
    
  } else {
    long elapsed = stopwatch.elapsed();
    int milisec = elapsed%1000;
    byte seconds = ((elapsed-milisec)/1000)%60;
    int minutes = (((elapsed-milisec-seconds)/1000)/60);

    String milisecS = String(milisec);
    String secondsS = String(seconds);
    String minutesS = String(minutes%60);
    while(milisecS.length() < 3) {milisecS = "0" +  milisecS; }
    if(secondsS.length() == 1) {secondsS = "0" + secondsS; }
    if(minutesS.length() ==1) {minutesS = "0" + minutesS; }

    String toShow = minutesS+":"+secondsS+":"+milisecS;
    while(toShow.length() < 16) {toShow = " "+toShow;}
    showDisplay(toShow);
    showSegments(secondsS+minutesS);
    
  }
}

void showDisplay(String text) {
  for(byte i = 0; i < 16; i++) {
    if(text[i] != lastText[i]) {
      lcd.setCursor(i,1);
      lcd.print(text[i]);
    }
  }
  
}

void showSegments(String nums) {
  for(byte i = 0; i < 4; i++) {
   int num;
   if(String(nums[i]) == "-") {num = 10;}
   else {num = String(nums[i]).toInt();} 
  
  Wire.beginTransmission(digitAddresses[i]);
  Wire.write(numbers[num]);
  Wire.endTransmission();
  }
}




void animate() {
  //const int melody[] ={  392,  330,  262,   262,   262,   294,   330,   349,   392,   392,  392,  330, };
  const int melody[] ={  250, 350, 450, 550, 650, 750, 850, 950 };
  const int toneTime[] ={  16,  16,  8,  8,  16,  16,  16,  16,  8,  8,  8,  8};
  byte anims[7] = {1, 2, 64, 4, 16, 32, 8};
  byte anims2[7] = {2, 66, 70, 86, 118, 126, 127};
  for(byte i = 0; i < 4; i++) {
    Wire.beginTransmission(digitAddresses[i]);
    Wire.write(0);
    Wire.endTransmission();
   
  }
  byte adrs[4] = {33, 34, 35, 36}; 
  for(byte an = 0; an < 7; an++) {
    for(byte i = 0; i < 4; i++) {
    
      Wire.beginTransmission(adrs[i]);
      Wire.write(anims[an]);
      Wire.endTransmission();
      
    }
      tone(tonePin, melody[an], (1000/toneTime[an])*2);
      delay(300);
    
  }
  
  for(byte an = 0; an < 7; an++) {
    for(byte i = 0; i < 4; i++) {
    
      Wire.beginTransmission(adrs[i]);
      Wire.write(anims2[an]);
      Wire.endTransmission();
      
    }
      tone(tonePin, melody[an], (1000/toneTime[an])*2);
      delay(300);
    
  }
}



void switchStopwatch() {
  if(stopwatch.isRunning()) {
    if((stopwatchToggle + (1000*5)) < millis()) {
      stopwatch.stop();
      stopwatchToggle = millis();
      playSound(0);
    }    
  } else {
     if((stopwatchToggle + (1000*5)) < millis()) {
      stopwatch.start();
      stopwatchToggle = millis();
      playSound(0);
    }    
  }
}

void playSound(int type) {
  switch(type) {
    case 0:
       tone(tonePin, 950, 1000);
      break;
    case 1:
      const int note[] = {262,277, 294, 311, 330, 349, 370,392, 415, 440, 466, 494, 523  };
      const int melody[] ={  392,  330,  262,   262,   262,   294,   330,   349,   392,   392,  392,  330, };
      const int toneTime[] ={  16,  16,  8,  8,  16,  16,  16,  16,  8,  8,  8,  8};
      for(int a = 0; a < 2; a++) {
        for (int i=0; i<= 11; i++){
          tone(tonePin, melody[i], 1000/toneTime[i]);
          delay(2000/toneTime[i]);   
        }
      }
      break  ;  
  }
  
}



//buttons
void plus1Btn() {
  if(counterActive) {
    score1++;
    if(score1 > 99) { score1 = 99; }
    refreshDisplay();
    delay(btnDelay);
  }
}

void rst1Btn() {
  if(counterActive) {
    score1 = 0;
    refreshDisplay();
    delay(btnDelay);
  } else {
    switchStopwatch();
  }
}

void minus1Btn() {
  if(counterActive) {
    score1--;
    if(score1 < 0) { score1 = 0; }
    refreshDisplay();
    delay(btnDelay);
  }
}
void rstAllBtn() {
  if(counterActive) {
    score1 = 0;
    score2 = 0;
    refreshDisplay();
    delay(btnDelay);
  } else {
    stopwatch.reset();
    stopwatchToggle = millis()-5000;
    refreshDisplay();
  }
}

void switchFunc() {
  lcd.init();
  //delay(100);
  
  lcd.backlight();
  if(counterActive) {
    counterActive = false;
    lcd.setCursor(0,0);
    lcd.print("Stopky");
  } else {
    counterActive = true;
    lcd.setCursor(0,0);
    lcd.print("Pocitadlo");
  }
  refreshDisplay();
  delay(btnDelay*0.8);
  
}
void plus2Btn() {
  if(counterActive) {
    score2++;
    if(score2 > 99) { score2 = 99; }
    refreshDisplay();
    delay(btnDelay);
  }
}

void rst2Btn() {
  if(counterActive) {
    score2 = 0;
    refreshDisplay();
    delay(btnDelay);
  } else {
    switchStopwatch();
  }
}

void minus2Btn() {
  if(counterActive) {
    score2--;
    if(score2 < 0) { score2 = 0; }
    refreshDisplay();
    delay(btnDelay);
  }
}

Any sugestions how to do it?
Thanks.

counter.ino (5.03 KB)

If your requirement is to be able to disconnect an I2C LCD you should have

  1. an procedure for it (like dismounting USB stick)

  2. keep a state variable that reflects the connectedness of the LCD.
    if not connected, do not print anything to it.

robtillaart:
If your requirement is to be able to disconnect an I2C LCD you should have

  1. an procedure for it (like dismounting USB stick)

  2. keep a state variable that reflects the connectedness of the LCD.
    if not connected, do not print anything to it.

I'm afraid that this won't help. I remembered that I2Cscanner check's if there is device on the address, so I copied the way how this is done and I'm using LCD only when it's connected. But when I disconnect it, it still doesn't work.

I commented ALL the lines that are using LCD, so only line with LCD is where I create the LCD object, the line LiquidCrystal_I2C lcd(LCDaddress, 16, 2);. But when I disconnect the LCD, everything again stops working. And when LCD is disconnected when I power up Arduino, it won't works.

I tried adding printing to serail after every line of code in setup, and when LCD is disconnected, it crahes right at the Wire.begin(); line, before the LCD could be initialized. I thought it might be called in the LCD library, so I removed it, but it crasher at Wire.endTransmission();

OK,
Can you try to make a minimal program that still shows the problem?

Which version of the IDE are you using?

note: Wire.Endtransmission() does the actual sending of the buffer. It has a return value that can indicate some errors.