{"id":655,"date":"2021-12-27T03:46:35","date_gmt":"2021-12-27T03:46:35","guid":{"rendered":"https:\/\/blog.embeddedexpert.io\/?p=655"},"modified":"2021-12-27T03:46:38","modified_gmt":"2021-12-27T03:46:38","slug":"working-with-stm32-and-liquid-crystal-display-i2c-mode","status":"publish","type":"post","link":"https:\/\/blog.embeddedexpert.io\/?p=655","title":{"rendered":"Working with STM32 and Liquid Crystal display: I2C mode"},"content":{"rendered":"\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-medium_image\"><img loading=\"lazy\" decoding=\"async\" width=\"400\" height=\"533\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/12\/IMG_7559-400x533.jpg\" alt=\"\" class=\"wp-image-656\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/12\/IMG_7559-400x533.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/12\/IMG_7559-225x300.jpg 225w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/12\/IMG_7559-768x1024.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/12\/IMG_7559-1152x1536.jpg 1152w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/12\/IMG_7559-1536x2048.jpg 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/12\/IMG_7559-1150x1533.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/12\/IMG_7559-750x1000.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/12\/IMG_7559-250x333.jpg 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/12\/IMG_7559-scaled.jpg 1920w\" sizes=\"(max-width: 400px) 100vw, 400px\" \/><\/figure><\/div>\n\n\n\n<p>In the pervious guide (<a rel=\"noreferrer noopener\" href=\"https:\/\/blog.embeddedexpert.io\/?p=600\" data-type=\"URL\" data-id=\"https:\/\/blog.embeddedexpert.io\/?p=600\" target=\"_blank\">here<\/a>), we took a look how to interface Liquid Crystal Display (LCD) in 4-bit mode which requires 4-line of data, RS line and Enable line, in total 6 lines of the mcu has to be reserved for the LCD. In this guide, we shall use PCF8574 which is 8-bit expander over I2C bus.<\/p>\n\n\n\n<p>In this guide, we shall cover the following:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Connection diagram <\/li><li>Code<\/li><li>Demo<\/li><\/ul>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">1. Connection Diagram:<\/h2>\n\n\n\n<p>In this guide, we need the following part:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>LCD (16&#215;2 or 20&#215;4)<\/li><li>PCF8574 for LCD module<\/li><li>STM32F411RE Nucelo-64<\/li><\/ul>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"568\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/12\/Screen-Shot-2021-12-27-at-6.22.13-AM-1024x568.png\" alt=\"\" class=\"wp-image-657\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/12\/Screen-Shot-2021-12-27-at-6.22.13-AM-1024x568.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/12\/Screen-Shot-2021-12-27-at-6.22.13-AM-300x166.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/12\/Screen-Shot-2021-12-27-at-6.22.13-AM-768x426.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/12\/Screen-Shot-2021-12-27-at-6.22.13-AM-1536x851.png 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/12\/Screen-Shot-2021-12-27-at-6.22.13-AM-2048x1135.png 2048w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/12\/Screen-Shot-2021-12-27-at-6.22.13-AM-1150x637.png 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/12\/Screen-Shot-2021-12-27-at-6.22.13-AM-750x416.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/12\/Screen-Shot-2021-12-27-at-6.22.13-AM-400x222.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/12\/Screen-Shot-2021-12-27-at-6.22.13-AM-250x139.png 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">2. Code:<\/h2>\n\n\n\n<p>First things first, we need to initialize the I2C of the stm32, you can find more information about I2C and how initialize it from <a href=\"https:\/\/blog.embeddedexpert.io\/?p=416\" data-type=\"URL\" data-id=\"https:\/\/blog.embeddedexpert.io\/?p=416\" target=\"_blank\" rel=\"noreferrer noopener\">here<\/a><\/p>\n\n\n\n<p>Now, we need a function that allow us to write 4-bytes to the i2c bus with no memory address, just data <\/p>\n\n\n\n<p>The function shall be 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_write_i2c(char saddr,uint8_t *buffer, uint8_t length)\n{\t\nwhile (I2C1-&gt;SR2 &amp; I2C_SR2_BUSY);           \/\/wait until bus not busy\nI2C1-&gt;CR1 |= I2C_CR1_START;                   \/\/generate start\nwhile (!(I2C1-&gt;SR1 &amp; I2C_SR1_SB)){;}\t\t\t\t\t\/\/wait until start is generated\nvolatile int Temp;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\nI2C1-&gt;DR = saddr&lt;&lt; 1;                 \t \t\t\t\/\/ Send slave address\nwhile (!(I2C1-&gt;SR1 &amp; I2C_SR1_ADDR)){;}        \/\/wait until address flag is set\nTemp = I2C1-&gt;SR2; \t\t\t\t\t\t\t\t\t\t\t\t\t\t\/\/Clear SR2\n\/\/sending the data\nfor (uint8_t i=0;i&lt;length;i++)\n { \n I2C1-&gt;DR=buffer[i]; \t\t\t\t\t\t\t\t\t\t\t\t\t\/\/filling buffer with command or data\n\twhile (!(I2C1-&gt;SR1 &amp; I2C_SR1_BTF));\n }\t\n                             \nI2C1-&gt;CR1 |= I2C_CR1_STOP;\t\t\t\t\t\t\t\t\t\t\/\/wait until transfer finished\n\n}<\/pre><\/div>\n\n\n\n<p>Now, for the LCD. In order to send data or command, we need to mask the two lines of the LCD which they are En line and RS line.<\/p>\n\n\n\n<p>When we want to display a character, we need to send data, hence we need to set RS low and high for command. This can be achieved as following:<\/p>\n\n\n\n<p>For sending command<\/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_cmd (char cmd)\n{\n  char data_u, data_l;\n\tuint8_t data_t[4];\n\tdata_u = (cmd&amp;0xf0);\n\tdata_l = ((cmd&lt;&lt;4)&amp;0xf0);\n\tdata_t[0] = data_u|0x0C;  \/\/en=1, rs=0\n\tdata_t[1] = data_u|0x08;  \/\/en=0, rs=0\n\tdata_t[2] = data_l|0x0C;  \/\/en=1, rs=0\n\tdata_t[3] = data_l|0x08;  \/\/en=0, rs=0\n\tlcd_write_i2c(SLAVE_ADDRESS_LCD,(uint8_t *)data_t,4);\n}<\/pre><\/div>\n\n\n\n<p>For sending data<\/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_data (char data)\n{\n\tchar data_u, data_l;\n\tuint8_t data_t[4];\n\tdata_u = (data&amp;0xf0);\n\tdata_l = ((data&lt;&lt;4)&amp;0xf0);\n\tdata_t[0] = data_u|0x0D;  \/\/en=1, rs=1\n\tdata_t[1] = data_u|0x09;  \/\/en=0, rs=1\n\tdata_t[2] = data_l|0x0D;  \/\/en=1, rs=1\n\tdata_t[3] = data_l|0x09;  \/\/en=0, rs=1\n\tlcd_write_i2c(SLAVE_ADDRESS_LCD,(uint8_t *)data_t,4);\n}<\/pre><\/div>\n\n\n\n<p>For the initializing the LCD, we need the send the following sequence <\/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\tdelay(50);  \/\/ wait for &gt;40ms\n\tlcd_send_cmd (0x3);\n\tdelay(5);  \/\/ wait for &gt;4.1ms\n\tlcd_send_cmd (0x3);\n\tdelay(1);  \/\/ wait for &gt;100us\n\tlcd_send_cmd (0x3);\n\tdelay(10);\n\tlcd_send_cmd (0x2);  \/\/ 4bit mode\n\tdelay(10);\n\n  \/\/ dislay initialisation\n\tlcd_send_cmd (0x28); \/\/ Function set --&gt; DL=0 (4 bit mode), N = 1 (2 line display) F = 0 (5x8 characters)\n\tdelay(1);\n\tlcd_send_cmd (0x08); \/\/Display on\/off control --&gt; D=0,C=0, B=0  ---&gt; display off\n\tdelay(1);\n\tlcd_send_cmd (0x01);  \/\/ clear display\n\tdelay(1);\n\tdelay(1);\n\tlcd_send_cmd (0x06); \/\/Entry mode set --&gt; I\/D = 1 (increment cursor) &amp; S = 0 (no shift)\n\tdelay(1);\n\tlcd_send_cmd (0x0C); \/\/Display on\/off control --&gt; D = 1, C and B = 0. (Cursor and blink, last two bits)\n}<\/pre><\/div>\n\n\n\n<p>for set a cursor at certain location:<\/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)\n{\n\tint i=0;\n\tswitch(b){\n\tcase 0:lcd_send_cmd(0x80);break;\n\tcase 1:lcd_send_cmd(0xC0);break;\n\tcase 2:lcd_send_cmd(0x94);break;\n\tcase 3:lcd_send_cmd(0xd4);break;}\n\tfor(i=0;i&lt;a;i++)\n\tlcd_send_cmd(0x14);\n}\n<\/pre><\/div>\n\n\n\n<p>For writing a string:<\/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_send_data (*str++);\n}\n<\/pre><\/div>\n\n\n\n<p>To clear the LCD, we can send the following command:<\/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_send_cmd(LCD_CLEARDISPLAY);\n\tdelay(100);\n\t\n}\n<\/pre><\/div>\n\n\n\n<p>In our main.c file, <\/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;i2c.h&quot;\n#include &quot;uart.h&quot;\n#include &quot;stdlib.h&quot;\n#include &quot;LiquidCrystal_PCF8574.h&quot;\n\nuint16_t var;\nchar str[40];\n\nint main()\n\t{\n\t\tUSART2_Init();\n\t\ti2c_init();\n\t\tlcd_init();\n\t\tlcd_clear();\n\n\twhile(1)\n\t\t\n\t\t{\n\t\tsetCursor(0,0);\n\t\tlcd_send_string(&quot;LCD 2004 I2C w STM32&quot;);\n\t\tsetCursor(0,1);\n\t\tlcd_send_string(&quot;EmbeddedExpert.io&quot;);\n\t\tsetCursor(0,2);\n\t\tlcd_send_string(&quot;Bare Metal&quot;);\n\t\tsetCursor(0,3);\n\t\tsprintf(str,&quot;var=%d&quot;,++var);\n\t\tlcd_send_string(str);\t\n\t\tfor (int i=0;i&lt;100000;i++);\n\t\t\t}\n\t\t}\n\t\n<\/pre><\/div>\n\n\n\n<p>You can download the source code from here<\/p>\n\n\n\n<div class=\"wp-block-file\"><a href=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/12\/LCD2004_I2C.zip\">LCD2004_I2C<\/a><a href=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/12\/LCD2004_I2C.zip\" class=\"wp-block-file__button\" download>Download<\/a><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">3. Demo:<\/h2>\n\n\n\n<figure class=\"wp-block-video\"><video controls src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/12\/IMG_7561.mp4\"><\/video><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Happy coding \ud83d\ude00 <\/p>\n","protected":false},"excerpt":{"rendered":"<p>In the pervious guide (here), we took a look how to interface Liquid Crystal Display (LCD) in 4-bit mode which requires 4-line of data, RS line and Enable line, in total 6 lines of the mcu has to be reserved for the LCD. In this guide, we shall use PCF8574 which is 8-bit expander over [&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-655","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\/655"}],"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=655"}],"version-history":[{"count":2,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/655\/revisions"}],"predecessor-version":[{"id":661,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/655\/revisions\/661"}],"wp:attachment":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=655"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=655"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=655"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}