LCD goes crazy when I use tact switch

The setup:
Arduino Mega, LCD 2x16 (checked with 4x20), 4 buttons in pull-down configuration (100K Ohms to GND) in addition each one using a diode provides HS to interrupt, USB powering. There is common GND for buttons and LCD.
LCD R/W pin is grounded.
Problem:
I believe it is only a hardware problem. When I press any button, not always, LCD starts to flicker and shows garbage. I know that the uC still works because (it operates LEDs and other things). The board has to be reset.
Other observations:
I know that USB power is somehow stable. When I power only from external adapter +12V it is even more unstable - I can see that displayed characters are 'waving' more or less 50Hz. Quite similar when I power from +12 from computer power supply (this is stable for sure).
When I swap to bigger LCD 4x40 it is more sensitive and goes crazy much faster and really doesn't work with external +12 (powered via arduino board).
With smaller LCD and USB power only, usually when I press a button and hold it for a few seconds it doesn't cause any problems. Seems that problem occurs only if press-release a few times.

The code for buttons...

void ButtonCall() {
  noInterrupts();
  if (abs(millis() - last_btn) > 200) {
    if (screensaver) {
      lightPWM = ScreenConfig.lightPWMhigh;
      analogWrite(backLight, lightPWM);
    }
    else if (digitalRead(btn_min)) {
      screen_pnt->btn1();
    }
    else if(digitalRead(btn_pls)) {
      screen_pnt->btn2();
    }
    else if(digitalRead(btn_ent)) {
      screen_pnt->btn3();
    }
    else if(digitalRead(btn_esc)) {
      screen_pnt->btn4();
    }
    last_btn = millis();
    screensaver = false;
    lcd.clear();
  }  
  interrupts();
}

attachInterrupt(0, ButtonCall, HIGH);

To be safe for debounce I have not only 200ms interval but also deactivate interrupts.

So... any suggestions?

Is there anything you are not telling us ?

What is this ?

if (screensaver) {
      lightPWM = ScreenConfig.lightPWMhigh;
      analogWrite(backLight, lightPWM);

Please post a schematic of EVERYTHING connected to uC and ALL declarations/definitions.
You have an analogWrite statement yet you have not declared any I/O.
You have not void Setup() or void loop().
Where is the rest of your code ?

What's missing? I assume he's trying to vary the brightness of the LCD backlight using PWM, I imagine the goal is to save power and potentially adapt to ambient lighting. The LCD is mentioned, I presume it's implied that all normal LCD pins are connected, including the backlight, with RW excepted as mentioned.

IMHO, the problem is either drawing too much current somewhere, or else it's noise pickup due to the PWM passing a long earth wire. If the latter feature is enabled I'd try disabling it for test purposes.

There is vagueness about the external power supply, i.e. 12V is mentioned, but not the current limit or the current required.

I note the built in assumption that the backlight is always an LED. I don't know if that assumption is correct.

DonMilne:
What's missing? I assume he's trying to vary the brightness of the LCD backlight using PWM, I imagine the goal is to save power and potentially adapt to ambient lighting. The LCD is mentioned, I presume it's implied that all normal LCD pins are connected, including the backlight, with RW excepted as mentioned.

IMHO, the problem is either drawing too much current somewhere, or else it's noise pickup due to the PWM passing a long earth wire. If the latter feature is enabled I'd try disabling it for test purposes.

There is vagueness about the external power supply, i.e. 12V is mentioned, but not the current limit or the current required.

I note the built in assumption that the backlight is always an LED. I don't know if that assumption is correct.

Correct :).
12V power adapter can provide 1500mA. The board is 'mainly' stable when powered only from USB (500mA).
I was trying the configuration without PWM. So the LCD back light was directly wired to +5 and GND. Problem still exists.
My suspect is a tact switch. Can it produce any noise? Like coil relay (I saw a topic somewhere that relays should be powered from separate source to not interfere with LCDs)?

It is not that I want to hide anything. The code is ... growing and mainly in Polish so it may be hard to understand it :slight_smile: Schematics - I don't have them yet, will post later tomorrow as it is now 1am.

if (screensaver) {
      lightPWM = ScreenConfig.lightPWMhigh;
      analogWrite(backLight, lightPWM);

analogWrite here controls LCD backlight using PWM. The 'if' statement is just to 'wake up' the LCD when a button is pressed the firs time. And then the next press actually do something.

The loop

void loop () {
  sprawdz_godzine(); //check time
  os1.checkState(sys); //
  os2.checkState(sys);
  checkDHT11(); //check sensor
  wyswietl(); //display on LCD see function below
}

The wyswietl() function

void wyswietl () {
  if (ScreenConfig.screensaver_flg && abs(millis()-last_btn)> ScreenConfig.screensaver_time) {//screen saver on
    screensaver = true;
    if (lightPWM>ScreenConfig.lightPWMlow)
      lightPWM --;
    analogWrite(backLight, lightPWM);
  }
  screen_pnt->show(&lcd);
/*
screen_pnt is a pointer to an instance of class responsible for UI of a certain page. So it actually displays text on LCD and contains methods for buttons. 
*/
}

And two of UI classes, there are tons of them and usually looks the same. Screen class is just a stub. Screen10 class the right one. I needed parent-child to play with their references.

class Screen {
public:
  Screen** screen_ptn; 
  Screen* next;
  Screen* prev;
  Screen* esc;
  Screen* ent;
  String menu;
  virtual void show(LiquidCrystal* lcd){
  }
  virtual void btn1(){
    Serial.println("Screen::btn1 click");      
  }
  virtual void btn2(){
    Serial.println("Screen::btn2 click");      
  }
  virtual void btn3(){
    Serial.println("Screen::btn3 click");      
  }
  virtual void btn4(){          
    Serial.println("Screen::btn4 click");      
  }

};

class Screen10 : 
public Screen {
public:
  int i;
  virtual void show (LiquidCrystal* lcd) {
    int tmp1 = i;
    int tmp2 = i;
    tmp1--;
    tmp2++;
    if (tmp1<1) tmp1 = 6;
    if (tmp2>6) tmp2 = 1;
    lcd->setCursor(0,0);
    lcd->print(writeln(&MENU_STR[tmp1-1], "  "));
    lcd->setCursor(0,1);
    lcd->print(writeln(&MENU_STR[i-1], String(char(RIGHT_ARROW))+" "));
    lcd->setCursor(0,2);
    lcd->print(writeln(&MENU_STR[tmp2-1], "  "));
    lcd->setCursor(0,3);
    lcd->print(STR_BOTTOM_MENU_DEF);
  }
  virtual void btn1(){
    *screen_ptn = next;    
  }
  virtual void btn2(){ 
    *screen_ptn = prev;
  }
  virtual void btn3(){
    *screen_ptn = ent;
  }
  virtual void btn4(){//esc
    *screen_ptn = esc;  
  }  

};

And the schematics for LCD and buttons

Schematic Prints2.pdf (8.3 KB)

The contrast pot should be no less than 10k ohm and should have +5V on the terminal that is not connected.
The backlight control is fine.
I see no reason for the symptoms exhibited . Do you have a meter you can you to do a continuity check between
the Arduino pins used to verify there is no short ?
Have you tried commenting out your button service routine and running it to see if the symptom goes away
to rule out a possible code error ?

The pot - sorry it is 22k. I connected the second terminal to +5. No difference.

But... I have modified the loop code slightly.

void loop () {
  sprawdz_godzine();
  os1.checkState(sys);
  os2.checkState(sys);
  checkDHT11();
[b]  noInterrupts();
  wyswietl();
  interrupts();
[/b]}

I have added noInterrupts and interrupts functions around the function that displays things on LCD.
Looks like it is working fine on USB power and 16x2 LCD (well... my 20x4 LCD released smoked soul when I connected it to +12 by mistake :). I have to redo the rest of the code.
But still, it is not perfect. When powered from +12V external adapter, text on the LCD still 'waves' and blinks and buttons doesn't work now. Looks like LCD doesn't get smooth power, so it is not stable and the communication with uC takes longer. Unfortunately I don't have an oscilloscope to exam the power source.
When powered from +12V computer PS it works fine.

What is the voltage for "Vcc" on your schematic ?
I thought all those LCDs only run on +5V, not 12V . Can you clarify what you mean by +12V power adaptor ?
(ie: INPUT VOLTAGE=/OUTPUT VOLTAGE=_)

Vcc is what Arduino board gives on +5V.