{"id":4363,"date":"2018-07-25T20:00:27","date_gmt":"2018-07-25T18:00:27","guid":{"rendered":"https:\/\/msalamon.pl\/?p=4363"},"modified":"2025-12-27T20:38:06","modified_gmt":"2025-12-27T19:38:06","slug":"16x2-lcd-display-with-stm32-hal-part-1","status":"publish","type":"post","link":"https:\/\/msalamon.pl\/en\/16x2-lcd-display-with-stm32-hal-part-1\/","title":{"rendered":"16\u00d72 LCD Display with STM32 + HAL, Part 1"},"content":{"rendered":"\n<p>A 16\u00d72 character display is probably the most popular form of communication between the microcontroller world and the human world. I decided to make a mini series of three posts that will explain the differences between ways of controlling a 16\u00d72 LCD on STM32. You usually encounter just one method online, which is often sufficient. So why the others? Read on <\/p>\n\n\n\n<!--more-->\n\n\n\n<p>here.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"https:\/\/sklep.msalamon.pl\/produkt\/lcd-2x16-znakow\/?utm_source=blog&amp;utm_medium=banner&amp;utm_campaign=lcd16x2&amp;utm_content=Text\" target=\"_blank\" rel=\"noopener noreferrer\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"341\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2018\/09\/HD44780_baner-1024x341.jpg\" alt=\"\" class=\"wp-image-957\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/09\/HD44780_baner-1024x341.jpg 1024w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/09\/HD44780_baner-300x100.jpg 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/09\/HD44780_baner-768x256.jpg 768w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/09\/HD44780_baner-24x8.jpg 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/09\/HD44780_baner-36x12.jpg 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/09\/HD44780_baner-160x53.jpg 160w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/09\/HD44780_baner.jpg 1200w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p><\/p>\n\n\n\n<h1 class=\"wp-block-heading\">LCD 2\u00d716 display<\/h1>\n\n\n\n<p>An alphanumeric LCD, or character LCD, combines many advantages such as ease of use, low price, and transflectivity in the positive version. Its drawbacks are undoubtedly weak contrast and a low refresh rate.<\/p>\n\n\n\n<p>Supply voltage can also turn out to be a problem. The market is dominated by displays with a 5V supply level, especially from the \u201cmajfriends\u201d. Is that a problem? In <a href=\"http:\/\/msalamon.pl\/dlaczego-stm32\/\">__this__<\/a> post I pointed out one of the advantages of STM32, namely 5V\u2011tolerant IO. The voltage level coming out of the LCD is taken care of. What about the input? Usually the high\u2011level tolerance of the display controller is wide enough that 3.3V should be sufficient to drive it. My test specimen is intended for 5V, yet I was able to drive it from an STM32 successfully. You can also get a 3.3V version since such ones are increasingly available, but for \u201cextra\u201d you may have to pay \u201cextra\u201d.<\/p>\n\n\n\n<p>To talk to a classic HD44780\u2011compatible LCD we have two interfaces available \u2013 4\u2011bit and 8\u2011bit. I veeery rarely see anyone using the 8\u2011bit one. After all, it takes 4 precious MCU pins more than the popular 4\u2011bit version. In each of these modes we can in turn send data in two ways. One is continuous <em>write<\/em> mode with the display\u2019s <em>RW<\/em> signal tied to ground. It\u2019s the simplest and the one often found in online descriptions. The other method is handling with reading the busy flag. This requires connecting the <em>RW<\/em> pin to the microcontroller and controlling the data direction on the MCU&lt;-&gt;LCD line. Cost: one additional MCU pin.<\/p>\n\n\n\n<p>I\u2019d like to test all these methods and compare them in terms of the time required to send an entire 2\u00d716 character frame to the display. Curious about the results?<\/p>\n\n\n\n<p>The test platform will be a Nucleo\u201164 with an STM32F401RE, with <em>HCLK<\/em> set to 84 MHz.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/20180717_215128.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"960\" height=\"540\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/20180717_215128.jpg\" alt=\"\" class=\"wp-image-156\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/20180717_215128.jpg 960w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/20180717_215128-300x169.jpg 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/20180717_215128-768x432.jpg 768w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/20180717_215128-24x14.jpg 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/20180717_215128-36x20.jpg 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/20180717_215128-142x80.jpg 142w\" sizes=\"auto, (max-width: 960px) 100vw, 960px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">4\u2011bit bus without checking the busy flag<\/h2>\n\n\n\n<p>This approach is probably the most popular among alphanumeric LCD users. I\u2019m not surprised at all. It\u2019s the simplest to implement and \u201ccosts\u201d us little in terms of MCU resources.<\/p>\n\n\n\n<p>To drive the display I will use <a href=\"https:\/\/sklep.msalamon.pl\/produkt\/nucleo-f401re\/?utm_source=blog&amp;utm_medium=article&amp;utm_campaign=lcd16x2&amp;utm_content=Text\">Nucleo F401RE<\/a>.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"https:\/\/sklep.msalamon.pl\/kategoria-produktu\/dev-boardy\/stm32-nucleo\/?utm_source=blog&amp;utm_medium=banner&amp;utm_campaign=lcd16x2&amp;utm_content=nucleo\"><img loading=\"lazy\" decoding=\"async\" width=\"1200\" height=\"400\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2020\/07\/Nucleo-64-baner.jpg\" alt=\"\" class=\"wp-image-1593\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2020\/07\/Nucleo-64-baner.jpg 1200w, https:\/\/msalamon.pl\/wp-content\/uploads\/2020\/07\/Nucleo-64-baner-300x100.jpg 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2020\/07\/Nucleo-64-baner-1024x341.jpg 1024w, https:\/\/msalamon.pl\/wp-content\/uploads\/2020\/07\/Nucleo-64-baner-768x256.jpg 768w\" sizes=\"auto, (max-width: 1200px) 100vw, 1200px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p><\/p>\n\n\n\n<p>The connection diagram looks as follows:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/4bit_bez_RW_KiCad_5V.png\"><img loading=\"lazy\" decoding=\"async\" width=\"960\" height=\"388\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/4bit_bez_RW_KiCad_5V.png\" alt=\"\" class=\"wp-image-124\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/4bit_bez_RW_KiCad_5V.png 960w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/4bit_bez_RW_KiCad_5V-300x121.png 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/4bit_bez_RW_KiCad_5V-768x310.png 768w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/4bit_bez_RW_KiCad_5V-24x10.png 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/4bit_bez_RW_KiCad_5V-36x15.png 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/4bit_bez_RW_KiCad_5V-160x65.png 160w\" sizes=\"auto, (max-width: 960px) 100vw, 960px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p><\/p>\n\n\n\n<p>and the STM32CubeMX configuration<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/4bit_bez_RW_Cube.png\"><img loading=\"lazy\" decoding=\"async\" width=\"960\" height=\"577\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/4bit_bez_RW_Cube.png\" alt=\"\" class=\"wp-image-99\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/4bit_bez_RW_Cube.png 960w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/4bit_bez_RW_Cube-300x180.png 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/4bit_bez_RW_Cube-768x462.png 768w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/4bit_bez_RW_Cube-24x14.png 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/4bit_bez_RW_Cube-36x22.png 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/4bit_bez_RW_Cube-133x80.png 133w\" sizes=\"auto, (max-width: 960px) 100vw, 960px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p><\/p>\n\n\n\n<p>From the standpoint of measuring refresh time, we\u2019re interested in the time to send all commands and data to the display so that the test text appears. By tying the <em>RW<\/em> pin to ground, we put the display into continuous write mode. In this mode you must adjust the wait time between sending subsequent data so that it is longer than the processing of the previous byte. First I\u2019ll do this using the simplest HAL_Delay(), which is offered by ST\u2019s library.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/\n\/\/ Write byte to LCD\n\/\/\nvoid LCD_WriteByte(uint8_t data)\n{\n\tSET_LCD_E;\n\tLCD_SetDataPort(data &amp;gt;&amp;gt; 4);\n\tRESET_LCD_E;\n\n\tSET_LCD_E;\n\tLCD_SetDataPort(data);\n\tRESET_LCD_E;\n\n\tHAL_Delay(1); \/\/ &amp;lt;&amp;lt;--- wait for data processing\n}<\/pre>\n\n\n\n<p>The test code I will base on looks as follows:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">while (1)\n{\n\t\/\/ Measurement start\n\tLCD_Cls();\n\tLCD_Locate(0,0);\n\tLCD_String(\" STM32 + HD44780\");\n\tLCD_Locate(0,1);\n\tLCD_String(\"www.msalamon.pl \");\n\t\/\/ Measurement end\n\tHAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);\n\tHAL_Delay(500);\n}<\/pre>\n\n\n\n<p>Unfortunately the HAL_Delay() function works with a minimum resolution of 1 ms, which is the time base for the entire STM32HAL library. For the display this is relatively long, hence the result is poor. You can clearly see the refresh on the screen because it\u2019s simply too slow. The entire test refresh procedure takes as much as 67.29 ms! That\u2019s more than three times longer than what the human eye needs to be fooled and not notice the refresh. Because of this you can also see how the second line of characters flickers badly.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/4-bit_bez_RW_HAL_Delay.png\"><img loading=\"lazy\" decoding=\"async\" width=\"960\" height=\"266\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/4-bit_bez_RW_HAL_Delay.png\" alt=\"\" class=\"wp-image-110\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/4-bit_bez_RW_HAL_Delay.png 960w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/4-bit_bez_RW_HAL_Delay-300x83.png 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/4-bit_bez_RW_HAL_Delay-768x213.png 768w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/4-bit_bez_RW_HAL_Delay-24x7.png 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/4-bit_bez_RW_HAL_Delay-36x10.png 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/4-bit_bez_RW_HAL_Delay-160x44.png 160w\" sizes=\"auto, (max-width: 960px) 100vw, 960px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p><\/p>\n\n\n\n<p>We need to speed this up! Unfortunately ST\u2019s library doesn\u2019t have any delay function with finer resolution. What now? I\u2019m ending the post. You can\u2019t do it on STM32 \u2013 Arduino is better \ud83d\ude41<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">I WAS JOKING!<\/h3>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"alignleft\"><a href=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/Timery.png\"><img loading=\"lazy\" decoding=\"async\" width=\"111\" height=\"191\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/Timery.png\" alt=\"\" class=\"wp-image-100\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/Timery.png 111w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/Timery-14x24.png 14w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/Timery-21x36.png 21w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/Timery-46x80.png 46w\" sizes=\"auto, (max-width: 111px) 100vw, 111px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p><\/p>\n\n\n\n<p>The MCU used in the example (like every STM32) has plenty of hardware timers. Why let them sit and gather dust? I\u2019ll use one for the <em>delay<\/em>. Which one? For now I won\u2019t dive into the intricacies of timers and will quickly go over the configuration. Today the random choice fell on TIM3 with internal clocking. The <em>Delay<\/em> we need should operate with 1 \u00b5s resolution, so using the magic formula we end up with a required clock of 1 MHz. Using another magic formula, with an 84 MHz clock, to supply 1 MHz to TIM3 I need to set the <em>prescaler<\/em> to 83. I\u2019ll set the counting direction to <em>Up, a&nbsp;<\/em><em>CounterPeriod&nbsp;<\/em>to the maximum value, i.e., 65535 (16\u2011bit timer). I\u2019ll leave other settings at defaults. I won\u2019t enable any interrupts or other bells and whistles for the timer. After setting it up, I regenerate the project code.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/TIM3_conf.png\"><img loading=\"lazy\" decoding=\"async\" width=\"641\" height=\"299\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/TIM3_conf.png\" alt=\"\" class=\"wp-image-106\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/TIM3_conf.png 641w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/TIM3_conf-300x140.png 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/TIM3_conf-24x11.png 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/TIM3_conf-36x17.png 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/TIM3_conf-160x75.png 160w\" sizes=\"auto, (max-width: 641px) 100vw, 641px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p><\/p>\n\n\n\n<p>For clarity I wrote the <em>delay<\/em> code in separate files \u2013&nbsp;<em>delays.c<\/em> and <em>delays.h.&nbsp;<\/em><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">void Delay_us(uint16_t us)\n{\n  htim3.Instance-&amp;gt;CNT = 0;\n  while(htim3.Instance-&amp;gt;CNT &amp;lt;= us);\n}<\/pre>\n\n\n\n<p>After setting the delay between sending bytes to 120 \u00b5s, a problem appeared in the form of cutting off the beginning of the frame. The issue lies in processing the previously written <em>cls<\/em> and <em>locate<\/em> commands. By shortening the data transfer I also had to extend the wait after commands, as their execution takes a bit longer than accepting data. I tested various numbers of microseconds, but quickly approached a value of 1 ms.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/\n\/\/ Write byte to LCD\n\/\/\nvoid LCD_WriteByte(uint8_t data)\n{\n\tSET_LCD_E;\n\tLCD_SetDataPort(data &amp;gt;&amp;gt; 4);\n\tRESET_LCD_E;\n\n\tSET_LCD_E;\n\tLCD_SetDataPort(data);\n\tRESET_LCD_E;\n\n\t\/\/ HAL_Delay(1);\n\tDelay_us(120); \/\/&amp;lt;&amp;lt;--- wait for data processing\n}\n\n\/\/\n\/\/ Write command to LCD\n\/\/\nvoid LCD_WriteCmd(uint8_t cmd)\n{\n\tRESET_LCD_RS;\n\tLCD_WriteByte(cmd);\n\tDelay_us(1000);\/\/&amp;lt;&amp;lt;--- wait for command processing\n}<\/pre>\n\n\n\n<p>Result? It\u2019s definitely better. You can\u2019t see \u201cwriting\u201d across the screen, so it\u2019s acceptable. Execution time? 7.14 ms, which means we can squeeze out about 140 Hz max. Success!<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/4-bit_bez_RW_TIM_Delay_us.png\"><img loading=\"lazy\" decoding=\"async\" width=\"960\" height=\"261\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/4-bit_bez_RW_TIM_Delay_us.png\" alt=\"\" class=\"wp-image-125\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/4-bit_bez_RW_TIM_Delay_us.png 960w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/4-bit_bez_RW_TIM_Delay_us-300x82.png 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/4-bit_bez_RW_TIM_Delay_us-768x209.png 768w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/4-bit_bez_RW_TIM_Delay_us-24x7.png 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/4-bit_bez_RW_TIM_Delay_us-36x10.png 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2018\/07\/4-bit_bez_RW_TIM_Delay_us-160x44.png 160w\" sizes=\"auto, (max-width: 960px) 100vw, 960px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p><\/p>\n\n\n\n<p>In the next post I\u2019ll handle the busy flag. I\u2019ll see how much further I can shorten the frame transmission \ud83d\ude09<\/p>\n\n\n\n<p>The second part of the post is <a href=\"http:\/\/msalamon.pl\/wyswietlacz-lcd-16x2-na-stm32-hal-cz-2\/\">&gt;&gt;here&lt;&lt;<\/a>.<\/p>\n\n\n\n<p>If you like the display, you can buy it in various versions <a href=\"https:\/\/sklep.msalamon.pl\/?utm_source=blog&amp;utm_medium=article&amp;utm_campaign=lcd16x2&amp;utm_content=Text\">in my store<\/a>.<\/p>\n\n\n\n<p>The complete code from this series of posts is on my GitHub: <a href=\"https:\/\/github.com\/lamik\/HD44780_STM32_HAL\" target=\"_blank\" rel=\"noopener\">link<\/a><\/p>\n\n\n\n<p>To end this post, I encourage discussion in the comments about handling the LCD on STM32. Do you think I made a mistake somewhere? Do you have an interesting idea for what can be improved? Share it in a comment!&nbsp;Remember that the discussion should be courteous and in accordance with the rules of the Polish language.<\/p>\n\n\n<div class=\"kk-star-ratings kksr-auto kksr-align-left kksr-valign-bottom\"\n    data-payload='{&quot;align&quot;:&quot;left&quot;,&quot;id&quot;:&quot;4363&quot;,&quot;slug&quot;:&quot;default&quot;,&quot;valign&quot;:&quot;bottom&quot;,&quot;ignore&quot;:&quot;&quot;,&quot;reference&quot;:&quot;auto&quot;,&quot;class&quot;:&quot;&quot;,&quot;count&quot;:&quot;0&quot;,&quot;legendonly&quot;:&quot;&quot;,&quot;readonly&quot;:&quot;&quot;,&quot;score&quot;:&quot;0&quot;,&quot;starsonly&quot;:&quot;&quot;,&quot;best&quot;:&quot;5&quot;,&quot;gap&quot;:&quot;0&quot;,&quot;greet&quot;:&quot;&quot;,&quot;legend&quot;:&quot;0\\\/5 - (0 votes)&quot;,&quot;size&quot;:&quot;24&quot;,&quot;title&quot;:&quot;16\u00d72 LCD Display with STM32 + HAL, Part 1&quot;,&quot;width&quot;:&quot;0&quot;,&quot;_legend&quot;:&quot;{score}\\\/{best} - ({count} {votes})&quot;,&quot;font_factor&quot;:&quot;1.25&quot;}'>\n            \n<div class=\"kksr-stars\">\n    \n<div class=\"kksr-stars-inactive\">\n            <div class=\"kksr-star\" data-star=\"1\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"2\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"3\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"4\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"5\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n    <\/div>\n    \n<div class=\"kksr-stars-active\" style=\"width: 0px;\">\n            <div class=\"kksr-star\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n    <\/div>\n<\/div>\n                \n\n<div class=\"kksr-legend\" style=\"font-size: 19.2px;\">\n            <span class=\"kksr-muted\"><\/span>\n    <\/div>\n    <\/div>\n","protected":false},"excerpt":{"rendered":"<p>A 16\u00d72 character display is probably the most popular form of communication between the microcontroller world and the human world. I decided to make a mini series of three posts that will explain the differences between ways of controlling a 16\u00d72 LCD on STM32. You usually encounter just one method [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":2931,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","_links_to":"","_links_to_target":""},"categories":[160],"tags":[175,176,174,177],"class_list":["post-4363","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-stm32","tag-electronics","tag-programming","tag-stm32","tag-stm32cubemx"],"_links":{"self":[{"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/posts\/4363","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/comments?post=4363"}],"version-history":[{"count":3,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/posts\/4363\/revisions"}],"predecessor-version":[{"id":4473,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/posts\/4363\/revisions\/4473"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/media\/2931"}],"wp:attachment":[{"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/media?parent=4363"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/categories?post=4363"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/tags?post=4363"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}