Answered: Does anyone know how to address character map of a 16x2 LCD?

Hi all!

There are lot more characters on the character map that can be accessed with lcd.print(); - like Greek scientific characters. Of course it is possible to just create them form scratch... But that takes space.
There is another function lcd.write(); that sort of does the trick. Rows and lines in character map
are numbered in binaries. If to insert these binaries into the lcd.write(); LCD does indeed draws additional characters...
For example: lcd.write (00000100); will yield character @
Thats first row (0000), column (0100).

But here the weird stuff begins... If to type for example lcd.write (0000100); that is with one less zero the LCD will still draw character @
Furthermore, next character in line is P. Thats row (0000), than column (0101).
But lcd.write (00000101); will return character A! Capital A is located under @ and the code for it is: row (0001), column (0100).

Something really strange is going on here and unfortunately I dont know enough about the screens to get through this obstacle.
I've tried to read up on the theory on how alphanumeric LCDs work but cant find a detailed enough tutorial that I can read through and understand without a degree in EE :stuck_out_tongue:
_

As far as I know you just use the ASCII code for the characters and they will work. Internally they may well be arranged as rows and columns, but that is too detailed for me to want to worry about when I am just trying to print a character.

Exactly my point! These screens can display non-ASCII characters, like tau or pi. Only problem its a b...h to get them to do it :smiley:

Hmm

Maybe you should write a little sketch that counts up from 0 to 255.
In the first line you would do a lcd.write, and on the second line a lcd.print of the value you just printed.
Delay a second or so, so you can make a note of the chartacter you're interested in, and then next value.
Or to keep full track, wire up an up and a down button and scroll the characters.
If you happen to have an lcd keypad shield, this should be quite easy.

Can you use lcd.write() with a byte from 0 to 255 ?

The characters above 127 are special characters. It depends on what the manufacturer put there. The very cheap 1602 lcd display from Ebay contain often chinese or japanse characters (my lcd does).

Great idea guys! Just tested it, work like a charm!

for (int i=0; i <= 255; i++){
      lcd.setCursor(0, 0);
      lcd.write(i);

      lcd.setCursor(0, 1);
      lcd.print(i);

      delay(200);
   }

This code went though page one that in the datasheet called "ROM Code: 0A". It seems to scroll down columns from top to bottom starting with the column on the left and then through columns left to right. There are all the usual ASCII characters followed by two empty columns and there is also basic set of japanise kana.

Thats definitely progress! There are also "ROM Code: 0B" and "ROM Code: 0E" with Cyrillic, special German, French and Greek characters and all kind of weird and wonderful stuff as well :slight_smile:

My reading of documentation has been that the LCD displays come with one rom set. Most of the ones I have seen have been the Asian extended characters. I have not found any way to 'switch' the rom code to one of the others sets - they are different part numbers from the manufacturer.

ROM code is fixed and supposed to be printed on the chip, but these blob chips have nothing printed.

I played around and hacked a working code into a character lookup thingy:

/*
Sloppy hack of the LcdKeyShield code i found somewhere
Meant to lookup the characters and their codes using the LcdKeyShield (this one is DFRobot compatible)

  The circuit:
 * LCD RS pin to digital pin 8
 * LCD Enable pin to digital pin 9
 * LCD D4 pin to digital pin 4
 * LCD D5 pin to digital pin 5
 * LCD D6 pin to digital pin 6
 * LCD D7 pin to digital pin 7
 * LCD BL pin to digital pin 10
 * KEY pin to analog pin 0        (14)  THIS IS THE BUTTON PIN
 */

#include <LiquidCrystal.h>

//Old LiquidCrystal lcd(8, 13, 9, 4, 5, 6, 7);
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

char msgs[5][16] = {"Right Key OK ",
                    "Up Key OK    ",               
                    "Down Key OK  ",
                    "Left Key OK  ",
                    "Select Key OK" };

//int adc_key_val[5] ={1, 150, 500, 350, 800 }; // 1st change
//int adc_key_val[5] ={800, 500, 350, 150, 50 }; // Original inverted order
int adc_key_val[5] ={50, 200, 400, 600, 800 }; //Original, works after actually reading the analog0

//int adc_key_val[5] ={ 0, 133, 308, 482, 723 };// Had  to change the order of the keys to have them show up correct.
int NUM_KEYS = 5;
int adc_key_in;
int key=-1;
int oldkey=-1;
int i=1;
void setup()
{
    Serial.begin(9600);
  lcd.clear(); 
  lcd.begin(16, 2);
  lcd.setCursor(0,0); 
  // lcd.print("ADC key testing"); 
  lcd.print("< Char lookup >"); 
}

void loop()
{ //1

 key = (analogRead (0));
 //Serial.println(analogRead(0));
  if (key != oldkey)   // if keypress is detected "!=" means not equal!!
   {//2
    delay(50);  // wait for debounce time
    adc_key_in = analogRead(0);    // read the value from the sensor 
    key = get_key(adc_key_in);    // convert into key press
    if (key != oldkey)    
    {//3   
      lcd.setCursor(0, 1);
      oldkey = key;
      if (key >=0){//4
           //lcd.print(msgs[key]);
      Serial.println(key); 
      Serial.println(analogRead(0));
      
      if (key == 308)
 {
  Serial.println("            down  ");
 }
      
if ((key)==3) i--;
if ((key)==0) i++;
if ((i)==256) i=1; 
if ((i)==0) i=255;
lcd.setCursor(1,1);  
lcd.print(i);
lcd.print("  ");
lcd.setCursor(8,1);  
lcd.write(i);
      }//4
    }//3

   }//2
  /*
 if (key = 800)
 {
   delay(2000);
   lcd.clear();
  }
*/
 delay(100);
 
}//1

// Convert ADC value to key number
int get_key(unsigned int input)
{
    int k;
   
    for (k = 0; k < NUM_KEYS; k++)
    {
      //if (input == adc_key_val[k]) //works
      if (input < adc_key_val[k]) // should be more reliable as it doesn't looks for a range instead of a fixed value but it isn't
 {
            return k;
        }
   }
   
    if (k >= NUM_KEYS)k = -1;  // No valid key pressed
    return k;
}

As stated, it's a bit sloppy but it works.
Use the left and right keys to go back or forth.
How about characters # 247, 249, 244 and 228 ?

MAS3:
How about characters # 247, 249, 244 and 228 ?

Yep, there are omega, sigma, tau and pi... But man, there is a whole universe stashed away on another rom code! Shame there is no way to get there..

marco_c:
My reading of documentation has been that the LCD displays come with one rom set.

Lets try a datasheet for a standard HD44780, like this one at Sparkfun:

pages 17 and 18 give two different rom codes "ROM Code: A00" and "ROM Code: A02"...

But there indeed no instructions on how to switch... Screen that I'm playing with is form RS Components with a different controller that has three rom codes, the description is even more sketchy. Whats interesting though, first sets are the identical on both screens. Both datasheets first describe interaction with the EEPROM, then the bloody ROM tables :), then the "Relationship between CGRAM Addresses, Character Codes (DDRAM) and Character Patterns (CGRAM Data)".
In commands for character modules there is function "Set CG RAM Address", presumably to read or write to/from it. But this is about all there is to go by.

Hence have to agree, seems like a lost cause. Its 2.30 am, not really thinking straight right now. Tomorrow will try to get through the CG RAM, only hope there might be a way to mess with addressing. There are some kind of control bits in front of character codes, thats the objective for tomorrow - if will be able to to get some sleep that is :grin:

The character rom on a hd44780 type lcd is what it is. You cannot change it.
Different LCD modules have different glyphs for the character codes above 0x7f.
The only thing you can do is define you own characters, but....
You only get eight of those.

If you really want to have custom character glyphs you will need
to switch over to a glcd.
Most glcd libraries render the charcters from fonts data stored in the library files
so you can have any font or define any glyph you want for any character code
including different sizes.

--- bill

pages 17 and 18 give two different rom codes "ROM Code: A00" and "ROM Code: A02"...

But there indeed no instructions on how to switch...

You 'switch' by carefully desoldering your HD44780A00 from the pc board and replacing it with an HD44780A02.

Don

Whats interesting though, first sets are the identical on both screens.

That is because they are the only characters defined by the original ASCII code. The ASCII code is a 7-bit code which therefore defines only 127 characters. Actually only about 96 characters because the other codes are 'control' codes that represent other actions rather than displayable characters. Any 8-bit 'ASCII' code with the high bit set is not part of the original ASCII character set. Since the 'A' in ASCII stands for 'American' you are not likely to find any Asian, Cyrillic, Hebrew, Arabic, etc characters in an ASCII chart.

For a more complete explanation you can follow the expanded ASCII chart link at http://web.alfredstate.edu/weimandn. Don't forget to scroll down to the interesting stuff.

Don

Does anyone know how to address character map of a 16x2 LCD?

I forgot to answer this question.

(1) Find the character that you want to display on the character map. I will use the 'ohm' symbol (fifth down in the right column).
(2) Use the binary number at the top of the column ( 1 1 1 1 ) for the high bits.
(3) Use the binary number at the left of the row ( 0 1 0 0 ) for the low bits.
(4) The resulting 'ASCII' code is 11110100 in binary or F4 in hex. It is also 244 in decimal, which is an awful way to define the character (go to the link above to find out why).
(5) Use this number in your favorite function to display the ohm symbol.

Don

Thanks a lot guys!