Microcontroller reverse engineer
Microcontroller reverse engineer
Everything they make, We can break! 
Disassembler Software   
World first mcu hack company
In business since 1998
Reversed tens of thousands of chips
Copied thousands of pcbs
Foreseen all pertential problems
Integrity with payments
crack ic
Microcontroller Beginners' Guide

Chapter 6


Part 16 - Displaying Numbers on the LCD Display

So, we know how to put characters and even strings of information to the LCD. The most useful thing to display on the LCD would be a number. Now, I'm sure you are thinking, well, we could just pass a number in quotes, like this: "632" using the Send_A_String command (that we created in the last tutorial ! Well, sure, but what if it is a number from a sensor stored in a variable, or something like that! We actually do want the number in those quotes, but how we get it there is where the magic comes in... and it is REALLY simple.


If we want the numbers to be displayed at the same locations every time (and not just fill the entire screen with a list of numbers), we will need to move the cursor to the desired locations every time we want to send the number to the LCD. This can also be used to locate strings and characters.


The magic of moving the cursor to any position on the LCD display is in the 0x80 number. That number represents the first location on the display, at the top left corner. If you've been paying attention to the binay tutorial, you would know that 0x80 represents 0b10000000 in binary. The "1" is in the 8th place, leaving a full 7 digits left for something wonderful. 7 binary digits can hold 128 numbers (0-127).


As you already know, LCD screens are divided up into many columns and rows. For the LCD in the tutorial, there are 4 lines (rows) and 20 columns, hence the 20x4 that is usually shown in the description. Add them all up and you have 80 total positions on the LCD. Hmm... 80 is less than 128. This tells us that there may be LCDs out there that have more lines and columns, becuase there are that many possibilities using this command.


If you sent a command using Send_A_Command and inserted 0x80 to get processed by the LCD, the cursor position would appear at the top left. If you inserted 0x8A, then the cursor would be positioned 10 spaces right of the top left corner. It would actually be in the middle, since the LCD is 20 columns wide. But there is a catch! One would think that if this number kept increasing, the cursor would wrap to the next line, but it doesn't. The cursor wraps to the third line instead. This is due to how it uses the 128 reserved spaces. Because of the various LCD displays out there with different line and column counts, the first line will start from "0" and fill lines 1 and three up to number 63, which is 1 minum half of 128. Now it is starting to come together, isn't it. The 2nd and fourth line start from 64 and go on towards the end. So half of the 128 is reserved for the first and third line, and the other half is reserved for the second and fourth line. That way, all LCD will start from 0 on the first line, and start from 64 on the second line, even on 2 line LCDs.


This makes great sense, because if you have an LCD with only two lines that were 64 columns long (using all of the 128 reserved positions), then the LCD would still be compatible with an LCD with 2 lines but with only 20 or so columns. You could expect to see the same information on the LCD, at least as far as the selected LCD.


However, trying to put the cursor in a desired location using a number within 0 to 64 and 64 to 128 not really knowing which line you may be affecting is as easy as it could be. We can create a new routine that allows you to simply state the x and y coordinate locations would be much easier. If you wanted to display something on the 4th line and 6 spaces from the start of the line could be written link GotoLocation(6, 4); That's easier than stating the location in this form: Send_A_Command(90); 90 (in decimal, not hex) just happens to be that position on a 20x4 LCD display. 90 is derived this way: 64 is the 2nd line. The 2nd line wraps to the 4th line by adding 20 to 64 (20+64 = 84). knowing that you are on the 4th line, just add 6 and you have the numer 90. But forget all that, because we will implement the easy way.


Creating a routine that you can just enter the X and Y component is pretty easy. First, you will need to create a variable that stores all of the initial column numbers. In the case of the 20x4 LCD, the numbers are 0 for the first line, 64 for the second line, 20 for the third line and 84 for the forth line. The variable declaration might look like this:

char firstColumnPositionsForMrLCD[4] = {0, 64, 20, 84};

I am using the "char" data type because the numbers are not that big. The "char" data type can range from 0 to 128. The variable name "firstColumnPositionsForMrLCD" is LONG. This is actually intentional. First, for best programming practice and readability, and second, so later on, the possibility for this name to be used for another use would be very unlikely. Remember, we will have this varialble in another file as a library and we wont see it (while working in our main .c file), but it will be present. The numbers between the squiggly brackets are the initial positions for each line. This way, all we need to do is put the "Y" component in this array and it will tell us the initial position for that line. Then we add the "X" component to that number and we will have the correct position on the LCD.


The array could also be a bit more systematic and could look like this:

#define numberOfColumns 20;
char firstColumnPositionsForMrLCD[4] = {0, 64, numberOfColumns , 64 + numberOfColumns };

This way, all you would need to do is specify the LCD's number of columns and you would not need to go to that obfuscatious data sheet (or should I say data BOOK). So, armed with these glorious instructions and new knowledge that you thought you would never know, how might the actual GotoLocation routine look like? Well, here you go:

void GotoMrLCDsLocation(uint8_t x, uint8_t y)
Send_A_Command(0x80 + firstColumnPositionsForMrLCD[y-1] + (x-1));

Notice the 0x80... That still needs to reside in the Send_A_Command since it is the command that represents the first position. then the array calls up the correct number and then the "X" is added. You may have also noticed the y-1 and x-1. This is added because the array is indexed from 0 and the screen positions are also indexed from 0 and not 1. The small subrraction is just to be able to call line #1 "1" instead of "0" and line #2 "2" instead of "1", and so on. For the "X", i like calling the first column "1" not "0". It's like being in Paris, all of the first floors are considered the ground, or "0" floor and the floor just above is considered the first floor. Not that it is wrong, but I'm just not accustomed to that. If you like your first column and first line to be "0", simple remove the subtraction and you are set.


Now, for the desert. Making a numeric variable appear on the LCD screen. The secret to doing this is to have a function that converts a number (numeric variable) into a string. We already know ow to put a string to the LCD, now