{"id":674,"date":"2022-01-03T04:26:10","date_gmt":"2022-01-03T04:26:10","guid":{"rendered":"https:\/\/blog.embeddedexpert.io\/?p=674"},"modified":"2022-01-03T04:26:13","modified_gmt":"2022-01-03T04:26:13","slug":"working-with-stm32-and-display-nokia-5110-graphic-lcd","status":"publish","type":"post","link":"https:\/\/blog.embeddedexpert.io\/?p=674","title":{"rendered":"Working with STM32 and display: Nokia 5110 Graphic LCD"},"content":{"rendered":"\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img decoding=\"async\" src=\"https:\/\/www.electronics-lab.com\/wp-content\/uploads\/2019\/05\/nokia-5110-lcd-500x500.jpg\" alt=\"\" \/><\/figure><\/div>\n\n\n\n<p>In this guide, we shall interface Nokia 5110 graphic LCD with STM32. <\/p>\n\n\n\n<p>In this guide, we will cover the following :<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Nokia 5110 graphic LCD<\/li><li>LCD connection with STM32<\/li><li>Code<\/li><li>Demo<\/li><\/ul>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">1.1 Nokia 5110 Graphic LCD:<\/h2>\n\n\n\n<p><\/p>\n\n\n\n<p>Remember the days when cell phones were still &#8220;dumb,&#8221; and they had physical keypads and just a tiny monochrome LCD for a display? Now that iPhones, Galaxies, and the like have revolutionized that market, those little LCDs have to find a new purpose in life: adding customized graphical displays to projects!<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Nokia5110 LCD screen is a simple black and white screen but it was the best display for mobile in its time. The usage of the screen was mostly in the Nokia 3310 and 5110. Therefore, the increase of color graphics and smart screens the screen is now the only available in most of the developing projects and small low budget devices. In the LCD, the Liquid crystal method helps to show the output data with a total of 84\u00d748 pixels. The LCD uses the SPI pins to communicate.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">1.2 What is Nokia5510 LCD Display?<\/h2>\n\n\n\n<p>Nokia 5510 LCD display is a graphics screen LCD display and has been used for a lot of applications. Initially, it was designed only for iconic Nokia 5510 cell phone screen but now we can easily use it for different purposes such as for displaying alphanumeric character, draw lines, shapes and even for displaying bitmap images because of its 84*48 monochrome pixels mean 84 columns and 48 rows. All necessary functions of this display are packed in a single small chip which is operated at very low voltages. It is very low cost more precise, more reliable and easy to use LCD display.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">1.3 Nokia5110 Pinout Diagram<\/h2>\n\n\n\n<p>The pin configuration of the LCD is almost SPI but in oneway only. The LCD only uses a one-way communication to operate because it doesn\u2019t have to send any data to the microcontroller. However, it has two modes of data and command modes for operating properly.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><a href=\"https:\/\/microcontrollerslab.com\/wp-content\/uploads\/2020\/01\/Nokia-5110-LCD-Pinout-diagram-details.png\"><img decoding=\"async\" src=\"https:\/\/microcontrollerslab.com\/wp-content\/uploads\/2020\/01\/Nokia-5110-LCD-Pinout-diagram-details.png?ezimgfmt=rs:407x538\/rscb1\/ngcb1\/notWebP\" alt=\"Nokia5110 LCD Pinout diagram details\" class=\"wp-image-14779\" \/><\/a><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">1.3 Nokia5510 Pinout Diagram Details<\/h3>\n\n\n\n<figure class=\"wp-block-table aligncenter is-style-stripes\"><table><tbody><tr><th>PINS<\/th><th>DETAIL<\/th><\/tr><tr><td>Pin6<\/td><td>Power (VCC)<\/td><td>The power pin will power up the LCD with external voltage to activate it.<\/td><\/tr><tr><td>Pin7<\/td><td>Back Light (BL)<\/td><td>The backlight is the internal color of the LCD. It is just turn on by giving the power input to its pin.<\/td><\/tr><tr><td>Pin8<\/td><td>Ground (GND)<\/td><td>The ground is internally common with LED and whole LCD. It helps to make common ground with external power and devices.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">1.4 SPI Communication Pins<\/h3>\n\n\n\n<figure class=\"wp-block-table aligncenter is-style-stripes\"><table><tbody><tr><th>PINS<\/th><th>DETAIL<\/th><\/tr><tr><td>Pin1<\/td><td>Reset<\/td><td>The reset pins are to reset the Nokia5110 display. Here it will help in the programming library to reset it.<\/td><\/tr><tr><td>Pin2<\/td><td>Chip Enable (CE)<\/td><td>The enable pin in SPI helps to select the device in case of multiple devices. Here it will active the LCD with the LOW input signal.<\/td><\/tr><tr><td>Pin3<\/td><td>Data\/Command (DC)<\/td><td>Pin3 helps to switch between the command\/data mode. The HIGH signal is for data and LOW signal for command.<\/td><\/tr><tr><td>Pin4<\/td><td>Serial IN (DIN)<\/td><td>The \u201cserial in\u201d pin will send the data from the microcontroller\/Arduino to the LCD Nokia5110.<\/td><\/tr><tr><td>Pin5<\/td><td>Clock (CLK)<\/td><td>The LCD and microcontroller will require a common clock to operate because of their SPI communication. CLK pin will help to make it.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">1.5 Nokia5110 Features<\/h2>\n\n\n\n<ul class=\"wp-block-list\"><li>The LCD is of 84\u00d748 pixels combination, which are useable with any microcontroller.<\/li><li>The SPI communication helps to communicate with LCD, which is common in every microcontroller.<\/li><li>It is available in multiple backlights.<\/li><li>The PCD8544 LCD driver helps to drive it, which is already present on it.<\/li><li>Bitmaps images are viewable on the Nokia5110.<\/li><\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">1.6 Nokia5110 LCD Applications<\/h2>\n\n\n\n<ul class=\"wp-block-list\"><li>Most of the pocket games use the LCD, like snake games, etc.<\/li><li>Mobile phones have a wide use of LCD.<\/li><li>The LCD is still in most of the industrial and commercial applications.<\/li><\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">1.7 Nokia5110 LCD Constructions<\/h2>\n\n\n\n<p>The Nokia5110 LCD uses a simple liquid crystal method for each pixel to show the data. In the liquid crystal, the three layers help to make a single pixel. The first layer is the glass, second is the polarized sheet and the third one is the crystal molecules. The light passes from one glass towards the other glass but it has to move from two polarized sheets. The polarized sheets are at different angles. So, to pass the light the molecules need to change their positions so the light gets a change in angle according to the second sheet with the help of modules. If light passes from it, then it is viewable by the user but in case of deflection, the LCD will show a dark pixel. However, the liquid crystals always use a light absorption method to show the image.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">LCD Driver<\/h3>\n\n\n\n<p>The Nokia5110 LCD uses SPI communication to operate. It is due to the driver attached to it. The data from the controllers pass to the driver which store in the buffer and also show on the LCD until it is in the buffer. The new incoming data will able to replace the previous one. The driver only takes the SPI input signal and uses the rest of the pin to operate the LCD. The driver is PCD8544, which is only for 48\u00d784 pixels LCD. Its functionality is viewable by the following block diagram:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><a href=\"https:\/\/microcontrollerslab.com\/wp-content\/uploads\/2020\/01\/Nokia-5110-LCD-block-diagram.png\"><img decoding=\"async\" src=\"https:\/\/microcontrollerslab.com\/wp-content\/uploads\/2020\/01\/Nokia-5110-LCD-block-diagram.png?ezimgfmt=rs:618x517\/rscb1\/ngcb1\/notWebP\" alt=\"block diagram\" class=\"wp-image-14778\" \/><\/a><\/figure><\/div>\n\n\n\n<p>The driver has its 504bytes GDD RAM. However, Its memory comes with 6 blanks and each blank has 84 segments and each segment can store the 8 bit of data. Therefore, the whole LCD data can store in the GDD RAM of the LCD screen.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Output Pins<\/h3>\n\n\n\n<p>The input pins of the driver are the same as the LCD pins which are already in the pin configuration section.&nbsp; The output pins of the driver are responsible for every function on the LCD screen. However, four types of output pins exist in the driver. The first part is the Row and Column pins. The row pins are 48 and columns are 84 in numbers. Therefore, all these pins connect to each pixel of the LCD and they are responsible for each output by them. The next part is the power part. The VSS, VDD, and VLCD help to power up the LCD and itself. The third part is the test pins that connect with the ground. In the Nokia5110 LCD, they have no use.<\/p>\n\n\n\n<p>The last part is the oscillator pin, to attach an external oscillator. There will be remaining dummy pins that have no use in the LCD screen. In this Nokia5110 LCD, every kind of symbol is drawable. Even images can also show on the screen but first, it requires to convert into the bitmap format.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Working Principle of Nokia 5510 LCD Display<\/strong><\/h3>\n\n\n\n<p>The word LCD stands for liquid crystal display. Its name describes that every LCD display consists of liquid crystal. When an electric current is passed through these crystals then the magnetic field is produced. This magnetic field-aligned the molecules of liquid crystal forcefully, then when they are aligned precisely then they allow the light to pass through these crystals.<\/p>\n\n\n\n<p>The working phenomena of every LCD display are almost the same. But the voltages which are required to produce the magnetic field are different. On the biases of these voltages, the LCD display shows data which is coming from any type of controller. Two types of data have come from the controller\u2019s fist one is word data and second one graphic data. Each data produces a different magnetic field and the LCD display shows this data according to its magnetic field.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">2. Connection with STM32:<\/h2>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"590\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/01\/Screen-Shot-2022-01-03-at-6.55.55-AM-1024x590.png\" alt=\"\" class=\"wp-image-675\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/01\/Screen-Shot-2022-01-03-at-6.55.55-AM-1024x590.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/01\/Screen-Shot-2022-01-03-at-6.55.55-AM-300x173.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/01\/Screen-Shot-2022-01-03-at-6.55.55-AM-768x443.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/01\/Screen-Shot-2022-01-03-at-6.55.55-AM-1536x885.png 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/01\/Screen-Shot-2022-01-03-at-6.55.55-AM-2048x1181.png 2048w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/01\/Screen-Shot-2022-01-03-at-6.55.55-AM-1150x663.png 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/01\/Screen-Shot-2022-01-03-at-6.55.55-AM-750x432.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/01\/Screen-Shot-2022-01-03-at-6.55.55-AM-400x231.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/01\/Screen-Shot-2022-01-03-at-6.55.55-AM-250x144.png 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">3. Coding:<\/h2>\n\n\n\n<p>We start off by creating new source and header file with name of nokia5110<\/p>\n\n\n\n<p>In the header 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;}\">#ifndef __nokia5110_H\n#define __nokia5110_H \n#include &lt;stdbool.h&gt;\n#include &quot;stm32f4xx.h&quot;                  \/\/ Device header\n\/* PCD8544-specific defines: *\/\n#define LCD_COMMAND  GPIOA-&gt;BSRR|=GPIO_BSRR_BR0\n#define LCD_DATA     GPIOA-&gt;BSRR|=GPIO_BSRR_BS0\n\n#define CS0 GPIOA-&gt;BSRR|=GPIO_BSRR_BR1\n#define CS1 GPIOA-&gt;BSRR|=GPIO_BSRR_BS1\n\n#define RST0 GPIOA-&gt;BSRR|=GPIO_BSRR_BR4\n#define RST1 GPIOA-&gt;BSRR|=GPIO_BSRR_BS4\n\n\/* 84x48 LCD Defines: *\/\n#define LCD_WIDTH   84 \/\/ Note: x-coordinates go wide\n#define LCD_HEIGHT  48 \/\/ Note: y-coordinates go high\n#define WHITE       0  \/\/ For drawing pixels. A 0 draws white.\n#define BLACK       1  \/\/ A 1 draws black.\n\nstatic const unsigned char ASCII[][5] = {\n  \/\/ First 32 characters (0x00-0x19) are ignored. These are\n  \/\/ non-displayable, control characters.\n   {0x00, 0x00, 0x00, 0x00, 0x00} \/\/ 0x20\n  ,{0x00, 0x00, 0x5f, 0x00, 0x00} \/\/ 0x21 !\n  ,{0x00, 0x07, 0x00, 0x07, 0x00} \/\/ 0x22 &quot;\n  ,{0x14, 0x7f, 0x14, 0x7f, 0x14} \/\/ 0x23 #\n  ,{0x24, 0x2a, 0x7f, 0x2a, 0x12} \/\/ 0x24 $\n  ,{0x23, 0x13, 0x08, 0x64, 0x62} \/\/ 0x25 %\n  ,{0x36, 0x49, 0x55, 0x22, 0x50} \/\/ 0x26 &amp;\n  ,{0x00, 0x05, 0x03, 0x00, 0x00} \/\/ 0x27 '\n  ,{0x00, 0x1c, 0x22, 0x41, 0x00} \/\/ 0x28 (\n  ,{0x00, 0x41, 0x22, 0x1c, 0x00} \/\/ 0x29 )\n  ,{0x14, 0x08, 0x3e, 0x08, 0x14} \/\/ 0x2a *\n  ,{0x08, 0x08, 0x3e, 0x08, 0x08} \/\/ 0x2b +\n  ,{0x00, 0x50, 0x30, 0x00, 0x00} \/\/ 0x2c ,\n  ,{0x08, 0x08, 0x08, 0x08, 0x08} \/\/ 0x2d -\n  ,{0x00, 0x60, 0x60, 0x00, 0x00} \/\/ 0x2e .\n  ,{0x20, 0x10, 0x08, 0x04, 0x02} \/\/ 0x2f \/\n  ,{0x3e, 0x51, 0x49, 0x45, 0x3e} \/\/ 0x30 0\n  ,{0x00, 0x42, 0x7f, 0x40, 0x00} \/\/ 0x31 1\n  ,{0x42, 0x61, 0x51, 0x49, 0x46} \/\/ 0x32 2\n  ,{0x21, 0x41, 0x45, 0x4b, 0x31} \/\/ 0x33 3\n  ,{0x18, 0x14, 0x12, 0x7f, 0x10} \/\/ 0x34 4\n  ,{0x27, 0x45, 0x45, 0x45, 0x39} \/\/ 0x35 5\n  ,{0x3c, 0x4a, 0x49, 0x49, 0x30} \/\/ 0x36 6\n  ,{0x01, 0x71, 0x09, 0x05, 0x03} \/\/ 0x37 7\n  ,{0x36, 0x49, 0x49, 0x49, 0x36} \/\/ 0x38 8\n  ,{0x06, 0x49, 0x49, 0x29, 0x1e} \/\/ 0x39 9\n  ,{0x00, 0x36, 0x36, 0x00, 0x00} \/\/ 0x3a :\n  ,{0x00, 0x56, 0x36, 0x00, 0x00} \/\/ 0x3b ;\n  ,{0x08, 0x14, 0x22, 0x41, 0x00} \/\/ 0x3c &lt;\n  ,{0x14, 0x14, 0x14, 0x14, 0x14} \/\/ 0x3d =\n  ,{0x00, 0x41, 0x22, 0x14, 0x08} \/\/ 0x3e &gt;\n  ,{0x02, 0x01, 0x51, 0x09, 0x06} \/\/ 0x3f ?\n  ,{0x32, 0x49, 0x79, 0x41, 0x3e} \/\/ 0x40 @\n  ,{0x7e, 0x11, 0x11, 0x11, 0x7e} \/\/ 0x41 A\n  ,{0x7f, 0x49, 0x49, 0x49, 0x36} \/\/ 0x42 B\n  ,{0x3e, 0x41, 0x41, 0x41, 0x22} \/\/ 0x43 C\n  ,{0x7f, 0x41, 0x41, 0x22, 0x1c} \/\/ 0x44 D\n  ,{0x7f, 0x49, 0x49, 0x49, 0x41} \/\/ 0x45 E\n  ,{0x7f, 0x09, 0x09, 0x09, 0x01} \/\/ 0x46 F\n  ,{0x3e, 0x41, 0x49, 0x49, 0x7a} \/\/ 0x47 G\n  ,{0x7f, 0x08, 0x08, 0x08, 0x7f} \/\/ 0x48 H\n  ,{0x00, 0x41, 0x7f, 0x41, 0x00} \/\/ 0x49 I\n  ,{0x20, 0x40, 0x41, 0x3f, 0x01} \/\/ 0x4a J\n  ,{0x7f, 0x08, 0x14, 0x22, 0x41} \/\/ 0x4b K\n  ,{0x7f, 0x40, 0x40, 0x40, 0x40} \/\/ 0x4c L\n  ,{0x7f, 0x02, 0x0c, 0x02, 0x7f} \/\/ 0x4d M\n  ,{0x7f, 0x04, 0x08, 0x10, 0x7f} \/\/ 0x4e N\n  ,{0x3e, 0x41, 0x41, 0x41, 0x3e} \/\/ 0x4f O\n  ,{0x7f, 0x09, 0x09, 0x09, 0x06} \/\/ 0x50 P\n  ,{0x3e, 0x41, 0x51, 0x21, 0x5e} \/\/ 0x51 Q\n  ,{0x7f, 0x09, 0x19, 0x29, 0x46} \/\/ 0x52 R\n  ,{0x46, 0x49, 0x49, 0x49, 0x31} \/\/ 0x53 S\n  ,{0x01, 0x01, 0x7f, 0x01, 0x01} \/\/ 0x54 T\n  ,{0x3f, 0x40, 0x40, 0x40, 0x3f} \/\/ 0x55 U\n  ,{0x1f, 0x20, 0x40, 0x20, 0x1f} \/\/ 0x56 V\n  ,{0x3f, 0x40, 0x38, 0x40, 0x3f} \/\/ 0x57 W\n  ,{0x63, 0x14, 0x08, 0x14, 0x63} \/\/ 0x58 X\n  ,{0x07, 0x08, 0x70, 0x08, 0x07} \/\/ 0x59 Y\n  ,{0x61, 0x51, 0x49, 0x45, 0x43} \/\/ 0x5a Z\n  ,{0x00, 0x7f, 0x41, 0x41, 0x00} \/\/ 0x5b [\n  ,{0x02, 0x04, 0x08, 0x10, 0x20} \/\/ 0x5c \\ (keep this to escape the backslash)\n  ,{0x00, 0x41, 0x41, 0x7f, 0x00} \/\/ 0x5d ]\n  ,{0x04, 0x02, 0x01, 0x02, 0x04} \/\/ 0x5e ^\n  ,{0x40, 0x40, 0x40, 0x40, 0x40} \/\/ 0x5f _\n  ,{0x00, 0x01, 0x02, 0x04, 0x00} \/\/ 0x60 `\n  ,{0x20, 0x54, 0x54, 0x54, 0x78} \/\/ 0x61 a\n  ,{0x7f, 0x48, 0x44, 0x44, 0x38} \/\/ 0x62 b\n  ,{0x38, 0x44, 0x44, 0x44, 0x20} \/\/ 0x63 c\n  ,{0x38, 0x44, 0x44, 0x48, 0x7f} \/\/ 0x64 d\n  ,{0x38, 0x54, 0x54, 0x54, 0x18} \/\/ 0x65 e\n  ,{0x08, 0x7e, 0x09, 0x01, 0x02} \/\/ 0x66 f\n  ,{0x0c, 0x52, 0x52, 0x52, 0x3e} \/\/ 0x67 g\n  ,{0x7f, 0x08, 0x04, 0x04, 0x78} \/\/ 0x68 h\n  ,{0x00, 0x44, 0x7d, 0x40, 0x00} \/\/ 0x69 i\n  ,{0x20, 0x40, 0x44, 0x3d, 0x00} \/\/ 0x6a j\n  ,{0x7f, 0x10, 0x28, 0x44, 0x00} \/\/ 0x6b k\n  ,{0x00, 0x41, 0x7f, 0x40, 0x00} \/\/ 0x6c l\n  ,{0x7c, 0x04, 0x18, 0x04, 0x78} \/\/ 0x6d m\n  ,{0x7c, 0x08, 0x04, 0x04, 0x78} \/\/ 0x6e n\n  ,{0x38, 0x44, 0x44, 0x44, 0x38} \/\/ 0x6f o\n  ,{0x7c, 0x14, 0x14, 0x14, 0x08} \/\/ 0x70 p\n  ,{0x08, 0x14, 0x14, 0x18, 0x7c} \/\/ 0x71 q\n  ,{0x7c, 0x08, 0x04, 0x04, 0x08} \/\/ 0x72 r\n  ,{0x48, 0x54, 0x54, 0x54, 0x20} \/\/ 0x73 s\n  ,{0x04, 0x3f, 0x44, 0x40, 0x20} \/\/ 0x74 t\n  ,{0x3c, 0x40, 0x40, 0x20, 0x7c} \/\/ 0x75 u\n  ,{0x1c, 0x20, 0x40, 0x20, 0x1c} \/\/ 0x76 v\n  ,{0x3c, 0x40, 0x30, 0x40, 0x3c} \/\/ 0x77 w\n  ,{0x44, 0x28, 0x10, 0x28, 0x44} \/\/ 0x78 x\n  ,{0x0c, 0x50, 0x50, 0x50, 0x3c} \/\/ 0x79 y\n  ,{0x44, 0x64, 0x54, 0x4c, 0x44} \/\/ 0x7a z\n  ,{0x00, 0x08, 0x36, 0x41, 0x00} \/\/ 0x7b {\n  ,{0x00, 0x00, 0x7f, 0x00, 0x00} \/\/ 0x7c |\n  ,{0x00, 0x41, 0x36, 0x08, 0x00} \/\/ 0x7d }\n  ,{0x10, 0x08, 0x08, 0x10, 0x08} \/\/ 0x7e ~\n  ,{0x78, 0x46, 0x41, 0x46, 0x78} \/\/ 0x7f DEL\n};\n\n\n\n\nvoid delay(int ms);\nvoid setLine(int x0, int y0, int x1, int y1, bool bw);\nvoid setRect(int x0, int y0, int x1, int y1, bool fill, bool bw);\nvoid setCircle (int x0, int y0, int radius, bool bw, int lineThickness);\nvoid setStr(char * dString, int x, int y, bool bw);\nvoid SetBitMap(const char * bitArray);\nvoid clearDisplay(bool bw);\nvoid gotoXY(int x, int y);\nvoid updateDisplay();\nvoid setContrast(int contrast);\nvoid invertDisplay();\nvoid lcdBegin(void);\n#endif <\/pre><\/div>\n\n\n\n<p>for the source 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;nokia5110.h&quot;\nvoid delay(int ms);\n\nunsigned char displayMap_5110[LCD_WIDTH * LCD_HEIGHT \/ 8] = {\n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \/\/ (0,0)-&gt;(11,7) ~ These 12 bytes cover an 8x12 block in the left corner of the display\n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \/\/ (12,0)-&gt;(23,7)\n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, \/\/ (24,0)-&gt;(35,7)\n  0xF0, 0xF8, 0xFC, 0xFC, 0xFE, 0xFE, 0xFE, 0xFE, 0x1E, 0x0E, 0x02, 0x00, \/\/ (36,0)-&gt;(47,7)\n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \/\/ (48,0)-&gt;(59,7)\n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \/\/ (60,0)-&gt;(71,7)\n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \/\/ (72,0)-&gt;(83,7)\n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \/\/ (0,8)-&gt;(11,15)\n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \/\/ (12,8)-&gt;(23,15)\n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, \/\/ (24,8)-&gt;(35,15)\n  0x0F, 0x1F, 0x3F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFC, 0xF8, \/\/ (36,8)-&gt;(47,15)\n  0xF8, 0xF0, 0xF8, 0xFE, 0xFE, 0xFC, 0xF8, 0xE0, 0x00, 0x00, 0x00, 0x00, \/\/ (48,8)-&gt;(59,15)\n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \/\/ (60,8)-&gt;(71,15)\n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \/\/ (72,8)-&gt;(83,15)\n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \/\/ (0,16)-&gt;(11,23)\n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \/\/ (12,16)-&gt;(23,23)\n  0x00, 0x00, 0xF8, 0xFC, 0xFE, 0xFE, 0xFF, 0xFF, 0xF3, 0xE0, 0xE0, 0xC0, \/\/ (24,16)-&gt;(35,23)\n  0xC0, 0xC0, 0xE0, 0xE0, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \/\/ (36,16)-&gt;(47,23)\n  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3E, 0x00, 0x00, 0x00, \/\/ (48,16)-&gt;(59,23)\n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \/\/ (60,16)-&gt;(71,23)\n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \/\/ (72,16)-&gt;(83,23)\n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \/\/ (0,24)-&gt;(11,31)\n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \/\/ (12,24)-&gt;(23,31)\n  0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \/\/ (24,24)-&gt;(35,31)\n  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \/\/ (36,24)-&gt;(47,31)\n  0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x1F, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, \/\/ (48,24)-&gt;(59,31)\n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \/\/ (60,24)-&gt;(71,31)\n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \/\/ (72,24)-&gt;(83,31)\n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \/\/ (0,32)-&gt;(11,39)\n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \/\/ (12,32)-&gt;(23,39)\n  0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x1F, \/\/ (24,32)-&gt;(35,39)\n  0x0F, 0x0F, 0x0F, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x03, 0x03, \/\/ (36,32)-&gt;(47,39)\n  0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \/\/ (48,32)-&gt;(59,39)\n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \/\/ (60,32)-&gt;(71,39)\n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \/\/ (72,32)-&gt;(83,39)\n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \/\/ (0,40)-&gt;(11,47)\n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \/\/ (12,40)-&gt;(23,47)\n  0x00, 0x00, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, \/\/ (24,40)-&gt;(35,47)\n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \/\/ (36,40)-&gt;(47,47)\n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \/\/ (48,40)-&gt;(59,47)\n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \/\/ (60,40)-&gt;(71,47)\n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \/\/ (72,40)-&gt;(83,47) !!! The bottom right pixel!\n};\n\n\n\n\n\n\n\n\nvoid spi_init(void){\nRCC-&gt;AHB1ENR|=RCC_AHB1ENR_GPIOAEN; \/\/enable clock forn gpio a\nRCC-&gt;APB2ENR|=RCC_APB2ENR_SPI1EN; \/\/enable clock for spi1\n\/\/GPIOA-&gt;MODER=0;\nGPIOA-&gt;MODER|=0xA900;\nGPIOA-&gt;AFR[0]|=0x55500000;\nSPI1-&gt;CR1|=0x304;\nSPI1-&gt;CR2=0;\nSPI1-&gt;CR1|=SPI_CR1_SPE;\n}\n\nvoid GPIO_init(void)\n{\nRCC-&gt;AHB1ENR|=RCC_AHB1ENR_GPIOAEN;\nGPIOA-&gt;MODER|=GPIO_MODER_MODE0_0|GPIO_MODER_MODE1_0|GPIO_MODER_MODE4_0;\n}\n\n\nvoid spi_write(unsigned char c){\n\twhile(!(SPI1-&gt;SR&amp;SPI_SR_TXE)){;} \/\/ wait to transmision buffer to be emplty\n\tSPI1-&gt;DR= c;\n\twhile(!(SPI1-&gt;SR&amp;SPI_SR_BSY)){;}\t\n}\n\nvoid LCDcommand(unsigned char data)\n{\nCS0;\nLCD_COMMAND;\nspi_write(data);\nCS1;\n\t\n}\n\nvoid LCDdata(unsigned char data)\n{\nCS0;\nLCD_DATA;\nspi_write(data);\nCS1;\n}\n\n\n\n\/\/ This function sets a pixel on displayMap to your preferred\n\/\/ color. 1=Black, 0= white.\nvoid setPixel1(int x, int y, bool bw)\n{\n  \/\/ First, double check that the coordinate is in range.\n  if ((x &gt;= 0) &amp;&amp; (x &lt; LCD_WIDTH) &amp;&amp; (y &gt;= 0) &amp;&amp; (y &lt; LCD_HEIGHT))\n  {\n    int shift = y % 8;\n\n    if (bw) \/\/ If black, set the bit.\n      displayMap_5110[x + (y\/8)*LCD_WIDTH] |= 1&lt;&lt;shift;\n    else   \/\/ If white clear the bit.\n      displayMap_5110[x + (y\/8)*LCD_WIDTH] &amp;= ~(1&lt;&lt;shift);\n  }\n}\n\n\/\/ Because I keep forgetting to put bw variable in when setting...\nvoid setPixel(int x, int y)\n{\n  setPixel1(x, y, BLACK); \/\/ Call setPixel with bw set to Black\n}\n\nvoid clearPixel(int x, int y)\n{\n  setPixel1(x, y, WHITE); \/\/ call setPixel with bw set to white\n}\n\n\/\/ setLine draws a line from x0,y0 to x1,y1 with the set color.\n\/\/ This function was grabbed from the SparkFun ColorLCDShield\n\/\/ library.\nvoid setLine(int x0, int y0, int x1, int y1, bool bw)\n{\n  int dy = y1 - y0; \/\/ Difference between y0 and y1\n  int dx = x1 - x0; \/\/ Difference between x0 and x1\n  int stepx, stepy;\n\n  if (dy &lt; 0)\n  {\n    dy = -dy;\n    stepy = -1;\n  }\n  else\n    stepy = 1;\n\n  if (dx &lt; 0)\n  {\n    dx = -dx;\n    stepx = -1;\n  }\n  else\n    stepx = 1;\n\n  dy &lt;&lt;= 1; \/\/ dy is now 2*dy\n  dx &lt;&lt;= 1; \/\/ dx is now 2*dx\n  setPixel1(x0, y0, bw); \/\/ Draw the first pixel.\n\n  if (dx &gt; dy)\n  {\n    int fraction = dy - (dx &gt;&gt; 1);\n    while (x0 != x1)\n    {\n      if (fraction &gt;= 0)\n      {\n        y0 += stepy;\n        fraction -= dx;\n      }\n      x0 += stepx;\n      fraction += dy;\n      setPixel1(x0, y0, bw);\n    }\n  }\n  else\n  {\n    int fraction = dx - (dy &gt;&gt; 1);\n    while (y0 != y1)\n    {\n      if (fraction &gt;= 0)\n      {\n        x0 += stepx;\n        fraction -= dy;\n      }\n      y0 += stepy;\n      fraction += dx;\n      setPixel1(x0, y0, bw);\n    }\n  }\n}\n\n\/\/ setRect will draw a rectangle from x0,y0 top-left corner to\n\/\/ a x1,y1 bottom-right corner. Can be filled with the fill\n\/\/ parameter, and colored with bw.\n\/\/ This function was grabbed from the SparkFun ColorLCDShield\n\/\/ library.\nvoid setRect(int x0, int y0, int x1, int y1, bool fill, bool bw)\n{\n  \/\/ check if the rectangle is to be filled\n  if (fill == 1)\n  {\n    int xDiff;\n\n    if(x0 &gt; x1)\n      xDiff = x0 - x1; \/\/Find the difference between the x vars\n    else\n      xDiff = x1 - x0;\n\n    while(xDiff &gt; 0)\n    {\n      setLine(x0, y0, x0, y1, bw);\n\n      if(x0 &gt; x1)\n        x0--;\n      else\n        x0++;\n\n      xDiff--;\n    }\n  }\n  else\n  {\n    \/\/ best way to draw an unfilled rectangle is to draw four lines\n    setLine(x0, y0, x1, y0, bw);\n    setLine(x0, y1, x1, y1, bw);\n    setLine(x0, y0, x0, y1, bw);\n    setLine(x1, y0, x1, y1, bw);\n  }\n}\n\n\/\/ setCircle draws a circle centered around x0,y0 with a defined\n\/\/ radius. The circle can be black or white. And have a line\n\/\/ thickness ranging from 1 to the radius of the circle.\n\/\/ This function was grabbed from the SparkFun ColorLCDShield\n\/\/ library.\nvoid setCircle (int x0, int y0, int radius, bool bw, int lineThickness)\n{\n  for(int r = 0; r &lt; lineThickness; r++)\n  {\n    int f = 1 - radius;\n    int ddF_x = 0;\n    int ddF_y = -2 * radius;\n    int x = 0;\n    int y = radius;\n\n    setPixel1(x0, y0 + radius, bw);\n    setPixel1(x0, y0 - radius, bw);\n    setPixel1(x0 + radius, y0, bw);\n    setPixel1(x0 - radius, y0, bw);\n\n    while(x &lt; y)\n    {\n      if(f &gt;= 0)\n      {\n        y--;\n        ddF_y += 2;\n        f += ddF_y;\n      }\n      x++;\n      ddF_x += 2;\n      f += ddF_x + 1;\n\n      setPixel1(x0 + x, y0 + y, bw);\n      setPixel1(x0 - x, y0 + y, bw);\n      setPixel1(x0 + x, y0 - y, bw);\n      setPixel1(x0 - x, y0 - y, bw);\n      setPixel1(x0 + y, y0 + x, bw);\n      setPixel1(x0 - y, y0 + x, bw);\n      setPixel1(x0 + y, y0 - x, bw);\n      setPixel1(x0 - y, y0 - x, bw);\n    }\n    radius--;\n  }\n}\n\n\/\/ This function will draw a char (defined in the ASCII table\n\/\/ near the beginning of this sketch) at a defined x and y).\n\/\/ The color can be either black (1) or white (0).\nvoid setChar(char character, int x, int y, bool bw)\n{\n  int column; \/\/ temp byte to store character's column bitmap\n  for (int i=0; i&lt;5; i++) \/\/ 5 columns (x) per character\n  {\n    column = ASCII[character - 0x20][i];\n    for (int j=0; j&lt;8; j++) \/\/ 8 rows (y) per character\n    {\n      if (column &amp; (0x01 &lt;&lt; j)) \/\/ test bits to set pixels\n        setPixel1(x+i, y+j, bw);\n      else\n        setPixel1(x+i, y+j, !bw);\n    }\n  }\n}\n\n\/\/ setStr draws a string of characters, calling setChar with\n\/\/ progressive coordinates until it's done.\n\/\/ This function was grabbed from the SparkFun ColorLCDShield\n\/\/ library.\nvoid setStr(char * dString, int x, int y, bool bw)\n{\n  while (*dString != 0x00) \/\/ loop until null terminator\n  {\n    setChar(*dString++, x, y, bw);\n    x+=5;\n    for (int i=y; i&lt;y+8; i++)\n    {\n      setPixel1(x, i, !bw);\n    }\n    x++;\n    if (x &gt; (LCD_WIDTH - 5)) \/\/ Enables wrap around\n    {\n      x = 0;\n      y += 8;\n    }\n  }\n}\n\n\/\/ This function will draw an array over the screen. (For now) the\n\/\/ array must be the same size as the screen, covering the entirety\n\/\/ of the display.\n\/\/ Also, the array must reside in FLASH and declared with PROGMEM.\nvoid SetBitMap(const char * bitArray)\n{\n  for (int i=0; i&lt;(LCD_WIDTH * LCD_HEIGHT \/ 8); i++)\n  {\n    char c = bitArray[i];\n    displayMap_5110[i] = c;\n  }\n}\n\n\/\/ This function clears the entire display either white (0) or\n\/\/ black (1).\n\/\/ The screen won't actually clear until you call updateDisplay()!\nvoid clearDisplay(bool bw)\n{\n  for (int i=0; i&lt;(LCD_WIDTH * LCD_HEIGHT \/ 8); i++)\n  {\n    if (bw)\n      displayMap_5110[i] = 0xFF;\n    else\n      displayMap_5110[i] = 0;\n  }\n}\n\n\/\/ Helpful function to directly command the LCD to go to a\n\/\/ specific x,y coordinate.\nvoid gotoXY(int x, int y)\n{\n  LCDcommand(0x80 | x);  \/\/ Column.\n  LCDcommand( 0x40 | y);  \/\/ Row.  ?\n}\n\n\/\/ This will actually draw on the display, whatever is currently\n\/\/ in the displayMap array.\nvoid updateDisplay(void)\n{\n  gotoXY(0, 0);\n  for (int i=0; i &lt; (LCD_WIDTH * LCD_HEIGHT \/ 8); i++)\n  {\n    LCDdata( displayMap_5110[i]);\n  }\n}\n\n\/\/ Set contrast can set the LCD Vop to a value between 0 and 127.\n\/\/ 40-60 is usually a pretty good range.\nvoid setContrast(int contrast)\n{\n  LCDcommand(0x21); \/\/Tell LCD that extended commands follow\n  LCDcommand( 0x80 | contrast); \/\/Set LCD Vop (Contrast): Try 0xB1(good @ 3.3V) or 0xBF if your display is too dark\n  LCDcommand(0x20); \/\/Set display mode\n}\n\n\/* There are two ways to do this. Either through direct commands\nto the display, or by swapping each bit in the displayMap array.\nWe'll leave both methods here, comment one or the other out if\nyou please. *\/\nvoid invertDisplay(void)\n{\n  \/* Direct LCD Command option\n  LCDWrite(LCD_COMMAND, 0x20); \/\/Tell LCD that extended commands follow\n  LCDWrite(LCD_COMMAND, 0x08 | 0x05); \/\/Set LCD Vop (Contrast): Try 0xB1(good @ 3.3V) or 0xBF if your display is too dark\n  LCDWrite(LCD_COMMAND, 0x20); \/\/Set display mode  *\/\n\n  \/* Indirect, swap bits in displayMap option: *\/\n  for (int i=0; i &lt; (LCD_WIDTH * LCD_HEIGHT \/ 8); i++)\n  {\n    displayMap_5110[i] = ~displayMap_5110[i] &amp; 0xFF;\n  }\n  updateDisplay();\n}\n\n\/\/This sends the magical commands to the PCD8544\nvoid lcdBegin(void)\n{\n\tGPIO_init();\n\tspi_init();\n\tRST0;\n\tdelay(1000);\n\tRST1;\n\tCS0;\n  LCDcommand( 0x21); \/\/Tell LCD extended commands follow\n\tdelay(10);\n  LCDcommand( 0xB0); \/\/Set LCD Vop (Contrast)\n\tdelay(10);\n  LCDcommand( 0x04); \/\/Set Temp coefficent\n\tdelay(10);\n  LCDcommand( 0x14); \/\/LCD bias mode 1:48 (try 0x13)\n\tdelay(10);\n  \/\/We must send 0x20 before modifying the display control mode\n  LCDcommand( 0x20);\n\tdelay(10);\n  LCDcommand( 0x0C); \/\/Set display control, normal mode.\n\tdelay(10);\n}\n\nvoid delay(int ms)\n{\n\tSysTick-&gt;LOAD=16000-1;\n\tSysTick-&gt;VAL=0;\n\tSysTick-&gt;CTRL=0x5;\n\t\tfor (int i=0;i&lt;ms;i++)\n\t\t{\n\t\t\twhile(!(SysTick-&gt;CTRL &amp;0x10000)){}\n\t\t}\n\tSysTick-&gt;CTRL=0;\n}<\/pre><\/div>\n\n\n\n<p>You may download the project from here:<\/p>\n\n\n\n<div class=\"wp-block-file\"><a href=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/01\/nokia5110.zip\">nokia5110<\/a><a href=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/01\/nokia5110.zip\" class=\"wp-block-file__button\" download>Download<\/a><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">4. Demo:<\/h2>\n\n\n\n<figure class=\"wp-block-video\"><video controls src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/01\/IMG_7615.mp4\"><\/video><\/figure>\n\n\n\n<p>Happy coding \ud83d\ude42 <\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this guide, we shall interface Nokia 5110 graphic LCD with STM32. In this guide, we will cover the following : Nokia 5110 graphic LCD LCD connection with STM32 Code Demo 1.1 Nokia 5110 Graphic LCD: Remember the days when cell phones were still &#8220;dumb,&#8221; and they had physical keypads and just a tiny monochrome [&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-674","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\/674"}],"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=674"}],"version-history":[{"count":1,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/674\/revisions"}],"predecessor-version":[{"id":678,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/674\/revisions\/678"}],"wp:attachment":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=674"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=674"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=674"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}