It is possible, but it’s a bit tricky:
-
It requires you to send a CTL-R at 9600 baud as soon as the splash screen is displayed to reset the baud rate to 9600.
-
Once this is done, you actually have to send the commands to physically set the baud-rate to 9600 baud, otherwise it won’t stick when you reboot the display.
-
Then, you might have to reset the display brightness, cursor type, or other things.
The big problem with this is that you either have to have access to a serial terminal that can send commands to the LCD during it’s power-up, or if you were using an Arduino sketch, a way to sync power and the CTL-R command.
What I did to reset mine was to use a Seeed motor shield (to control power), and snippits of Sparkfun’s “Fake_Data” demo, to send commands to the LCD display. Even though I used the Seeed motor shield, (because it was what I had), you could probably do this with any motor shield that allows you to completely turn off power to the external device, and lets you tie the “device” power to the Arduino +5 since the current drain from the LCD is negligible.
Here is the sketch I used. It’s a bit long because I include a lot of explanatory text and comments.
/*
ResetLCD uses code from both the LCD FakeData and Seeed stepper
sketches to create a sketch to do a force-reset on the
SparkFun 16x2 LCD display
Theory:
If the SparkFun LCD display module gets fed garbage, it can get itself
into a bizarre and unknown state - especially if the baud-rate gets
set to something unknown.
Within section 3.4, (Changing the LCD Baud Rate), of the SparkFun LCD
datasheet, (SerLCD_V2_5.PDF at www.sparkfun.com), the datasheet tells
us that we can reset the baud-rate to 9600 baud if we send a CTRL-R
character during the LCD module's startup process - while the logo
screen is, (should be), displayed.
One issue is that the reset command has to be sent to the LCD very quickly
after power has been applied in order for it to work properly.
To accomplish this we used an Arduino Uno, an Arduino prototyping
shield, and a Seeed Motor shield.
The Arduino gives us a way to control both the LCD display module's
power and the serial data sent to it.
The prototyping shield gives us a place to attach the serial and ground
wires from the LCD display module.
The Seeed motor control shield allows us to apply, and remove, power
under program control by connecting the LCD's power pin to pin 1 of
the DC motor control power pins.
====================================================*/
// Use the softwareserial library to create a new "soft" serial port
// for the display. This prevents display corruption when uploading code.
#include <SoftwareSerial.h>
/* Define the motor power output control pins.
These pins control power to the four DC motor control pins
on the Seeed motor controller */
int power_1 = 8; // This is the pin connected to the LCD
int power_2 = 11; // But you could use any one of these you want
int power_3 = 12; // If you use pins 3 or 4, you have to swap the
int power_4 = 13; // two enable statements - a to off, b to on.
/* Define the two enable pins on the Seeed motor controller shield
The two enable pins enable the motor power pairs 1 - 2 and 3 - 4
respectively
enable_a enables the 1&2 pair
enable_b enables the 3&4 pair
*/
int enable_a = 9;
int enable_b = 10;
// We define certain command and control constants here
int cntrl_r = 18; // CTRL-R = 0x12 or decimal 18
int display_cfg = 124; // Begins a display configuration command
int display_fmt = 254; // Begins a display formatting command
int lcdbright = 142; // Sets backlight brightness 128 - 157 (142 is half-bright)
int firstline = 128; // Beginning of first line on first row
int lcdoff = 0x08; // Disable display
int lcdon = 0x0C; // Re-enable display and turn off anything fancy
// Attach the serial display's RX line to digital pin 2
SoftwareSerial mySerial(3,2); // pin 2 = TX, pin 3 = RX (unused)
// The setup routine only runs once when you press reset.
void setup() {
// initialize the four coil control pins as outputs on the Arduino
pinMode(power_1, OUTPUT);
pinMode(power_2, OUTPUT);
pinMode(power_3, OUTPUT);
pinMode(power_4, OUTPUT);
// initialize the two enable control pins as outputs too.
pinMode(enable_a, OUTPUT);
pinMode(enable_b, OUTPUT);
// set all power output pins low - nothing turned on yet
digitalWrite(power_1, LOW);
digitalWrite(power_2, LOW);
digitalWrite(power_3, LOW);
digitalWrite(power_4, LOW);
/* set enable a high and enable b low - we only need pair 1-2 active
to control power to the LCD module. */
digitalWrite(enable_a, HIGH);
digitalWrite(enable_b, LOW);
mySerial.begin(9600); // set up serial port for 9600 baud
} // End "setup" block
/*
The "loop" structure works identically to a forever loop;
for(ever), if(1), while(1), etc., as it repeats the block of code
until reset - or Hell freezes!
*/
void loop() {
/*
This first part applies power to the LCD display module, and while the
module is doing its "initialize" thing - we bit-bang it with the baud-rate
reset command.
If we're lucky, the LCD module will catch this and reset itself.
*/
// We start by turning power on to the LCD so we can start the reset process
digitalWrite(power_1, HIGH); // Turn on +5 to LCD
// Next we "bit-bang" CTRL-R repeatedly to reset the baud rate
// (The number of iterations here was entirely arbitrary.)
mySerial.write(cntrl_r); // attempt to clear baud rate to 9600
mySerial.write(cntrl_r);
mySerial.write(cntrl_r);
mySerial.write(cntrl_r);
mySerial.write(cntrl_r);
mySerial.write(cntrl_r);
mySerial.write(cntrl_r);
mySerial.write(cntrl_r);
mySerial.write(cntrl_r);
mySerial.write(cntrl_r); // and hope it sticks!
/*
It appears that the baud-rate force-reset, (CTRL-R), only performs a *SOFT* baud-rate reset.
Apparently, after soft-resetting the baud rate to something sane, you must also
"formally" set the baud rate using a standard display mode set command emitting a CTRL-M,
otherwise the reset baud-rate is not committed to EEPROM memory.
*/
/* First, we set and **commit** the correct default baud-rate (9600) by emitting a
CTRL-M (0x0D) after giving the chip some settling time.
*/
delay(500);
mySerial.write(display_cfg);
mySerial.write(0x0D); // Set and commit baud rate to 9600
delay(1000); // give the command time to finish.
// Next, we cycle the display enable to reset the display and clear any fancy settings
mySerial.write(display_fmt); // Signal display format command
mySerial.write(lcdoff); // Set LCD off
delay(500);
mySerial.write(display_fmt); // Signal display format command
mySerial.write(lcdon); // Set LCD back on again
delay(500);
// Then, we increase the display brightness in case it was turned off
mySerial.write(display_cfg); // Signal display function command
mySerial.write(lcdbright); // Set backlight brightness
delay(500);
// Here we restart the LCD to verify that the settings were committed.
digitalWrite(power_1, LOW); // Turn off +5 to LCD
delay(1000);
digitalWrite(power_1, HIGH); // Turn on +5 to LCD
// Once we've done that, we need to give the LCD module time to catch
// its breath and restart.
delay(1500);
/*
At this point - if all has gone well - we should be back in business!
so we try to indicate this by displaying something "normal"
*/
// Here we try to display a success message
mySerial.write(display_fmt); // move cursor to beginning of first line
mySerial.write(firstline);
mySerial.write(" "); // clear display
mySerial.write(" ");
mySerial.write(display_fmt); // move cursor to beginning of first line
mySerial.write(firstline);
mySerial.write(" Display Reset "); // display success
mySerial.write(" is Successful! "); // message
delay(2000); // give the display time to be read before trying again
mySerial.write(display_fmt); // move cursor to beginning of first line
mySerial.write(firstline);
mySerial.write("Remove Power and"); // display success
mySerial.write(" Disconnect LCD "); // message
delay(2000); // give the display time to be read before trying again
digitalWrite(power_1, LOW); // Turn the display back off so we can try again
delay(2000);
} // . . . and so on.
Hopefully this will do someone some good.
Jim (JR)