{"id":3186,"date":"2025-01-25T14:11:53","date_gmt":"2025-01-25T14:11:53","guid":{"rendered":"https:\/\/blog.embeddedexpert.io\/?p=3186"},"modified":"2025-01-25T14:11:55","modified_gmt":"2025-01-25T14:11:55","slug":"building-a-library-for-1602-lcd-with-stm32f4-display-initialization-and-display-characters-part-2","status":"publish","type":"post","link":"https:\/\/blog.embeddedexpert.io\/?p=3186","title":{"rendered":"Building a Library for 1602 LCD with STM32F4: Display Initialization and Display Characters (Part 2)"},"content":{"rendered":"\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"1024\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/163ed22b-34cb-4106-8f7e-38582ecf4e4d-1.webp\" alt=\"\" class=\"wp-image-3187\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/163ed22b-34cb-4106-8f7e-38582ecf4e4d-1.webp 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/163ed22b-34cb-4106-8f7e-38582ecf4e4d-1-300x300.webp 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/163ed22b-34cb-4106-8f7e-38582ecf4e4d-1-150x150.webp 150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/163ed22b-34cb-4106-8f7e-38582ecf4e4d-1-768x768.webp 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/163ed22b-34cb-4106-8f7e-38582ecf4e4d-1-750x750.webp 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/163ed22b-34cb-4106-8f7e-38582ecf4e4d-1-400x400.webp 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/163ed22b-34cb-4106-8f7e-38582ecf4e4d-1-250x250.webp 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>In the second part of building library for 1602 LCD, we shall intialize the LCD and start writing some data to the display.<\/p>\n\n\n\n<p>In this guide, we shall cover the following:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Creating header and source files.<\/li>\n\n\n\n<li>Developing the header file.<\/li>\n\n\n\n<li>Developing the source file.<\/li>\n\n\n\n<li>Testing the library.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">4. Creating Header and Source Files:<\/h2>\n\n\n\n<p>After the project has been generated by STM32CubeMX within STM32CubeIDE, we shall add new source file and header file.<\/p>\n\n\n\n<p>Right click on Src folder and add new source file as following:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"486\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/11\/2024-11-07_07-03-43-1024x486.jpg\" alt=\"\" class=\"wp-image-2972\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/11\/2024-11-07_07-03-43-1024x486.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/11\/2024-11-07_07-03-43-300x142.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/11\/2024-11-07_07-03-43-768x364.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/11\/2024-11-07_07-03-43-1536x729.jpg 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/11\/2024-11-07_07-03-43-2048x972.jpg 2048w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/11\/2024-11-07_07-03-43-1150x546.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/11\/2024-11-07_07-03-43-750x356.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/11\/2024-11-07_07-03-43-400x190.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/11\/2024-11-07_07-03-43-250x119.jpg 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Give a name for the source file, we shall name it as lcd_driver.c as following:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"734\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-25_16-20-46-1024x734.jpg\" alt=\"\" class=\"wp-image-3188\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-25_16-20-46-1024x734.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-25_16-20-46-300x215.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-25_16-20-46-768x550.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-25_16-20-46-1150x824.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-25_16-20-46-750x538.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-25_16-20-46-400x287.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-25_16-20-46-250x179.jpg 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-25_16-20-46.jpg 1172w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>In similar manner, right click on Inc folder and add new header file with name of lcd_driver.h.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">5. Developing the Header File:<\/h2>\n\n\n\n<p><\/p>\n\n\n\n<p>Open lcd_driver.h header file.<\/p>\n\n\n\n<p>After the define of the header file, include the main.h header file as following:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#include &quot;main.h&quot;<\/pre><\/div>\n\n\n\n<p>Next, declare the following function:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">void lcd_init (void);<\/pre><\/div>\n\n\n\n<p>This function shall initialize the display. It takes no parameters and returns nothing.n<\/p>\n\n\n\n<p>Declare also this function:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">void setCursor(int a, int b);<\/pre><\/div>\n\n\n\n<p>This function shall set the cursor at the desired location. It will take the following parameters:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li> int a is the column position.<\/li>\n\n\n\n<li>int b is the row address.<\/li>\n<\/ul>\n\n\n\n<p>The function shall return nothing.<\/p>\n\n\n\n<p>Declare the following function:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">void lcd_send_string (char *str);<\/pre><\/div>\n\n\n\n<p>This function shall print a string to the lcd. It takes characters array and returns nothing.<\/p>\n\n\n\n<p>Also, this function:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">void lcd_clear (void);<\/pre><\/div>\n\n\n\n<p>This function shall clear the entire display, it takes nothing return nothing.<\/p>\n\n\n\n<p>Next,<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">void create_custom_char (uint8_t loc, char * data);<\/pre><\/div>\n\n\n\n<p>This function shall store a custom character to the LCD GRAM. It takes the following:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>uint8_t loc which is the character location in the memory.<\/li>\n\n\n\n<li>character array that hold the custom character.<\/li>\n<\/ul>\n\n\n\n<p>The function shall return nothing<\/p>\n\n\n\n<p>The final function is:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">void display_custom_char (uint8_t loc);<\/pre><\/div>\n\n\n\n<p>This function shall draw the custom character that store the specific location.<\/p>\n\n\n\n<p>Hence, the header file as following:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#ifndef INC_LCD_DRIVER_H_\n#define INC_LCD_DRIVER_H_\n\n#include &quot;main.h&quot;\n\nvoid lcd_init (void);\nvoid setCursor(int a, int b);\nvoid lcd_send_string (char *str);\nvoid lcd_clear (void);\nvoid create_custom_char (uint8_t loc, char * data);\nvoid display_custom_char (uint8_t loc);\n\n\n\n\n#endif \/* INC_LCD_DRIVER_H_ *\/<\/pre><\/div>\n\n\n\n<p>Thats all for the header file.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">6. Developing the Source File:<\/h2>\n\n\n\n<p>We start by including lcd_driver.h header file as following:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#include &quot;lcd_driver.h&quot;<\/pre><\/div>\n\n\n\n<p>Since the LCD is interfaced in 4-bit mode, we need to send the as 4bit wide, hence a nibble function is used to transmit the data,<\/p>\n\n\n\n<p>The sequence as following:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"400\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-25_16-48-20-1024x400.jpg\" alt=\"\" class=\"wp-image-3189\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-25_16-48-20-1024x400.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-25_16-48-20-300x117.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-25_16-48-20-768x300.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-25_16-48-20-1536x601.jpg 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-25_16-48-20-1150x450.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-25_16-48-20-750x293.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-25_16-48-20-400x156.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-25_16-48-20-250x98.jpg 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-25_16-48-20.jpg 2010w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Set the 4 upper bits of the data, then set the EN pin to high then back to low.<\/p>\n\n\n\n<p>Repeat the same step for the 4 lower bits of the data.<\/p>\n\n\n\n<p>Hence the function as following:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">static void LCD_WriteNibble(uint8_t nibble)\n{\n    \/\/ Set D4-D7 according to the nibble value\n    HAL_GPIO_WritePin(D4_GPIO_Port, D4_Pin, (nibble &amp; 0x01));\n    HAL_GPIO_WritePin(D5_GPIO_Port, D5_Pin, (nibble &amp; 0x02) &gt;&gt; 1);\n    HAL_GPIO_WritePin(D6_GPIO_Port, D6_Pin, (nibble &amp; 0x04) &gt;&gt; 2);\n    HAL_GPIO_WritePin(D7_GPIO_Port, D7_Pin, (nibble &amp; 0x08) &gt;&gt; 3);\n\n    \/\/ Toggle EN pin to latch the nibble\n    HAL_GPIO_WritePin(EN_GPIO_Port, EN_Pin, GPIO_PIN_SET);\n    \/\/HAL_Delay(1);  \/\/ Small delay to ensure the LCD latches the data\n    HAL_GPIO_WritePin(EN_GPIO_Port, EN_Pin, GPIO_PIN_RESET);\n    HAL_Delay(1);  \/\/ Small delay to ensure the LCD processes the nibble\n}<\/pre><\/div>\n\n\n\n<p>Defined as static since it is accessible from the lcd_driver source file and not from any other source file.<\/p>\n\n\n\n<p>In each LCD, there is two functions needed as following:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Function that will write command to the LCD.<\/li>\n\n\n\n<li>Function that will write data to the LCD.<\/li>\n<\/ul>\n\n\n\n<p>Hence, the function to write command to the LCD as following:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">static void LCD_WriteCommand(uint8_t command)\n{\n    \/\/ Set RS to 0 for command mode\n    HAL_GPIO_WritePin(RS_GPIO_Port, RS_Pin, GPIO_PIN_RESET);\n\n    \/\/ Send the higher nibble\n    LCD_WriteNibble(command &gt;&gt; 4);\n    \/\/ Send the lower nibble\n    LCD_WriteNibble(command &amp; 0x0F);\n\n    HAL_Delay(1);  \/\/ Delay for command execution\n}<\/pre><\/div>\n\n\n\n<p>The steps as following:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Set the RS pin to Low to indicate command mode.<\/li>\n\n\n\n<li>Write the command as two 4-bits data.<\/li>\n\n\n\n<li>Wait for 1ms for the command to finish.<\/li>\n<\/ul>\n\n\n\n<p>For the writing data, it is similar to writing command except that RS is set to 1 as following:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">static void LCD_WriteData(uint8_t data)\n{\n    \/\/ Set RS to 1 for data mode\n    HAL_GPIO_WritePin(RS_GPIO_Port, RS_Pin, GPIO_PIN_SET);\n\n    \/\/ Send the higher nibble\n    LCD_WriteNibble(data &gt;&gt; 4);\n    \/\/ Send the lower nibble\n    LCD_WriteNibble(data &amp; 0x0F);\n\n    HAL_Delay(1);  \/\/ Delay for data processing\n}<\/pre><\/div>\n\n\n\n<p>The initialization sequence as following:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1020\" height=\"1024\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-25_16-57-09-1020x1024.jpg\" alt=\"\" class=\"wp-image-3190\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-25_16-57-09-1020x1024.jpg 1020w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-25_16-57-09-300x300.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-25_16-57-09-150x150.jpg 150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-25_16-57-09-768x771.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-25_16-57-09-1150x1155.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-25_16-57-09-750x753.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-25_16-57-09-400x402.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-25_16-57-09-250x250.jpg 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-25_16-57-09.jpg 1436w\" sizes=\"(max-width: 1020px) 100vw, 1020px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Hence the initialization function as following:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">void lcd_init (void)\n{\n\t\/\/ 4 bit initialisation\n\tHAL_Delay(50);  \/\/ wait for &gt;40ms\n\tLCD_WriteCommand (0x3);\n\tHAL_Delay(5);  \/\/ wait for &gt;4.1ms\n\tLCD_WriteCommand (0x3);\n\tHAL_Delay(1);  \/\/ wait for &gt;100us\n\tLCD_WriteCommand (0x3);\n\tHAL_Delay(10);\n\tLCD_WriteCommand (0x2);  \/\/ 4bit mode\n\tHAL_Delay(10);\n\n  \/\/ dislay initialisation\n\tLCD_WriteCommand (0x28); \/\/ Function set --&gt; DL=0 (4 bit mode), N = 1 (2 line display) F = 0 (5x8 characters)\n\tHAL_Delay(1);\n\tLCD_WriteCommand (0x08); \/\/Display on\/off control --&gt; D=0,C=0, B=0  ---&gt; display off\n\tHAL_Delay(1);\n\tLCD_WriteCommand (0x01);  \/\/ clear display\n\tHAL_Delay(1);\n\tHAL_Delay(1);\n\tLCD_WriteCommand (0x06); \/\/Entry mode set --&gt; I\/D = 1 (increment cursor) &amp; S = 0 (no shift)\n\tHAL_Delay(1);\n\tLCD_WriteCommand (0x0C); \/\/Display on\/off control --&gt; D = 1, C and B = 0. (Cursor and blink, last two bits)\n\n}<\/pre><\/div>\n\n\n\n<p>For setting the cursor at certain position:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">oid setCursor(int a, int b)\n{\n\tint i=0;\n\tswitch(b){\n\tcase 0:LCD_WriteCommand(0x80);break;\n\tcase 1:LCD_WriteCommand(0xC0);break;\n\tcase 2:LCD_WriteCommand(0x94);break;\n\tcase 3:LCD_WriteCommand(0xd4);break;}\n\tfor(i=0;i&lt;a;i++)\n\t\tLCD_WriteCommand(0x14);\n}<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>To write string to the lcd, simple send data to the lcd as following:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">void lcd_send_string (char *str)\n{\n\twhile (*str) LCD_WriteData (*str++);\n}\n<\/pre><\/div>\n\n\n\n<p>To clear the display:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">void lcd_clear (void)\n{\n\n\t#define LCD_CLEARDISPLAY 0x01\n\tLCD_WriteCommand(LCD_CLEARDISPLAY);\n\tHAL_Delay(100);\n\n}<\/pre><\/div>\n\n\n\n<p>For setting a custom character and display it:<\/p>\n\n\n\n<p>For more information about it, please refer to this guide <a href=\"https:\/\/blog.embeddedexpert.io\/?p=1039\" data-type=\"link\" data-id=\"https:\/\/blog.embeddedexpert.io\/?p=1039\" target=\"_blank\" rel=\"noreferrer noopener\">here<\/a>.<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">void create_custom_char (uint8_t loc, char * data)\n{\n\tswitch (loc)\n\t{\n\t\tcase 0:LCD_WriteCommand(0x40);break;\n\t\tcase 1:LCD_WriteCommand(0x40+8);break;\n\t\tcase 2:LCD_WriteCommand(0x40+16);break;\n\t\tcase 3:LCD_WriteCommand(0x40+24);break;\n\t\tcase 4:LCD_WriteCommand(0x40+32);break;\n\t\tcase 5:LCD_WriteCommand(0x40+40);break;\n\t\tcase 6:LCD_WriteCommand(0x40+48);break;\n\t\tcase 7:LCD_WriteCommand(0x40+56);break;\n\t\tdefault : break;\n\t}\n\n\tuint8_t cc_data[8];\n\tfor (int i=0;i&lt;8;i++)\n\t{\n\t\tcc_data[i]=*data++;\n\t}\n\tfor (int i=0;i&lt;8;i++)\n\t{\n\t\tLCD_WriteData(cc_data[i]);\n\t}\n\n}\n\nvoid display_custom_char (uint8_t loc)\n{\n\tswitch (loc)\n\t\t\t{\n\t\tcase 0:LCD_WriteData(0);break;\n\t\tcase 1:LCD_WriteData(1);break;\n\t\tcase 2:LCD_WriteData(2);break;\n\t\tcase 3:LCD_WriteData(3);break;\n\t\tcase 4:LCD_WriteData(4);break;\n\t\tcase 5:LCD_WriteData(5);break;\n\t\tcase 6:LCD_WriteData(6);break;\n\t\tcase 7:LCD_WriteData(7);break;\n\t\tdefault: break;\n\t}\n}\n<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Hence, the source file as following:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#include &quot;lcd_driver.h&quot;\n\n\nstatic void LCD_WriteNibble(uint8_t nibble)\n{\n    \/\/ Set D4-D7 according to the nibble value\n    HAL_GPIO_WritePin(D4_GPIO_Port, D4_Pin, (nibble &amp; 0x01));\n    HAL_GPIO_WritePin(D5_GPIO_Port, D5_Pin, (nibble &amp; 0x02) &gt;&gt; 1);\n    HAL_GPIO_WritePin(D6_GPIO_Port, D6_Pin, (nibble &amp; 0x04) &gt;&gt; 2);\n    HAL_GPIO_WritePin(D7_GPIO_Port, D7_Pin, (nibble &amp; 0x08) &gt;&gt; 3);\n\n    \/\/ Toggle EN pin to latch the nibble\n    HAL_GPIO_WritePin(EN_GPIO_Port, EN_Pin, GPIO_PIN_SET);\n    \/\/HAL_Delay(1);  \/\/ Small delay to ensure the LCD latches the data\n    HAL_GPIO_WritePin(EN_GPIO_Port, EN_Pin, GPIO_PIN_RESET);\n    HAL_Delay(1);  \/\/ Small delay to ensure the LCD processes the nibble\n}\n\nstatic void LCD_WriteCommand(uint8_t command)\n{\n    \/\/ Set RS to 0 for command mode\n    HAL_GPIO_WritePin(RS_GPIO_Port, RS_Pin, GPIO_PIN_RESET);\n\n    \/\/ Send the higher nibble\n    LCD_WriteNibble(command &gt;&gt; 4);\n    \/\/ Send the lower nibble\n    LCD_WriteNibble(command &amp; 0x0F);\n\n    HAL_Delay(1);  \/\/ Delay for command execution\n}\n\nstatic void LCD_WriteData(uint8_t data)\n{\n    \/\/ Set RS to 1 for data mode\n    HAL_GPIO_WritePin(RS_GPIO_Port, RS_Pin, GPIO_PIN_SET);\n\n    \/\/ Send the higher nibble\n    LCD_WriteNibble(data &gt;&gt; 4);\n    \/\/ Send the lower nibble\n    LCD_WriteNibble(data &amp; 0x0F);\n\n    HAL_Delay(1);  \/\/ Delay for data processing\n}\n\n\nvoid setCursor(int a, int b)\n{\n\tint i=0;\n\tswitch(b){\n\tcase 0:LCD_WriteCommand(0x80);break;\n\tcase 1:LCD_WriteCommand(0xC0);break;\n\tcase 2:LCD_WriteCommand(0x94);break;\n\tcase 3:LCD_WriteCommand(0xd4);break;}\n\tfor(i=0;i&lt;a;i++)\n\t\tLCD_WriteCommand(0x14);\n}\n\n\nvoid lcd_send_string (char *str)\n{\n\twhile (*str) LCD_WriteData (*str++);\n}\n\n\nvoid lcd_init (void)\n{\n\t\/\/ 4 bit initialisation\n\tHAL_Delay(50);  \/\/ wait for &gt;40ms\n\tLCD_WriteCommand (0x3);\n\tHAL_Delay(5);  \/\/ wait for &gt;4.1ms\n\tLCD_WriteCommand (0x3);\n\tHAL_Delay(1);  \/\/ wait for &gt;100us\n\tLCD_WriteCommand (0x3);\n\tHAL_Delay(10);\n\tLCD_WriteCommand (0x2);  \/\/ 4bit mode\n\tHAL_Delay(10);\n\n  \/\/ dislay initialisation\n\tLCD_WriteCommand (0x28); \/\/ Function set --&gt; DL=0 (4 bit mode), N = 1 (2 line display) F = 0 (5x8 characters)\n\tHAL_Delay(1);\n\tLCD_WriteCommand (0x08); \/\/Display on\/off control --&gt; D=0,C=0, B=0  ---&gt; display off\n\tHAL_Delay(1);\n\tLCD_WriteCommand (0x01);  \/\/ clear display\n\tHAL_Delay(1);\n\tHAL_Delay(1);\n\tLCD_WriteCommand (0x06); \/\/Entry mode set --&gt; I\/D = 1 (increment cursor) &amp; S = 0 (no shift)\n\tHAL_Delay(1);\n\tLCD_WriteCommand (0x0C); \/\/Display on\/off control --&gt; D = 1, C and B = 0. (Cursor and blink, last two bits)\n\n}\n\nvoid lcd_clear (void)\n{\n\n\t#define LCD_CLEARDISPLAY 0x01\n\tLCD_WriteCommand(LCD_CLEARDISPLAY);\n\tHAL_Delay(100);\n\n}\n\nvoid create_custom_char (uint8_t loc, char * data)\n{\n\tswitch (loc)\n\t{\n\t\tcase 0:LCD_WriteCommand(0x40);break;\n\t\tcase 1:LCD_WriteCommand(0x40+8);break;\n\t\tcase 2:LCD_WriteCommand(0x40+16);break;\n\t\tcase 3:LCD_WriteCommand(0x40+24);break;\n\t\tcase 4:LCD_WriteCommand(0x40+32);break;\n\t\tcase 5:LCD_WriteCommand(0x40+40);break;\n\t\tcase 6:LCD_WriteCommand(0x40+48);break;\n\t\tcase 7:LCD_WriteCommand(0x40+56);break;\n\t\tdefault : break;\n\t}\n\n\tuint8_t cc_data[8];\n\tfor (int i=0;i&lt;8;i++)\n\t{\n\t\tcc_data[i]=*data++;\n\t}\n\tfor (int i=0;i&lt;8;i++)\n\t{\n\t\tLCD_WriteData(cc_data[i]);\n\t}\n\n}\n\nvoid display_custom_char (uint8_t loc)\n{\n\tswitch (loc)\n\t\t\t{\n\t\tcase 0:LCD_WriteData(0);break;\n\t\tcase 1:LCD_WriteData(1);break;\n\t\tcase 2:LCD_WriteData(2);break;\n\t\tcase 3:LCD_WriteData(3);break;\n\t\tcase 4:LCD_WriteData(4);break;\n\t\tcase 5:LCD_WriteData(5);break;\n\t\tcase 6:LCD_WriteData(6);break;\n\t\tcase 7:LCD_WriteData(7);break;\n\t\tdefault: break;\n\t}\n}\n<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">7. Testing the Library:<\/h2>\n\n\n\n<p>In main.c file, in user code includes, include the lcd_driver header file as following:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#include &quot;lcd_driver.h&quot;<\/pre><\/div>\n\n\n\n<p>In user begin PV (Private variables):<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">char cc1[8] = {0x00, 0x00, 0x0A, 0x00, 0x11, 0x0E, 0x00, 0x00};  \/\/ smiley\nchar cc2[8] = {0x0E, 0x0E, 0x04, 0x0E, 0x15, 0x04, 0x0A, 0x0A};  \/\/ Robo\nchar cc3[8] = {0x08, 0x0C, 0x0E, 0x0F, 0x0E, 0x0C, 0x08, 0x00};  \/\/ arrow\nchar cc4[8] = {0x00, 0x04, 0x0E, 0x0E, 0x0E, 0x1F, 0x04, 0x00};  \/\/ bell\nchar cc5[8] = {0x00, 0x00, 0x0A, 0x15, 0x11, 0x0E, 0x04, 0x00};  \/\/ Heart\nchar cc6[8] = {0x00, 0x0E, 0x11, 0x11, 0x11, 0x0A, 0x1B, 0x00};  \/\/ omega\nchar cc7[8] = {0x0E, 0x10, 0x17, 0x12, 0x12, 0x12, 0x10, 0x0E};  \/\/ CT\nchar cc8[8] = {0x04, 0x04, 0x1F, 0x04, 0x04, 0x00, 0x1F, 0x00};  \/\/ +-<\/pre><\/div>\n\n\n\n<p>In user code begin 2 in main function:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">  lcd_init();\n\n  create_custom_char(0,cc1);\n  create_custom_char(1,cc2);\n  create_custom_char(2,cc3);\n  create_custom_char(3,cc4);\n  create_custom_char(5,cc6);\n  create_custom_char(6,cc7);\n  create_custom_char(7,cc8);<\/pre><\/div>\n\n\n\n<p>In user code begin 3 in while 1 loop:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">\tsetCursor(0, 0);\n\tlcd_send_string(&quot;Custom characters&quot;);\n\tHAL_Delay(200);\n\tsetCursor(0, 1);\n\tfor (int i=0; i&lt;8; i++) {display_custom_char(i); HAL_Delay(300);}\n\tHAL_Delay(700);\n\tlcd_clear();\n\tHAL_Delay(200);<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Save the project, build it and run it on your board as following:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"28\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/11\/image-1024x28.png\" alt=\"\" class=\"wp-image-2982\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/11\/image-1024x28.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/11\/image-300x8.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/11\/image-768x21.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/11\/image-1536x43.png 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/11\/image-1150x32.png 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/11\/image-750x21.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/11\/image-400x11.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/11\/image-250x7.png 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/11\/image.png 1734w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/IMG_5723.heic\" alt=\"\" class=\"wp-image-3191\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>You may download the code from <a href=\"https:\/\/github.com\/hussamaldean\/LCD1602-STM32-Library\/tree\/main\" data-type=\"link\" data-id=\"https:\/\/github.com\/hussamaldean\/LCD1602-STM32-Library\/tree\/main\" target=\"_blank\" rel=\"noreferrer noopener\">here<\/a>.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Happy coding \ud83d\ude09<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In the second part of building library for 1602 LCD, we shall intialize the LCD and start writing some data to the display. In this guide, we shall cover the following: 4. Creating Header and Source Files: After the project has been generated by STM32CubeMX within STM32CubeIDE, we shall add new source file and header [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2,19,11,12],"tags":[],"class_list":["post-3186","post","type-post","status-publish","format-standard","hentry","category-embedded-systems","category-lcd","category-peripheral-drivers","category-stm32"],"_links":{"self":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/3186"}],"collection":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3186"}],"version-history":[{"count":1,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/3186\/revisions"}],"predecessor-version":[{"id":3192,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/3186\/revisions\/3192"}],"wp:attachment":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3186"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3186"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3186"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}