Experimenting with ST7920 128×64 graphical LCD on a PIC
This is a monochrome 128×64 graphical LCD using the ST7920 controller that I purchased from eBay:
The module is using a 20-pin standard 2.54mm connector, making it easy for prototype development on a breadboard:
Communication modes
According to the datasheet, the following communication modes are supported:
- 8-bit mode. Data or instruction bytes are transferred via pin DB7-DB0.
- 4-bit mode. Data or instruction bytes are separated into two parts. Higher 4 bits will be transferred through DB7-DB4, followed by the lower 4 bits. The DB3-DB0 pins will not be used and should be connected to ground.
- Serial mode. This is done by pulling down the PSB pin. When enabled, communication will only require 4 pins in total. Only writing data is supported in serial mode
Unfortunately, the board that I purchased has the PSB pin permanently connected to VCC. Hence, only parallel communication is possible. To cut down on the number of output pins required, I have selected 4-bit mode, instead of 8-bit.
The LCD supports both graphics and text modes:
- Maximum 16 characters x 4 lines in text mode
- 128×64 resolution in graphics mode.
Initialization codes
The following code performs LCD initialization and configures 4-bit communication in text mode:
void LCD_Init(void) { LCD_REST=1; LCD_REST=0; delay_ms(5); LCD_REST=1; delay_ms(50); LCD_WriteCommand(0b00100000); delay_ms(5); LCD_WriteCommand(0b00100000); delay_ms(5); LCD_WriteCommand(0b00001100); delay_ms(5); LCD_WriteCommand(0x01); delay_ms(5); LCD_WriteCommand(0x06); delay_ms(5); LCD_WriteCommand(0b00000010); delay_ms(5); }
After the LCD has been initialized, the following function will display a string on the LCD:
void LCD_TextDisplayString(unsigned char line, char* string) { unsigned char addr,i; if(line==1) addr=0x80; //The first line address else if(line==2) addr=0x90; //The second line address else if(line==3) addr=0x88; //The third line address else if(line==4) addr=0x98; //The fourth line address LCD_WriteCommand(addr); for(i=0;i<16;i++) LCD_WriteData(*string++); }
This is how it will look when displaying 4 lines of text:
Displaying graphics
Despite the large screen resolution, the default text mode only allows me to display up to 64 characters on the screen due to the thick font. My next attempt is to use graphics mode, so that I can use my custom font and display more characters. The following code shows how to enable and disable the graphics mode on this LCD:
void LCD_EnableGraphics(void) { LCD_WriteCommand(0x20); delay_ms(1); LCD_WriteCommand(0x24); delay_ms(1); LCD_WriteCommand(0x26); delay_ms(1); } void LCD_DisableGraphics(void) { LCD_WriteCommand(0x20); delay_ms(1); }
Similar to the Nokia 5110 LCD, every 8 pixels on this LCD will consume a single byte in the display memory space. With that knowledge I was quickly able to use my custom 5×7 bitmap font and display more characters. The following picture is the display showing information from various sensors that I have interfaced with the PIC24FJ64GA002. It can show up to 16×8=128 characters:
Various graphics that I manage to display on this LCD:
The full C30 source code for this LCD can be downloaded here. If you are interested, the syntax highlighting of the source code in this article is done using this tool.
with what software did u use to code this?
You can use any PIC C compiler. I am using Microchip MPLAB with its C30 compiler.
Hi Friend, what applicattion do you use to make the fonts? Thank you!
Hi Henry, try this
http://www.mikroe.com/glcd-font-creator/ – bitmap font generator for LCD
http://en.radzio.dxp.pl/bitmap_converter/ – LCD assistant, to convert bitmap into byte array
hi
can i create this circuit diagram using pic microcontroller? our university dont give chance to use Arduino and pic 32 boards so i am in big trouble with this disply
Of course, if you read the article at all it says I am using a PIC24FJ64GA002. The code of course can be ported to any other micro controller with no issues.
i am confused with
#define LCD_RS LATAbits.LATA3
#define LCD_EN LATBbits.LATB11
#define LCD_REST LATAbits.LATA4
#define LCD_DB4 LATBbits.LATB12
#define LCD_DB5 LATBbits.LATB13
#define LCD_DB6 LATBbits.LATB14
#define LCD_DB7 LATBbits.LATB10
i am using 16F877A pic so how should i initialised pins in there..please give me example code for that..
The PIC16F877A does not have the latch registers (e.g. LATB, LATA, etc) which is for newer PICs such as the PIC24. Just replace the LAT registers with the PORT registers. If you're using Hi-Tech C compiler, replace LATAbits.LATA3 and other similar declarations with, for example, RA3 and it should compile.
do we need to enable graphics mode to display character string on this or any GLCD..?
please help..!
urgent..!!
Please tell me how to display a variable on your cord.,.
Hello MD,
Thanks for the code. Some years back I've written this for a PIC32 microcontroller in a website (you have seen this already – Cytron tutorial) – glad that you added new features to it!
Hi NYH,
Glad you find the code for this LCD useful I also have codes for other LCD/OLED modules which I purchased from eBay and plan to make it available on my blog shortly for the benefits of the electronics hobbyist community
how can i use 5×7 font, ai only show 4 like with big font ="=
Hi,
You can download the custom 5×7 font (font.zip) and the LCD sample code (12864_lcd.zip) from my article. After that you can use the LCD_GraphicsDisplayString(unsigned char line, char* str) function to display the text on string as graphics using the 5×7 font.
This way you can show up to 128 characters on the screen, and not just 64 big characters.
Let me know if this works.
Hello MD,
I am trying to use the custom 5×7 font you provided. When I use the LCD_GraphicsDisplayString(unsigned char line, char* str) function it displays the 5×7 font but uses a larger space to do it, resulting in the same number of characters (16) as the larger font in each row. What is wrong?
Thank you
Hi,
The LCD_GraphicsDisplayString in the code I provided will display 16 characters per row and 8 rows on the screen, so it can display a total of 16×8=128 characters.
Although the number of characters per row is the same (16), the height of each row is shorter compared with the default font so it can display twice as many characters. The default text mode can only display 4 rows of 16 characters each, totaling to 64 characters.
This is because each character is displayed in a 8×8 box. I have tried to use a smaller box in order to display more characters, but the results don't look nice due to the lack of spacing between characters. So for now, 16 characters on 8 rows should be sufficient for most use cases.
As you can see on the screenshot, the LCD can display much more text using the custom 5×7 font.
Let me know if you have any questions.
Thanks. I mod it to use with CCS and it work fine.
Good night you have examples with this code em ccs
Could you send me your code in CCS? Please, I need it urgent for my thesis project. In my country I one can find displays with this driver.
My email is glori.mag3@hotmail.com.
thankyou for this code its helped me alot. however the .h file has the function LCD_GraphicsDisplayChar() but itisnt in the .c file
Hi,
Thanks for spotting that. You are right that function LCD_GraphicsDisplayChar is present in the header but not in the .c file. I probably forgot about it when I write the code. However you can still adapt from function LCD_GraphicsDisplayString (present in the .c file) to output a character at a specific position. Just some minor modifications. Let me know if you have any issues.
Hi
I’m trying to display characters on the 12864zw (st7920) using a pic 16f877a and xc8 in 8 bit mode.
could you please post the code for the LCD_WriteCommand and LCD_WriteData please.
The C code for these 2 functions (and other functions) are already provided in the download link at the end of this article.
Hello,
can send me example for CCS for use 128×64 with big font?
very thanks
info@umbertomori.it
many compliments for your code to write 4 lines with large characters on 128×64.
I tried using your code but I found it difficult.
Can you kindly send me the code to try it with the CCS compiler?
I would be very grateful.
Thank you
many compliments for your code to write 4 lines with large characters on 128×64.
I tried using your code but I found it difficult.
Can you kindly send me the code to try it with the CCS compiler?
I would be very grateful.
Thank you
Do you have maybe a footprint of this LCD?
Hi, I’ve been experimenting with your code to use GLCD with PIC18F26K42. I’ve got it working but wanted to adapt your code a bit to make it work better for the project I am working on.
I wanted to add the ability to display graphic text at specific columns within rows without overwriting the rest of the row. I have added the new “col” variable to my function and it works except the problem I am running into is with the way the GLCD blocks the text into groups of two characters.
Do you think it is possible to make text start on the second half of a block, for example, without overwriting the first half?
Hi Didier
You are right about the limitations of text mode on this LCD. It might not be possible to freely write characters at arbitrary locations on the screen without overwriting existing characters, since characters must be written in pairs. To achieve your objectives, I suggest using graphics mode to draw text. You can use function LCD_GraphicsDisplayString which is present in the sample source code. I have also updated the download link with the 5×7 font (file font.h) so that this function will compile – the previous download was missing this file. Let me know if this helps.
I did get the 5×7 font to work in graphics mode, and that is actually the mode I’d prefer to use. From what I can tell, though, in graphics mode it is also grouping the text in groups of 2 characters.
Is this something that can be easily changed in the code?
Hi,
In graphics mode every 8 pixels on the screen will form a byte on the LCD memory map to be written via LCD_WriteData after setting the DRAM address on the LCD using LCD_WriteCommand. Although you can display anything on the LCD in graphic mode, the datasheet explicitly states “Each RAM address (CGRAM,DDRAM,IRAM…..) must write 2 consecutive bytes for 16 bit data”. Take note that the font we use is 5×7, which will become 6 cols x 8 rows after leaving a space on the right and at the bottom of each character, which is why the code has to display 2 characters (16 rows = 16-bit = 2-byte) at once. To update only a single character, you will have to write the new character first and then rewrite the old character on the right. This means your code will somehow have to keep track of the text that is currently being displayed on the screen. Definitely doable, but might be slightly complicated.
In my projects, I simple redraw the entire LCD line every time the screen needs to be updated.
I suppose rewriting the entire line might be the simplest approach.
Does your code allow to display a value from a variable, though?
Hi,
To display a value from a variable, you will need to use sprintf() to convert the value (integer, double, etc.) into a string, and then fetch that string into LCD_GraphicsDisplayString(). See this for an overview of sprintf function: https://www.tutorialspoint.com/c_standard_library/c_function_sprintf.htm
Thank you so much for all of your replies. This is really helpful!!
Hi.
Thanks for your code ans examples. I try to print somethings on the screen but i juste have two big squares on each side of it. I don’t know if I made an error in the code or if the screen is dead. It make like if there was’nt data (it make the same when the uC is out of the PCB). I’m using PIC18F4580.
Thanks.
Hi,
Without knowing your code and a photo of what your LCD looks like it will be hard to tell. Try to check the connection and make sure that you are at least able to control the uC pins (e.g. toggle between 0 and 1) you plan to use for the LCD from your code first before attempting any further troubleshooting. With the power supply and backlight pins connected, the LCD backlight should lit up and a slightly darkened area can be seen in the center of the LCD (where the displayable area is supposed to be).
However, if the display still shows two big squares even when the uC is not connected, there might be a hardware issue. From experience, the connection between the front of the LCD and the controller board (at the back) might become loose during shipping and cause intermittent issues. If you have a spare module you can test your code on that and see if there is any difference.
Hope this helps.
Hi again. I’ll be able to send image later. I have the two square on top and down and a line with no pixel between them. My code is very simple :
(before the main i made the #include needed)
void main()
{
LCD_Init();
LCD_EnabeGraphics();
LCD_GraphicsDisplayString(1,”1234″)
}
I just want to display somthing on the screen to have the technic.
Have you updated the declarations in the 12864_lcd.h to reflect the correct pin assignments for your uC and set the correct TRIS bits for these pins? Verify that these pins are working as intended by toggling each and every of them without the LCD connected first and observe the output on an oscilloscope or a perhaps a multimeter. The delays might also be too fast or too slow – may sure the value of the FOSC constant is correct.
The ST7920 controller supports 8-bit, 4-bit and serial modes. The provided code works in 4-bit mode. Check the PSB pin of the board and make sure it’s set up correctly for 4-bit mode (connected to VCC) as mentioned in the article.
For a start, you might want to try text mode first (function LCD_TextDisplayString()) before experimenting with graphics mode.
main.c file is missing can u send me the 4 line big font pic project to mrpraveenkumarr21@gmail.com
Hello Sir,
I am using same 12864 LCD and i am using your code.
also i am using PIC24FJ64GU205 Curiosity board. But in my case
my pins configurations are.
// LCD Pin Connection in 4-bit mode
#define LCD_RW LATAbits.LATA7
#define LCD_RS LATAbits.LATA8
#define LCD_EN LATAbits.LATA9
#define LCD_REST LATAbits.LATA10
#define LCD_DB4 LATCbits.LATC4
#define LCD_DB5 LATCbits.LATC5
#define LCD_DB6 LATCbits.LATC6
#define LCD_DB7 LATCbits.LATC7
i am doing always LCD_RW = 0 in Initialization before while(1).
After printing Hello according to your function LCD not printing any thing or not responding.
I am little confused how is this possible. All wiring i checked it is correct.
Please help me sir.
This is my main code.
int main(void)
{
// initialize the device
SYSTEM_Initialize();
LCD_RW = 0;
LCD_Init();
LCD_TextDisplayString(1,”Hii”);
LED_SetLow();
while (1)
{
// Add your application code
}
return 1;
}
Hello. First, thanks for sharing such information, it’s very hard to find quality info for LCDs based on ST7920. I have been doing my own experiments with this display/controller, and almost everything works perfectly… but I am facing issues to clear the GDRAM in graphics mode. It takes a lot of time to do it, the LCD fills every line with “zeroes”, but not as fast as I expected. This means the microprocessor is stuck in the pooling every time I need to clear (or fill) the screen. It does not happen in text mode, the clear command is almost instantaneous… Have you faced delays to clean the screen as well? Your LCD_ClearGraphics(void) function is basically what I’ve written in my code… Thanks
Hi, you mentioned that the microprocessor is stuck in the pooling when you fill your screen with zeros, can you set a breakpoint and see exactly where the code is stuck? There is nothing in my code which waits in a loop, so it’s possible that your code might be waiting on the LCD BUSY signal, which could take a while. Check your code to see if there’s any such loop, and from there see how you can improve it, for example, by changing to a delay.