How to stop flickering of LCD using Arduino Code? - Page 1
Forum section: electronics / general

author: radhika
author_rank: Regular Contributor
timestamp: June 09, 2018, 06:46:54 pm
content: Hello,I am new to Arduino coding. I have developed a menu code where 5V 1A, 5V 2A, 5V 3A are a different option. These options get ON and OFF with the help of 3 buttons which is UP, DOWN and SELECT.The LCD displays correct output in Proteus, but it flickers a lot. I am unable to get the stable output. Please guide me.Here is the attached code:#include<LiquidCrystal.h>LiquidCrystal lcd(12, 11, 5, 4, 3, 2);int menuitem = 1;int page = 1;int oneamp = 6; // This is the output pinsint twoamp = 7;int threeamp = 8;volatile boolean up = false; //BUTTONvolatile boolean down = false;volatile boolean select = false;int downButtonState = 0;int upButtonState = 0;int selectButtonState = 0;int lastDownButtonState = 0;int lastSelectButtonState = 0;int lastUpButtonState = 0;void setup() {lcd.begin(16, 2);lcd.setCursor(1,0);pinMode(9, INPUT_PULLUP);pinMode(1, INPUT_PULLUP);pinMode(0, INPUT_PULLUP);pinMode(oneamp, OUTPUT);pinMode(twoamp, OUTPUT);pinMode(threeamp, OUTPUT);Serial.begin(9600);}void loop() {drawMenu();downButtonState = digitalRead(1);selectButtonState = digitalRead(0);upButtonState = digitalRead(9);oneamp = digitalRead(6);twoamp = digitalRead(7);threeamp = digitalRead(;checkIfDownButtonIsPressed();checkIfUpButtonIsPressed();checkIfSelectButtonIsPressed();if (up == 1 ){up = false;menuitem--;if (menuitem==0){menuitem=3;{if (select = 1){digitalWrite( oneamp, HIGH );digitalWrite( twoamp, LOW );digitalWrite( threeamp, LOW );}else{digitalWrite( oneamp, LOW );digitalWrite( twoamp, LOW );digitalWrite( threeamp, LOW );}}}}if (down == 1 ){down = false;menuitem++;if (menuitem==4){menuitem=1;{if (select = 1){digitalWrite( oneamp, LOW );digitalWrite( twoamp, HIGH );digitalWrite( threeamp, LOW );}else{digitalWrite( oneamp, LOW );digitalWrite( twoamp, LOW );digitalWrite( threeamp, LOW );}}}}if (menuitem == 5 ){menuitem=2;{if (select = 1){digitalWrite( oneamp, LOW );digitalWrite( twoamp, LOW );digitalWrite( threeamp, HIGH );}else{digitalWrite( oneamp, LOW );digitalWrite( twoamp, LOW );digitalWrite( threeamp, LOW );}}}}void checkIfDownButtonIsPressed(){if (downButtonState != lastDownButtonState){if (downButtonState == 0){down=true;}delay(50);}lastDownButtonState = downButtonState;}void checkIfUpButtonIsPressed(){if (upButtonState != lastUpButtonState){if (upButtonState == 0) {up=true;}delay(50);}lastUpButtonState = upButtonState;}void checkIfSelectButtonIsPressed(){if (selectButtonState != lastSelectButtonState){if (selectButtonState == 0) {select=true;}delay(50);}lastSelectButtonState = selectButtonState;}void drawMenu(){if (page==1){lcd.clear();lcd.setCursor(1, 0);lcd.print("MAIN MENU");if (menuitem==1){lcd.setCursor(1, 1);lcd.print(">5V 1A:");if (select = 1){lcd.print("ON");}else{lcd.print("OFF");}}if (menuitem==2){lcd.setCursor(1, 2);lcd.print(">5V 2A: ");if (select = 1){lcd.print("ON");}else{lcd.print("OFF");}}if (menuitem==3){lcd.setCursor(1, 3);lcd.print(">5V 3A:");if (select = 1){lcd.print("ON");}else{lcd.print("OFF");}}}}

author: dmills
author_rank: Super Contributor
timestamp: June 09, 2018, 06:56:49 pm
content: Horrible code, but anyway, you only want to redraw the LCD if something has changed, so do something likeint redraw = 1;then in the main loop :if (redraw){drawMenu();redraw = 0;}Then in your button handlers set redraw to 1 if a button has been pressed.Regards, Dan.

author: janoc
author_rank: Super Contributor
timestamp: June 09, 2018, 07:21:53 pm
content: I won't give you a solution because this is a very good learning problem and you will like it better when you figure it out yourself. But I will give you a few hints:* Why does an LCD flicker? (let's assume there are no hardware faults) Flicker usually means rapid changing between the pixels being on and off. Try to think about what in your code could make this happen.* Once you figure out the above, try to identify where in your code you are making the pixels flip back and forth.* Also keep in mind that these small LCDs are not like computer screens where you can afford to wipe the entire screen on every "frame" and draw from scratch. There is no double buffering neither and the display is rather slow, you may actually have towaitfor it to finish whatever it is doing before you attempt to send another thing to it instead of "blasting" it with data in a loop.So you may want to rethink you approach.

author: radhika
author_rank: Regular Contributor
timestamp: June 09, 2018, 07:30:21 pm
content: Hello,I have added the required redraw in main loop. I have checked the result but it still flickers.

author: Cyberdragon
author_rank: Super Contributor
timestamp: June 09, 2018, 07:46:42 pm
content: Quote from: dmills on June 09, 2018, 06:56:49 pmInt? Don't you mean boolean?

author: dmills
author_rank: Super Contributor
timestamp: June 10, 2018, 01:22:15 am
content: Ick, C++, yea bool, but really whatever, it is not the worst thing in that code.Regards, Dan.

author: Nusa
author_rank: Super Contributor
timestamp: June 10, 2018, 01:53:43 am
content: Those simple LCD's really are slow enough for the eye to perceive changes, so screen clears are going to be visible in the general case. Also, I suggest that you use actual hardware before deciding what's acceptable. Hardware simulations are not perfect.For your specific case, I suggest commenting out the lcd.clear entirely. Then change "ON" to "ON " in all places. That way "ON " and "OFF" have the same number of characters and will overwrite one another completely when they get changed. You should no longer NEED to clear the screen unless you change to a completely different menu. That should eliminate the flicker effect.

author: Monkeh
author_rank: Super Contributor
timestamp: June 10, 2018, 02:19:29 am
content: Quote from: dmills on June 10, 2018, 01:22:15 amWe've had boolean in C for nearly 20 years. It's not 1972 any more.

author: amyk
author_rank: Super Contributor
timestamp: June 10, 2018, 03:38:05 am
content: Might want to fix this first:Code:if (select = 1)Agree with the others here, this ishorriblecode. There is anexcruciatingamount of duplication. Also, responding to buttons and changing the settings should be done in an interrupt handler, since there's nothing to be done "in the background", and the MCU should be just halted waiting for an interrupt the majority of the time.Learn to do the above, use the ?: operator, and simplify your code by removing/refactoring repeated pieces. That will get you 90% of the way to a good solution.

author: janoc
author_rank: Super Contributor
timestamp: June 10, 2018, 10:27:22 am
content: I just love how everyone is lecturing the poor newbie about how bad and horrible the code is (it is) but nobody actually answers their question ...Quote from: radhika on June 09, 2018, 07:30:21 pmOf course it does flicker.The problem is that you areclearingthe display andredrawingit from scratch onevery iterationof the main loop (the loop() function). Don't do that!The display isn't fast enough to update that quickly, so you will have weird artifacts, flicker and what not. It may even crash the display controller (depends on whether or not the LCD library actually waits for the ready signal from the LCD/you have it connected). It is also a terrible approach from the power consumption point of view because the MCU is constantly busy looping and blasting data into the LCD even when nothing is changing (no buttons are being pressed).The proper way to do this is to redraw the display (either fully or partially) only when the user presses a button and you need to actually change something. That can be done in various ways - e.g. using an interrupt to read the buttons and triggering the redrawing there, polling the buttons in the loop() and redrawing the display only when a button was pressed and not every time.The button debouncing code - don't put delay() there, that will just slow down the entire processing. If you don't want to implement your own debouncer, the Bounce2 library is a good choice for doing it for you:https://github.com/thomasfredericks/Bounce2If you want to make your own debouncer, then this series is a great start (the actual debouncers are in the part two linked at the bottom):http://www.ganssle.com/debouncing.htm

author: mariush
author_rank: Super Contributor
timestamp: June 10, 2018, 10:46:55 am
content: so tldr:redraw lcd only if stuff actually changesfor debouncing consider using a ceramic capacitor and a resistor, they're cheap and you basically get hw debounce.

author: janoc
author_rank: Super Contributor
timestamp: June 10, 2018, 11:51:14 am
content: Quote from: mariush on June 10, 2018, 10:46:55 amThat's actually a fairly terrible idea and doesn't work properly. Even if the MCU has Schmitt trigger inputs (most don't) it still has issues - check the article I have linked above for explanation why (http://www.ganssle.com/debouncing-pt2.htm) and how to make it work if you really want to use this type of solution.

author: PlainName
author_rank: Super Contributor
timestamp: June 10, 2018, 02:44:13 pm
content: As world+dog has pointed out, clearing the screen every time you do something is going to cause flicker. A pretty decent fix for this particular project is the one where ON and OFF are the same length (i.e. 'ON ' and 'OFF') then you can just write the correct one in place when needed and it'll overwrite the unwanted one without any screen clearing.However, that won't help in projects where the screen display isn't so simple or convenient. There is also the issue of having to slow down to the screens input speed.What I would do is double-buffer the display. That is, have a copy of the display in memory and all the functions write to that. The physical display is then updated from the virtual one (either in a loop or via a timer) and only changes are copied, so there is no flickering, no waiting for the display to catch up, and because the physical display writes are minimal it's jolly fast. There are other advantages too, but it'd be too tedious to list them all

author: Nusa
author_rank: Super Contributor
timestamp: June 10, 2018, 03:11:40 pm
content: Quote from: janoc on June 10, 2018, 10:27:22 amIncluding yourself. I love how people fail to read prior responses. Pretty sure I answered the actual question above, without criticizing the code.

author: tsman
author_rank: Frequent Contributor
timestamp: June 10, 2018, 03:21:35 pm
content: Quote from: radhika on June 09, 2018, 06:46:54 pmYou're using the oneamp/twoamp/threeamp variables to store the pin number for later calls to digitalWrite but then you overwrite those variables with 0/1 with digitalRead. Take out these 3 digitalRead calls.Quote from: radhika on June 09, 2018, 06:46:54 pmQuote from: radhika on June 09, 2018, 06:46:54 pmAs amyk pointed out, these lines are wrong. You're actually assigning 1 to select. You need to do == to test for equality.

author: radhika
author_rank: Regular Contributor
timestamp: June 10, 2018, 04:53:56 pm
content: Hello there,I know it's horrible code. But, for me it is an excellent one. I learnt Arduino so quick and code long one.I found the error, that I just need to remove lcd.clear().Thank You for guidance and help.#a5Radhika Das

author: radhika
author_rank: Regular Contributor
timestamp: June 10, 2018, 08:06:19 pm
content: I have redraw the code, here it won't flicker anymore. But, when I press rewuired button to select let say 5V 1A, it won't turn ON LED attached to it. Here is the code:#include<LiquidCrystal.h>LiquidCrystal lcd(12, 11, 5, 4, 3, 2);int menuitem = 1;int page = 1;boolean oneamp = false;boolean twoamp = false;boolean threeamp = false;int oneampState = 0;int twoampState = 0;int threeampState = 0;volatile boolean up = false;volatile boolean down = false;volatile boolean select = false;int downButtonState = 0;int upButtonState = 0;int selectButtonState = 0;int lastDownButtonState = 0;int lastSelectButtonState = 0;int lastUpButtonState = 0;void setup() {lcd.clear();lcd.begin(16, 2);lcd.setCursor(1,0);pinMode(9, INPUT_PULLUP);pinMode(1, INPUT_PULLUP);pinMode(0, INPUT_PULLUP);pinMode(6, OUTPUT);pinMode(7, OUTPUT);pinMode(8, OUTPUT);digitalWrite(6, LOW);digitalWrite(7, LOW);digitalWrite(8, LOW);Serial.begin(9600);}void loop() {drawMenu();downButtonState = digitalRead(1);selectButtonState = digitalRead(0);upButtonState = digitalRead(9);oneampState = digitalWrite(6);twoampState = digitalWrite(7);threeampState = digitalWrite(;checkIfDownButtonIsPressed();checkIfUpButtonIsPressed();checkIfSelectButtonIsPressed();if (up == 1 ) //UP Button Menuitem Logics{up = false;menuitem--;if (menuitem==0){menuitem=1;}if (menuitem==2){menuitem=1;}if (menuitem==3){menuitem=2;}}if (down == 1 ) //DOWN Button Menuitem Logics{down = false;menuitem++;if (menuitem==1){menuitem=2;}if (menuitem==2){menuitem=3;}if (menuitem==3){menuitem=3;}}if (select == 1){select = false;if(menuitem==1){if(oneamp){digitalWrite( oneampState, HIGH );digitalWrite( twoampState, LOW );digitalWrite( threeampState, LOW );}else{digitalWrite( oneamp, LOW );digitalWrite( twoamp, LOW );digitalWrite( threeamp, LOW );}}if (menuitem==2){if(twoamp){digitalWrite( oneamp, LOW );digitalWrite( twoamp, HIGH );digitalWrite( threeamp, LOW );}else{digitalWrite( oneamp, LOW );digitalWrite( twoamp, LOW );digitalWrite( threeamp, LOW );}}if (menuitem==3){if (threeamp){digitalWrite( oneamp, LOW );digitalWrite( twoamp, LOW );digitalWrite( threeamp, HIGH );}else{digitalWrite( oneamp, LOW );digitalWrite( twoamp, LOW );digitalWrite( threeamp, LOW );}}}}void checkIfDownButtonIsPressed(){if (downButtonState != lastDownButtonState){if (downButtonState == 1){down=true;}delay(50);}lastDownButtonState = downButtonState;}void checkIfUpButtonIsPressed(){if (upButtonState != lastUpButtonState){if (upButtonState == 1) {up=true;}delay(50);}lastUpButtonState = upButtonState;}void checkIfSelectButtonIsPressed(){if (selectButtonState != lastSelectButtonState){if (selectButtonState == 1) {select=true;}delay(50);}lastSelectButtonState = selectButtonState;}void drawMenu(){if (page==1){lcd.setCursor(1, 0);lcd.print("MAIN MENU");if (menuitem==1){lcd.setCursor(1, 1);lcd.print(">5V 1A: ");if (oneamp){lcd.print(" ON ");}else{lcd.print(" OFF ");}}if (menuitem==2){lcd.setCursor(1, 2);lcd.print(">5V 2A: ");if (twoamp){lcd.print(" ON ");}else{lcd.print(" OFF ");}}if (menuitem==3){lcd.setCursor(1, 3);lcd.print(">5V 3A: ");if (threeamp){lcd.print(" ON ");}else{lcd.print(" OFF ");}}}}

author: tsman
author_rank: Frequent Contributor
timestamp: June 10, 2018, 08:43:16 pm
content: You've got the pin variables all mixed up and weird in your latest version. oneamp/twoamp/threeamp used to be storing the pin number but you've changed it to be a boolean i.e. true/false variable instead now. Change it back to ints and set the pin numbers again.Code:boolean oneamp = false;boolean twoamp = false;boolean threeamp = false;Your calls to digitalWrite are a mixture of oneamp and oneampState. Change it back. oneampState/twoampState/threeampState are all useless and can be removed along with the calls to digitalRead.Code:digitalWrite( oneampState, HIGH );digitalWrite( twoampState, LOW );digitalWrite( threeampState, LOW );}else{digitalWrite( oneamp, LOW );digitalWrite( twoamp, LOW );digitalWrite( threeamp, LOW );I've no idea what you're trying to do with this chunk of code with menuitem. If menuitem is 1 or 2 then it'll just set it to 3.Code:if (menuitem==1){menuitem=2;}if (menuitem==2){menuitem=3;}if (menuitem==3){menuitem=3;}

author: Cyberdragon
author_rank: Super Contributor
timestamp: June 11, 2018, 04:31:32 am
content: The menu item code doesn't make sense. You are already using the incrementor (++) decrementor (--) which would do the same thing. Except you also have it trying to go to from zero to one in the decriment section, but since you decrimented before, it would be -1 before it reached and conditions and fail. Have it increment or decriment inside of the condition that checks the valueso if 0 add 1, if 2 subtract 1, exc. You could also eliminate the if 3 change to 3. Just use "else {}" and it will skip that (or any other) condition.(I love how the server turned a piece of code into an emote)EDIT: it's not in a code block, that's why

author: Raj
author_rank: Frequent Contributor
timestamp: June 11, 2018, 04:51:21 am
content: what are you trying to achieve BTW?Reading a sensor?learning to make menus?proper project?Prettyprinting is a must for codes.Simply put some delays in your code and vola,it'll be good enoughalso,increase the clock speed to 16mhz if its 8mhz right now.(will require 5v as power source)you've initialized Serial with Serial.begin(9600); but I don't see you using serial anywhere throughout the codeI'd suggest,you make a flow chart first,and then start typing code for it.Here's a suggestion-have all button inputs on single portset a timer in backgroundthe code starts,prints onto lcd whatever it's supposed towait for port with buttons to changeif change to port with button occurs,read sensors if any,redraw lcd,reset timerif timer overflows,read sensors if any and redraw lcdalso try Atmel Studio,it's way better than arduino.I only use arduino when I have to work with OLED (cause I haven't gotten time to read it's datasheet so far).

author: radhika
author_rank: Regular Contributor
timestamp: June 11, 2018, 08:54:32 am
content: Quote from: tsman on June 10, 2018, 08:43:16 pmThis really work. I added oneamp in boolean, that is why my circuit is not working. But, after making it int back and removing oneampState, code work much better.Thanks for your guidance.#a5Radhika Das

author: @rt
author_rank: Super Contributor
timestamp: June 11, 2018, 09:25:46 am
content: You can certainly dynamically update a character LCD with no perceivable flicker, but you need your data ready to write at once, straight after clearing,or better still, it’s a character LCD, and doesn’t need clearing. You can simply overwrite the display for each iteration of the main loop.Either way there should only be a single instance in the program that writes to the LCD.The other routines can write to an LCD data buffer, rather than writing to the LCD itself.

author: Raj
author_rank: Frequent Contributor
timestamp: June 11, 2018, 10:02:26 am
content: Coding with Arduino is done best if you make a flow chart first.If you rewrite your program that way,I bet,it'll be smaller,faster,flawless

author: amyk
author_rank: Super Contributor
timestamp: June 11, 2018, 11:26:45 am
content: Code:if (menuitem==1){menuitem=2;}if (menuitem==2){menuitem=3;}if (menuitem==3){menuitem=3;}Code:menuitem += menuitem < 3;