Go Down

Topic: 16x1 LCD not working as expected? (Read 352 times) previous topic - next topic

wilykat

Dec 15, 2017, 07:17 am Last Edit: Dec 15, 2017, 07:19 am by wilykat
Got a new 16x1 LCD in today but it's not working as I expected.  When I print a string to it that is longer than 8 but not longer than 16 characters, only 8 characters are printed.  I did some testing to verify wiring is correct and used a 16x2 LCD I had around.  Video of it in action

https://youtu.be/YEBPrTObj9s

If I printed a string of 9 to 16 characters to 16x2, all are on one line but if I printed one string to 16x1 display, only the first 8 are printed.  The test I did shows the other 8 are working but it's on second line!  It's like I got 8x2 display with 16x1 LCD panel.

Did I get a lemon? There's only 2 sets of solder pads on the back.  Backside of the panel:


quick edit: if it's not a lemon but a quirk of Nx1 displays, how would I split a string so the first 8 are on first line and second 8 characters are on second line so it'd appear to be unbroken 16 character line?

floresta

#1
Dec 15, 2017, 03:33 pm Last Edit: Dec 15, 2017, 03:36 pm by floresta
Quote
It's like I got 8x2 display with 16x1 LCD panel.
That's pretty much what you have!

Quote
quick edit: if it's not a lemon but a quirk of Nx1 displays, how would I split a string so the first 8 are on first line and second 8 characters are on second line so it'd appear to be unbroken 16 character line?
It's a quirk of most 16x1 displays.

You have to tell the library that it is an 8x2 display and then you re-position the cursor to the start of the 'second' line in order to put characters on the right half of the display screen.  You pretty much figured this out already.

For all the gory details follow the LCD Addressing link at http://web.alfredstate.edu/faculty/weimandn .

Don

wilykat

Ok so I'd need to figure a way to split the variable across 2 "lines".  Here's my entire code:
Code: [Select]

// unused Arduino pin: 6,14-18 (A0-A4)  (AVR 12, 23-27)
#include <LiquidCrystal.h>
int LCDLED = 13;                                 // backlight LED pin AVR 18
int buttonup = 2;                                // pin to connect the UP button  AVR 4
int buttondn = 3;                             // pin to connect the DOWN button AVR 5
int presses = 0;                              // variable to store number of presses
long dtime = 0;                              // used for 'since last press'
long debounce = 200;                            // how many ms to "debounce"
long idletime = 15000;                           // about 15 seconds for display idle before turning off LED
const byte numPins = 5;                          // just 5 pins (4 pins to 75154, 5th to enable for either second '154 or '138
int state;                                // used for HIGH or LOW
byte pins[] = {19, 0, 1, 4, 5};                  // pins to connect to 74154 AVR 28, 2, 3, 6, 11
const int rs = 7, en = 8, d4 = 9, d5 = 10, d6 = 11, d7 = 12; // AVR 19, 23, 24, 25, 26, 27
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);


char* gameSys[] = {"   Atari 5200   ",           
                   "   Atari 7800   ",
                   " Intellivision  ",
                   "  Colecovision  ",
                   "    Nintendo    ",
                   " Super Nintendo ",
                   "   Nintendo 64  ",
                   "    Gamecube    ",
                   " Genesis CD 32X ",
                   "  Sega Saturn   ",
                   "   Dreamcast    ",
                   "   Turbo Duo    ",
                   "  Playstation   ",
                   " Platstation 2  ",
                   "   Sony PSP     ",           // portable system via AV cable + Bluetooth PS3 controller
                   "      ---1      ",
                   "      ---2      ",
                   "      ---3      ",
                   "      ---4      ",
                   "      ---5      ",
                   "      ---6      ",
                   "      ---7      ",
                   "      ---8      ",
                   "      ---9      ",
                   "      ---10     ",
                   "      ---11     ",
                   "      ---12     ",
                   "      ---13     ",
                   "      ---14     ",
                   "      ---15     ",
                   "      ---16     ",
                   "   End of line  ",
                  };



void setup()
{
  for (int i = 0; i < numPins; i++) {            // setting the 5 pins to 74154 + 74137 or second 74154
    pinMode(pins[i], OUTPUT);
    digitalWrite (pins[i], LOW);
  }
  pinMode(buttonup, INPUT);                      //setting both buttons
  pinMode(buttondn, INPUT);
  digitalWrite(buttonup, HIGH);                  // internal pullup
  digitalWrite(buttondn, HIGH);
  attachInterrupt(0, countdn, LOW);              // attaching interrupt to 2 separate loops
  attachInterrupt(1, countup, LOW);
  pinMode(LCDLED, OUTPUT);                       // for LED on LCD panel
  digitalWrite(LCDLED, HIGH);                    // turn on LED backlight
  lcd.begin(8, 2);                              //  using 16x1 display that is mapped like 8x2
  lcd.setCursor(0, 0);                           // reset LCD cursor
  lcd.print(gameSys[0]);                         // prints starting display

}

void loop()
{
  String binNumber = String(presses, BIN);
  if ((0 <= presses) && (presses <= 31)) {      // set the 5 pins output according to current button setting
    digitalWrite(pins[0], (presses &        B1));// using bitmask to select the correct bit to write to pin
    digitalWrite(pins[1], (presses &       B10));
    digitalWrite(pins[2], (presses &      B100));
    digitalWrite(pins[3], (presses &     B1000));
    digitalWrite(pins[4], (presses &    B10000));

  } else {
    if (presses > 31) presses = 0;
    if (presses < 0) presses = 31;               
  }

  if (millis() - dtime > idletime) {
    digitalWrite(LCDLED, LOW);               // turn off backlight, switch hasn't been used for a while
    lcd.setCursor(0, 0);                         // reset LCD cursor
    lcd.print("                ");               // erase display

  }
}

void countup() {  // up button
  if (millis() - dtime > debounce) presses++;   // increment presses
  digitalWrite(LCDLED, HIGH);                    // turn on LCD backlight, a button was pressed
  lcd.setCursor(0, 0);                           // reset LCD cursor
  lcd.print(gameSys[presses]);                   // prints current display according to variable in gamesys[]
  dtime = millis();                              // reset last pressed
}

void countdn() {  // down button
  if (millis() - dtime > debounce) presses--;   // decrement presses
  digitalWrite(LCDLED, HIGH);                    // turn on LCD backlight, a button was pressed
  lcd.setCursor(0, 0);                         // reset LCD cursor
  lcd.print(gameSys[presses]);                 // prints current display according to variable in gamesys[]
  dtime = millis();                              // reset last pressed
}


lcd.print on 0,0 works for the first 8 characters, how would I put the second 8 characters from inside gameSys[presses] so it'd appear on 0,1?  I tried -7,1 but that doesn't seem to work, 0,32 does work but it just seems a little messy if there's a way to take only the right 8 characters and stick them in 0,1

david_prentice

Untested.   I understand that the new HD44780 library can do automagic line wrap.
So if you try it on your 8x2 it should wrap onto the second line i.e. the second half of the 16x1

On the other hand,   it might be too clever and start a new line to avoid splitting a word.

Most regular LCD libraries do not wrap.

David.

floresta

You might just try to find a 'real' 16x1 display.  It will have two ICs (or epoxy blobs) instead of one. 

Also, with that type of display you may be able to invoke a larger (5 x 10) font although I'm not sure if any of the libraries support that feature.

Don

bperrybap

Yeah, that type of display is pretty difficult to use with "standard" arduino LiquidCrystal type libraries.
I would go so far to say it actually sucks.
However, the hd44780 library can do automatic line wrapping to make it work the way you want it work.

There is no sort of word wrapping in hd44780; it is very simple.
When enabled, it wraps to the next line when characters get to the end of the current line
and back to the first line if on the bottom line.
There is no scrolling capability.

The hd44780 library should be smart enough to handle that type of display.
What you will want to do is initialize the display as an 8x2 display.
Then tell the library to do automatic line wrapping by calling lcd.lineWrap()

After that, you can treat the display as if was a 16x1, including using setCursor(col, row)
when col > 7
i.e. you can set the cursor col to any position between 0 and 15 on row 0
and it will work as you want it to work. Even though the display is really 8x2, it will work as a 16x1

The hd44780 library can be installed directly from the GUI library manager.

There is even a LineWrap demo sketch example to demonstrate this.
Read the comments in it, but basically you just need to set the geometry to 8x2.

If you are currently using the LiquidCrystal library you will want to use the hd44780_pinIO class in the hd44780 library. See the examples for what header files you need to include and the constructor parameters.
Start by looking at the HelloWorld sketch.

See the hd44780 github page for more information: https://github.com/duinoWitchery/hd44780
And also read the wiki: https://github.com/duinoWitchery/hd44780/wiki
as it explains where the examples are for each i/o class.

Use the IDE GUI library manager to do the install, do not install it from a zip file.


--- bill

wilykat

Bill, that is a big help! Automatic line wrapping works great on cheap 16x1 displays.  It seems to work fine with hd44780-compatible VFD like Noritake CU series.


bperrybap

So I assume you got it working on your 16x1 display?

I threw in some special support to make sure the library could handle those types of displays after seeing people struggling with them.
IMO, having to handle the line breaks in the application is simply not workable.

The 1.0.0 release is getting closer. Likely in a few weeks.
If you see any issues please create github issues so they can get fixed.

--- bill

wilykat

#8
Dec 17, 2017, 12:11 pm Last Edit: Dec 17, 2017, 12:14 pm by wilykat
So I assume you got it working on your 16x1 display?

It works after I swapped the code a bit to remove the original LCD libraries and changed the pinout from example sketch to match my wiring. My cheap 1x16 display now behaves like a true 1x16 display without messy manual wrapping.

Correction: lcd.clear() seems to be stuck, display does not come back.  The LED on D13 does go off after 25 seconds of idle, it is to be wired to control backlight. When I press the button, LED comes back but display does not.

Code: [Select]
// unused Arduino pin: 4-6,16-18 (A2-A4)  (AVR 10-12, 25-27)
#include <hd44780.h>
#include <hd44780ioClass/hd44780_pinIO.h> // Arduino pin i/o class header

int LCDLED = 13;                                 // backlight LED pin AVR 18
int buttonup = 2;                                // pin to connect the UP button  AVR 4
int buttondn = 3;                             // pin to connect the DOWN button AVR 5
int presses = 0;                              // variable to store number of presses
long dtime = 0;                              // used for 'since last press'
long debounce = 200;                            // how many ms to "debounce"
long idletime = 25000;                           // about 15 seconds for display idle before turning off LED
const byte numPins = 5;                          // just 5 pins
int state;                                // used for HIGH or LOW
byte pins[] = {19, 0, 1, 14, 15};                // pins to connect to 74154 AVR 28, 2, 3, 6, 11
const int rs = 7, en = 8, d4 = 9, d5 = 10, d6 = 11, d7 = 12; // AVR 19, 23, 24, 25, 26, 27
hd44780_pinIO lcd(rs, en, d4, d5, d6, d7);
const int LCD_COLS = 8;
const int LCD_ROWS = 2;        // using cheap 1x16 display that behaves like 2x8 display

char* gameSys[] = {"   Atari 5200   ",         
                   "   Atari 7800   ",
                   " Intellivision  ",
                   "  Colecovision  ",
                   "    Nintendo    ",
                   " Super Nintendo ",
                   "   Nintendo 64  ",
                   "    Gamecube    ",
                   " Genesis CD 32X ",
                   "  Sega Saturn   ",
                   "   Dreamcast    ",
                   "   Turbo Duo    ",
                   "  Playstation   ",
                   " Platstation 2  ",
                   "   Sony PSP     ",           // portable system via AV cable + Bluetooth PS3 controller
                   "      ---1      ",
                   "      ---2      ",
                   "      ---3      ",
                   "      ---4      ",
                   "      ---5      ",
                   "      ---6      ",
                   "      ---7      ",
                   "      ---8      ",
                   "      ---9      ",
                   "      ---10     ",
                   "      ---11     ",
                   "      ---12     ",
                   "      ---13     ",
                   "      ---14     ",
                   "      ---15     ",
                   "      ---16     ",
                   "   End of line  ",
                  };

void setup()
{
  for (int i = 0; i < numPins; i++) {            // setting the 5 pins
    pinMode(pins[i], OUTPUT);
    digitalWrite (pins[i], LOW);
  }
  pinMode(buttonup, INPUT);                      //setting both buttons
  pinMode(buttondn, INPUT);
  digitalWrite(buttonup, HIGH);                  // internal pullup
  digitalWrite(buttondn, HIGH);
  attachInterrupt(0, countdn, LOW);              // attaching interrupt to 2 separate loops
  attachInterrupt(1, countup, LOW);
  pinMode(LCDLED, OUTPUT);                       // for LED on LCD panel
  digitalWrite(LCDLED, HIGH);                    // turn on LED backlight
  int status;
  status = lcd.begin(LCD_COLS, LCD_ROWS);
  if (status)                                    // non zero status means it was unsuccesful
  {
    status = -status;                            // convert negative status value to positive number
    hd44780::fatalError(status);                 // does not return
  }
  lcd.lineWrap();
  lcd.setCursor(0, 0);                           // reset LCD cursor
  lcd.print(gameSys[presses]);                   // prints starting display
}

void loop()
{
  String binNumber = String(presses, BIN);
  if ((0 <= presses) && (presses <= 31)) {      // set the 5 pins output according to current button setting
    digitalWrite(pins[0], (presses &        B1));// using bitmask to select the correct bit to write to pin
    digitalWrite(pins[1], (presses &       B10));
    digitalWrite(pins[2], (presses &      B100));
    digitalWrite(pins[3], (presses &     B1000));
    digitalWrite(pins[4], (presses &    B10000));
  }
  if (millis() - dtime > idletime) {
    digitalWrite(LCDLED, LOW);                   // turn off backlight (on LCD only), switch hasn't been used for a while
    lcd.clear();                                 // clear display
  }
}

void countup() {  // up button
  if (millis() - dtime > debounce) presses++;   // increment presses
  if (presses > 31) presses = 0;
  digitalWrite(LCDLED, HIGH);                    // turn on LCD backlight, a button was pressed
  lcd.setCursor(0, 0);                         // reset LCD cursor
  lcd.print(gameSys[presses]);                 // prints current display according to variable in gamesys[]
  dtime = millis();                              // reset last pressed
}

void countdn() {  // down button
  if (millis() - dtime > debounce) presses--;   // decrement presses
  if (presses < 0) presses = 31;               // loop around if you reach the end, change both 15 to 23 or 31 if using mezzanine
  digitalWrite(LCDLED, HIGH);                    // turn on LCD backlight, a button was pressed
  lcd.setCursor(0, 0);                         // reset LCD cursor
  lcd.print(gameSys[presses]);                 // prints current display according to variable in gamesys[]
  dtime = millis();                              // reset last pressed
}

bperrybap

hd44780 also supports backlight control.
See the HelloWorld sketch for the constructor. It has two addtional parameters, the pin # and the active level.
Once you do that, you can use backlight()/noBacklight() to turn on/off the backlight.
and setBacklight(dimlevel) if you are using a PWM pin.

From you code it appears that the active level is LOW.
i.e.
Code: [Select]
hd44780_pinIO lcd(rs, en, d4, d5, d6, d7, LCDLED, LOW );


I'm not sure what you mean by
Quote
Correction: lcd.clear() seems to be stuck, display does not come back.  The LED on D13 does go off after 25 seconds of idle, it is to be wired to control backlight. When I press the button, LED comes back but display does not.
lcd.clear() replaces every character on the display with spaces.
If you want the display to only turn off its pixels but not clear the actual characters on the display you can use
noDisplay()/display() to turn off/on the pixels.
Or you could use off()/on() which turns on/off the pixels and the backlight (assuming you configured it in the constructor)
When you turn the pixels back on using display() what was on the display will come back.
And when you use on() the characters/pixels will come back and the backlight will turn on..

--- bill

wilykat

What I mean is the display does not come back after I clear it.  When I start it, it works as expected, display changes when I press the button. And the display and LED goes out after 25 seconds of inactivity. But when I press the button, only LED comes back on. The display remains blank, it's like somehow Arduino forgot how to print to screen.  I don't know if I messed up something in the code during clear screen or if it's something else.

wilykat

I tried display and noDisplay, it's working. I couldn't get around clear for some reason.

Go Up