{"id":150511,"date":"2024-06-11T17:31:18","date_gmt":"2024-06-11T17:31:18","guid":{"rendered":"https:\/\/randomnerdtutorials.com\/?p=150511"},"modified":"2024-08-22T09:42:29","modified_gmt":"2024-08-22T09:42:29","slug":"raspberry-pi-pico-i2c-lcd-display-micropython","status":"publish","type":"post","link":"https:\/\/randomnerdtutorials.com\/raspberry-pi-pico-i2c-lcd-display-micropython\/","title":{"rendered":"Raspberry Pi Pico with I2C LCD Display (MicroPython)"},"content":{"rendered":"\n<p>Learn how to use the I2C LCD (Liquid Crystal Display) with the Raspberry Pi Pico programmed with MicroPython. We&#8217;ll cover how to write static text, scrolling text, and how to display custom icons.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" fetchpriority=\"high\" decoding=\"async\" width=\"1200\" height=\"675\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/Raspberry-Pi-Pico-LCD-Micropython.jpg?resize=1200%2C675&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Raspberry Pi Pico Guide to the I2C LCD Display MicroPython\" class=\"wp-image-150541\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/Raspberry-Pi-Pico-LCD-Micropython.jpg?w=1920&amp;quality=100&amp;strip=all&amp;ssl=1 1920w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/Raspberry-Pi-Pico-LCD-Micropython.jpg?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/Raspberry-Pi-Pico-LCD-Micropython.jpg?resize=1024%2C576&amp;quality=100&amp;strip=all&amp;ssl=1 1024w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/Raspberry-Pi-Pico-LCD-Micropython.jpg?resize=768%2C432&amp;quality=100&amp;strip=all&amp;ssl=1 768w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/Raspberry-Pi-Pico-LCD-Micropython.jpg?resize=1536%2C864&amp;quality=100&amp;strip=all&amp;ssl=1 1536w\" sizes=\"(max-width: 1200px) 100vw, 1200px\" \/><\/figure><\/div>\n\n\n<p class=\"rntbox rntclgreen\"><strong>New to the Raspberry Pi Pico?<\/strong>&nbsp;Read the following guide:&nbsp;<a href=\"https:\/\/randomnerdtutorials.com\/getting-started-raspberry-pi-pico-w\/\">Getting Started with Raspberry Pi Pico (and Pico W)<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Table of Contents<\/h2>\n\n\n\n<p>Throughout this guide, we&#8217;ll cover the following topics:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"#intro-lcd\" title=\"\">Introducing the LCD<\/a><\/li>\n\n\n\n<li><a href=\"#rpi-pico-lcd-wiring\" title=\"\">Wiring the I2C LCD to the Raspberry Pi Pico<\/a><\/li>\n\n\n\n<li><a href=\"#lcd-libraries\" title=\"\">LCD Libraries &#8211; MicroPython<\/a><\/li>\n\n\n\n<li><a href=\"#display-static-text\" title=\"\">Displaying Static Text<\/a><\/li>\n\n\n\n<li><a href=\"#scroll-text\" title=\"\">Displaying Scrolling Text<\/a><\/li>\n\n\n\n<li><a href=\"#display-custom-characters\" title=\"\">Displaying Custom Characters<\/a><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Prerequisites<\/h2>\n\n\n\n<p>Before proceeding, make sure you check the following prerequisites:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">MicroPython Firmware<\/h3>\n\n\n\n<p>To follow this tutorial you need MicroPython firmware installed in your Raspberry Pi Pico board. You also need an IDE to write and upload the code to your board.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter is-resized\"><img decoding=\"async\" width=\"250\" height=\"250\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/02\/micropython-logo.png?resize=150%2C150&amp;quality=100&amp;strip=all&amp;ssl=1\" alt=\"micorpython logo\" class=\"wp-image-148797\" style=\"width:136px;height:auto\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/02\/micropython-logo.png?w=250&amp;quality=100&amp;strip=all&amp;ssl=1 250w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/02\/micropython-logo.png?resize=150%2C150&amp;quality=100&amp;strip=all&amp;ssl=1 150w\" sizes=\"(max-width: 250px) 100vw, 250px\" \/><\/figure><\/div>\n\n\n<p>The recommended MicroPython IDE for the Raspberry Pi Pico is Thonny IDE. Follow the next tutorial to learn how to install Thonny IDE, flash MicroPython firmware, and upload code to the board.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/getting-started-raspberry-pi-pico-w\/#install-thonny-ide\">Programming Raspberry Pi Pico using MicroPython<\/a><\/li>\n<\/ul>\n\n\n\n<p>Alternatively, if you like programming using VS Code, you can start with the following tutorial:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/raspberry-pi-pico-vs-code-micropython\/\">Programming Raspberry Pi Pico with VS Code and MicroPython<\/a><\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Parts Required<\/h3>\n\n\n\n<p>To follow the examples in this tutorial, you need the following parts:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/i2c-lcd-16x2\/\" target=\"_blank\" rel=\"noopener\" title=\"\">LCD Display (with I2C support)<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/raspberry-pi-pico-w\/\" target=\"_blank\" rel=\"noopener\" title=\"\">Raspberry Pi Pico or Raspberry Pi Pico W<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/mb-102-solderless-breadboard-830-points\/\" target=\"_blank\" rel=\"noopener\" title=\"\">Breadboard<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/jumper-wires-kit-120-pieces\/\" target=\"_blank\" rel=\"noopener\" title=\"\">Jumper wires<\/a><\/li>\n<\/ul>\n\n\n<p>You can use the preceding links or go directly to <a href=\"https:\/\/makeradvisor.com\/tools\/?utm_source=rnt&utm_medium=post&utm_campaign=post\" target=\"_blank\">MakerAdvisor.com\/tools<\/a> to find all the parts for your projects at the best price!<\/p><p style=\"text-align:center;\"><a href=\"https:\/\/makeradvisor.com\/tools\/?utm_source=rnt&utm_medium=post&utm_campaign=post\" target=\"_blank\"><img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2017\/10\/header-200.png?w=1200&#038;quality=100&#038;strip=all&#038;ssl=1\"><\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"intro-lcd\">Introducing the LCD<\/h2>\n\n\n\n<p>One of the simplest and cheapest display screens around is the liquid crystal display (LCD). LCDs are found in everyday electronic devices like vending machines, calculators, parking meters, and printers, and are ideal for displaying text or small icons.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"750\" height=\"500\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/07\/i2c_LCD.jpg?resize=750%2C500&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"LCD Display with I2C interface\" class=\"wp-image-67540\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/07\/i2c_LCD.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/07\/i2c_LCD.jpg?resize=300%2C200&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<p>LCDs are measured according to the number of rows and col\u00adumns of characters that fit on the screen. A 16\u00d72 LCD can display 2 rows of 16 characters each. You\u2019ll find sizes ranging from 8\u00d71 to 40\u00d74.<\/p>\n\n\n\n<p>One of the easiest ways to control an LCD with a microcontroller is using one that comes with an I2C interface. We\u2019ll use a <a href=\"https:\/\/makeradvisor.com\/tools\/i2c-lcd-16x2\/\" target=\"_blank\" rel=\"noopener\" title=\"\">16&#215;2 LCD that uses I2C communication<\/a>.<\/p>\n\n\n\n<p>To follow this tutorial, you should get one that also uses I2C. As for the size, you can choose whatever size you want, and it should be compatible.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">LCD with I2C Driver<\/h3>\n\n\n\n<p>The advantage of using an I2C LCD is that the wiring is really simple. You just need to wire the SDA and SCL pins.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"750\" height=\"500\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/07\/I2C_LCD2.jpg?resize=750%2C500&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"LCD Display with I2C Driver\" class=\"wp-image-67541\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/07\/I2C_LCD2.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/07\/I2C_LCD2.jpg?resize=300%2C200&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<p>Additionally, it comes with a built-in potentiometer to adjust the contrast between the background and the characters on the LCD. On a \u201cregular\u201d LCD without I2C support, you need to add a potentiometer to the circuit to adjust the contrast.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"rpi-pico-lcd-wiring\">Wiring the I2C LCD to the Raspberry Pi Pico<\/h2>\n\n\n\n<p>Because this LCD module supports I2C communication, wiring is very straightforward. We\u2019ll connect the I2C pins to <span class=\"rnthl rntcblue\">GPIO 5<\/span> and <span class=\"rnthl rntcgreen\">GPIO 4<\/span>, but you can use any other I2C pins as long as you adjust the code. The VCC pin of the LCD needs to be connected to <strong>5V<\/strong>. So, you\u2019ll connect it to the <strong>VBUS (5V)<\/strong> pin.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td><strong>LCD Display<\/strong><\/td><td><strong>Raspberry Pi Pico<\/strong><\/td><\/tr><tr><td>SCL<\/td><td><span class=\"rnthl rntcblue\">GPIO 5<\/span><\/td><\/tr><tr><td>SDA<\/td><td><span class=\"rnthl rntcgreen\">GPIO 4<\/span><\/td><\/tr><tr><td>VCC<\/td><td>VBUS (5V)<\/td><\/tr><tr><td>GND<\/td><td>GND<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"rntbox rntclblue\">Recommended reading: <a href=\"https:\/\/randomnerdtutorials.com\/raspberry-pi-pico-w-pinout-gpios\/\" title=\"\">Raspberry Pi Pico and Pico W Pinout Guide: GPIOs Explained<\/a><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Circuit Diagram<\/h3>\n\n\n\n<p>You can also use the following diagram as a reference.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1200\" height=\"548\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/Raspberry-Pi-Pico-LCD_bb.png?resize=1200%2C548&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Wiring the Raspberry Pi Pico to the LCD Display (I2C)\" class=\"wp-image-150517\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/Raspberry-Pi-Pico-LCD_bb.png?w=1377&amp;quality=100&amp;strip=all&amp;ssl=1 1377w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/Raspberry-Pi-Pico-LCD_bb.png?resize=300%2C137&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/Raspberry-Pi-Pico-LCD_bb.png?resize=1024%2C468&amp;quality=100&amp;strip=all&amp;ssl=1 1024w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/Raspberry-Pi-Pico-LCD_bb.png?resize=768%2C351&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 1200px) 100vw, 1200px\" \/><\/figure><\/div>\n\n\n<h2 class=\"wp-block-heading\">Finding the LCD I2C Address<\/h2>\n\n\n\n<p>Most I2C LCDs will have the I2C address <strong>0x27<\/strong>. However, yours might be different. So it\u2019s&nbsp;important to check the I2C address&nbsp;before continuing. <\/p>\n\n\n\n<p>Follow the next tutorial to double-check your display I2C address:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/raspberry-pi-pico-i2c-scanner-micropython\/\">Raspberry Pi Pico: I2C Scanner (MicroPython) \u2013 Finding the Address of I2C Devices<\/a><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"lcd-libraries\">LCD Libraries &#8211; MicroPython<\/h2>\n\n\n\n<p>There are different libraries that make it easy to communicate with the LCD. We\u2019ll use a combination of two different modules developed and forked <a href=\"https:\/\/github.com\/T-622\/RPI-PICO-I2C-LCD\/tree\/main\" target=\"_blank\" rel=\"noopener\" title=\"\">by this GitHub user<\/a>.<\/p>\n\n\n\n<p>Follow the next steps to install the two required modules.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Download and Upload the <em>lcd_api.py<\/em><\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><a href=\"https:\/\/raw.githubusercontent.com\/RuiSantosdotme\/Random-Nerd-Tutorials\/master\/Projects\/Raspberry-Pi-Pico\/MicroPython\/lcd_api.py\" target=\"_blank\" rel=\"noopener\" title=\"\">Click here to download the <em>lcd_api.py<\/em> code<\/a>;<\/li>\n\n\n\n<li>Copy the code to a file on Thonny IDE;<\/li>\n\n\n\n<li>Go to <strong>File<\/strong> &gt; <strong>Save as\u2026<\/strong> and select Raspberry Pi Pico;<\/li>\n\n\n\n<li>Save the file with the name <strong><em>lcd_api.py<\/em><\/strong> (don\u2019t change the name).<\/li>\n<\/ol>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-python\"># forked from https:\/\/github.com\/T-622\/RPI-PICO-I2C-LCD\/\nimport time\n\nclass LcdApi:\n    \n    # Implements the API for talking with HD44780 compatible character LCDs.\n    # This class only knows what commands to send to the LCD, and not how to get\n    # them to the LCD.\n    #\n    # It is expected that a derived class will implement the hal_xxx functions.\n    #\n    # The following constant names were lifted from the avrlib lcd.h header file,\n    # with bit numbers changed to bit masks.\n    \n    # HD44780 LCD controller command set\n    LCD_CLR             = 0x01  # DB0: clear display\n    LCD_HOME            = 0x02  # DB1: return to home position\n\n    LCD_ENTRY_MODE      = 0x04  # DB2: set entry mode\n    LCD_ENTRY_INC       = 0x02  # DB1: increment\n    LCD_ENTRY_SHIFT     = 0x01  # DB0: shift\n\n    LCD_ON_CTRL         = 0x08  # DB3: turn lcd\/cursor on\n    LCD_ON_DISPLAY      = 0x04  # DB2: turn display on\n    LCD_ON_CURSOR       = 0x02  # DB1: turn cursor on\n    LCD_ON_BLINK        = 0x01  # DB0: blinking cursor\n\n    LCD_MOVE            = 0x10  # DB4: move cursor\/display\n    LCD_MOVE_DISP       = 0x08  # DB3: move display (0-&gt; move cursor)\n    LCD_MOVE_RIGHT      = 0x04  # DB2: move right (0-&gt; left)\n\n    LCD_FUNCTION        = 0x20  # DB5: function set\n    LCD_FUNCTION_8BIT   = 0x10  # DB4: set 8BIT mode (0-&gt;4BIT mode)\n    LCD_FUNCTION_2LINES = 0x08  # DB3: two lines (0-&gt;one line)\n    LCD_FUNCTION_10DOTS = 0x04  # DB2: 5x10 font (0-&gt;5x7 font)\n    LCD_FUNCTION_RESET  = 0x30  # See &quot;Initializing by Instruction&quot; section\n\n    LCD_CGRAM           = 0x40  # DB6: set CG RAM address\n    LCD_DDRAM           = 0x80  # DB7: set DD RAM address\n\n    LCD_RS_CMD          = 0\n    LCD_RS_DATA         = 1\n\n    LCD_RW_WRITE        = 0\n    LCD_RW_READ         = 1\n\n    def __init__(self, num_lines, num_columns):\n        self.num_lines = num_lines\n        if self.num_lines &gt; 4:\n            self.num_lines = 4\n        self.num_columns = num_columns\n        if self.num_columns &gt; 40:\n            self.num_columns = 40\n        self.cursor_x = 0\n        self.cursor_y = 0\n        self.implied_newline = False\n        self.backlight = True\n        self.display_off()\n        self.backlight_on()\n        self.clear()\n        self.hal_write_command(self.LCD_ENTRY_MODE | self.LCD_ENTRY_INC)\n        self.hide_cursor()\n        self.display_on()\n\n    def clear(self):\n        # Clears the LCD display and moves the cursor to the top left corner\n        self.hal_write_command(self.LCD_CLR)\n        self.hal_write_command(self.LCD_HOME)\n        self.cursor_x = 0\n        self.cursor_y = 0\n\n    def show_cursor(self):\n        # Causes the cursor to be made visible\n        self.hal_write_command(self.LCD_ON_CTRL | self.LCD_ON_DISPLAY |\n                               self.LCD_ON_CURSOR)\n\n    def hide_cursor(self):\n        # Causes the cursor to be hidden\n        self.hal_write_command(self.LCD_ON_CTRL | self.LCD_ON_DISPLAY)\n\n    def blink_cursor_on(self):\n        # Turns on the cursor, and makes it blink\n        self.hal_write_command(self.LCD_ON_CTRL | self.LCD_ON_DISPLAY |\n                               self.LCD_ON_CURSOR | self.LCD_ON_BLINK)\n\n    def blink_cursor_off(self):\n        # Turns on the cursor, and makes it no blink (i.e. be solid)\n        self.hal_write_command(self.LCD_ON_CTRL | self.LCD_ON_DISPLAY |\n                               self.LCD_ON_CURSOR)\n\n    def display_on(self):\n        # Turns on (i.e. unblanks) the LCD\n        self.hal_write_command(self.LCD_ON_CTRL | self.LCD_ON_DISPLAY)\n\n    def display_off(self):\n        # Turns off (i.e. blanks) the LCD\n        self.hal_write_command(self.LCD_ON_CTRL)\n\n    def backlight_on(self):\n        # Turns the backlight on.\n        \n        # This isn't really an LCD command, but some modules have backlight\n        # controls, so this allows the hal to pass through the command.\n        self.backlight = True\n        self.hal_backlight_on()\n\n    def backlight_off(self):\n        # Turns the backlight off.\n\n        # This isn't really an LCD command, but some modules have backlight\n        # controls, so this allows the hal to pass through the command.\n        self.backlight = False\n        self.hal_backlight_off()\n\n    def move_to(self, cursor_x, cursor_y):\n        # Moves the cursor position to the indicated position. The cursor\n        # position is zero based (i.e. cursor_x == 0 indicates first column).\n        self.cursor_x = cursor_x\n        self.cursor_y = cursor_y\n        addr = cursor_x &amp; 0x3f\n        if cursor_y &amp; 1:\n            addr += 0x40    # Lines 1 &amp; 3 add 0x40\n        if cursor_y &amp; 2:    # Lines 2 &amp; 3 add number of columns\n            addr += self.num_columns\n        self.hal_write_command(self.LCD_DDRAM | addr)\n\n    def putchar(self, char):\n        # Writes the indicated character to the LCD at the current cursor\n        # position, and advances the cursor by one position.\n        if char == '\\n':\n            if self.implied_newline:\n                # self.implied_newline means we advanced due to a wraparound,\n                # so if we get a newline right after that we ignore it.\n                pass\n            else:\n                self.cursor_x = self.num_columns\n        else:\n            self.hal_write_data(ord(char))\n            self.cursor_x += 1\n        if self.cursor_x &gt;= self.num_columns:\n            self.cursor_x = 0\n            self.cursor_y += 1\n            self.implied_newline = (char != '\\n')\n        if self.cursor_y &gt;= self.num_lines:\n            self.cursor_y = 0\n        self.move_to(self.cursor_x, self.cursor_y)\n\n    def putstr(self, string):\n        # Write the indicated string to the LCD at the current cursor\n        # position and advances the cursor position appropriately.\n        for char in string:\n            self.putchar(char)\n\n    def custom_char(self, location, charmap):\n        # Write a character to one of the 8 CGRAM locations, available\n        # as chr(0) through chr(7).\n        location &amp;= 0x7\n        self.hal_write_command(self.LCD_CGRAM | (location &lt;&lt; 3))\n        self.hal_sleep_us(40)\n        for i in range(8):\n            self.hal_write_data(charmap[i])\n            self.hal_sleep_us(40)\n        self.move_to(self.cursor_x, self.cursor_y)\n\n    def hal_backlight_on(self):\n        # Allows the hal layer to turn the backlight on.\n        # If desired, a derived HAL class will implement this function.\n        pass\n\n    def hal_backlight_off(self):\n        # Allows the hal layer to turn the backlight off.\n        # If desired, a derived HAL class will implement this function.\n        pass\n\n    def hal_write_command(self, cmd):\n        # Write a command to the LCD.\n        # It is expected that a derived HAL class will implement this function.\n        raise NotImplementedError\n\n    def hal_write_data(self, data):\n        # Write data to the LCD.\n        # It is expected that a derived HAL class will implement this function.\n        raise NotImplementedError\n\n    def hal_sleep_us(self, usecs):\n        # Sleep for some time (given in microseconds)\n        time.sleep_us(usecs)\n<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/Random-Nerd-Tutorials\/raw\/master\/Projects\/Raspberry-Pi-Pico\/MicroPython\/lcd_api.py\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Download and Upload the <em>pico_i2c_lcd.py<\/em><\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><a href=\"https:\/\/raw.githubusercontent.com\/RuiSantosdotme\/Random-Nerd-Tutorials\/master\/Projects\/Raspberry-Pi-Pico\/MicroPython\/pico_i2c_lcd.py\" target=\"_blank\" rel=\"noopener\" title=\"\">Click here to download the <em>pico_i2c_lcd.py<\/em> code<\/a>;<\/li>\n\n\n\n<li>Copy the code to a file on Thonny IDE;<\/li>\n\n\n\n<li>Go to <strong>File<\/strong> &gt; <strong>Save as\u2026<\/strong> and select Raspberry Pi Pico;<\/li>\n\n\n\n<li>Save the file with the name<strong> pico_i2c_lcd.py<\/strong> (don\u2019t change the name).<\/li>\n<\/ol>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-python\"># forked from https:\/\/github.com\/T-622\/RPI-PICO-I2C-LCD\/\nimport utime\nimport gc\n\nfrom lcd_api import LcdApi\nfrom machine import I2C\n\n# PCF8574 pin definitions\nMASK_RS = 0x01       # P0\nMASK_RW = 0x02       # P1\nMASK_E  = 0x04       # P2\n\nSHIFT_BACKLIGHT = 3  # P3\nSHIFT_DATA      = 4  # P4-P7\n\nclass I2cLcd(LcdApi):\n    \n    #Implements a HD44780 character LCD connected via PCF8574 on I2C\n\n    def __init__(self, i2c, i2c_addr, num_lines, num_columns):\n        self.i2c = i2c\n        self.i2c_addr = i2c_addr\n        self.i2c.writeto(self.i2c_addr, bytes([0]))\n        utime.sleep_ms(20)   # Allow LCD time to powerup\n        # Send reset 3 times\n        self.hal_write_init_nibble(self.LCD_FUNCTION_RESET)\n        utime.sleep_ms(5)    # Need to delay at least 4.1 msec\n        self.hal_write_init_nibble(self.LCD_FUNCTION_RESET)\n        utime.sleep_ms(1)\n        self.hal_write_init_nibble(self.LCD_FUNCTION_RESET)\n        utime.sleep_ms(1)\n        # Put LCD into 4-bit mode\n        self.hal_write_init_nibble(self.LCD_FUNCTION)\n        utime.sleep_ms(1)\n        LcdApi.__init__(self, num_lines, num_columns)\n        cmd = self.LCD_FUNCTION\n        if num_lines &gt; 1:\n            cmd |= self.LCD_FUNCTION_2LINES\n        self.hal_write_command(cmd)\n        gc.collect()\n\n    def hal_write_init_nibble(self, nibble):\n        # Writes an initialization nibble to the LCD.\n        # This particular function is only used during initialization.\n        byte = ((nibble &gt;&gt; 4) &amp; 0x0f) &lt;&lt; SHIFT_DATA\n        self.i2c.writeto(self.i2c_addr, bytes([byte | MASK_E]))\n        self.i2c.writeto(self.i2c_addr, bytes([byte]))\n        gc.collect()\n        \n    def hal_backlight_on(self):\n        # Allows the hal layer to turn the backlight on\n        self.i2c.writeto(self.i2c_addr, bytes([1 &lt;&lt; SHIFT_BACKLIGHT]))\n        gc.collect()\n        \n    def hal_backlight_off(self):\n        #Allows the hal layer to turn the backlight off\n        self.i2c.writeto(self.i2c_addr, bytes([0]))\n        gc.collect()\n        \n    def hal_write_command(self, cmd):\n        # Write a command to the LCD. Data is latched on the falling edge of E.\n        byte = ((self.backlight &lt;&lt; SHIFT_BACKLIGHT) |\n                (((cmd &gt;&gt; 4) &amp; 0x0f) &lt;&lt; SHIFT_DATA))\n        self.i2c.writeto(self.i2c_addr, bytes([byte | MASK_E]))\n        self.i2c.writeto(self.i2c_addr, bytes([byte]))\n        byte = ((self.backlight &lt;&lt; SHIFT_BACKLIGHT) |\n                ((cmd &amp; 0x0f) &lt;&lt; SHIFT_DATA))\n        self.i2c.writeto(self.i2c_addr, bytes([byte | MASK_E]))\n        self.i2c.writeto(self.i2c_addr, bytes([byte]))\n        if cmd &lt;= 3:\n            # The home and clear commands require a worst case delay of 4.1 msec\n            utime.sleep_ms(5)\n        gc.collect()\n\n    def hal_write_data(self, data):\n        # Write data to the LCD. Data is latched on the falling edge of E.\n        byte = (MASK_RS |\n                (self.backlight &lt;&lt; SHIFT_BACKLIGHT) |\n                (((data &gt;&gt; 4) &amp; 0x0f) &lt;&lt; SHIFT_DATA))\n        self.i2c.writeto(self.i2c_addr, bytes([byte | MASK_E]))\n        self.i2c.writeto(self.i2c_addr, bytes([byte]))\n        byte = (MASK_RS |\n                (self.backlight &lt;&lt; SHIFT_BACKLIGHT) |\n                ((data &amp; 0x0f) &lt;&lt; SHIFT_DATA))      \n        self.i2c.writeto(self.i2c_addr, bytes([byte | MASK_E]))\n        self.i2c.writeto(self.i2c_addr, bytes([byte]))\n        gc.collect()\n<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/Random-Nerd-Tutorials\/raw\/master\/Projects\/Raspberry-Pi-Pico\/MicroPython\/pico_i2c_lcd.py\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<p>With the modules loaded to the Raspberry Pi Pico, now you can use the library functionalities in your code to write text to the LCD.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"display-static-text\">Displaying Static Text &#8211; Code<\/h2>\n\n\n\n<p>Displaying static text on the LCD is very simple. All you have to do is select where you want the characters to be displayed on the screen and then send the message to the display. If you don\u2019t specify where you want to display the text, it will be written in the first available space.<\/p>\n\n\n\n<p>This simple example displays the \u201cHello, World!\u201d message in the first row, and then on the second row.<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-python\"># Rui Santos &amp; Sara Santos - Random Nerd Tutorials\n# Complete project details at https:\/\/RandomNerdTutorials.com\/raspberry-pi-pico-i2c-lcd-display-micropython\/\n\nfrom machine import Pin, SoftI2C\nfrom pico_i2c_lcd import I2cLcd\nfrom time import sleep\n\n# Define the LCD I2C address and dimensions\nI2C_ADDR = 0x27\nI2C_NUM_ROWS = 2\nI2C_NUM_COLS = 16\n\n# Initialize I2C and LCD objects\ni2c = SoftI2C(sda=Pin(4), scl=Pin(5), freq=400000)\nlcd = I2cLcd(i2c, I2C_ADDR, I2C_NUM_ROWS, I2C_NUM_COLS)\n\nlcd.putstr(&quot;It's working :)&quot;)\nsleep(4)\n\ntry:\n    while True:\n        # Clear the LCD\n        lcd.clear()\n        # Display two different messages on different lines\n        # By default, it will start at (0,0) if the display is empty\n        lcd.putstr(&quot;Hello World!&quot;)\n        sleep(2)\n        lcd.clear()\n        # Starting at the second line (0, 1)\n        lcd.move_to(0, 1)\n        lcd.putstr(&quot;Hello World!&quot;)\n        sleep(2)\n\nexcept KeyboardInterrupt:\n    # Turn off the display\n    print(&quot;Keyboard interrupt&quot;)\n    lcd.backlight_off()\n    lcd.display_off()\n<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/Random-Nerd-Tutorials\/raw\/master\/Projects\/Raspberry-Pi-Pico\/MicroPython\/LDC_Display_Static_Text.py\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">How the Code Works<\/h3>\n\n\n\n<p>Let\u2019s take a quick look at how the code works to see how to interact with the LCD.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Importing Libraries<\/h4>\n\n\n\n<p>We start by including all the required modules to communicate with the LCD. We\u2019ll use software I2C.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>from machine import Pin, SoftI2C\nfrom pico_i2c_lcd import I2cLcd\nfrom time import sleep<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">LCD Properties<\/h4>\n\n\n\n<p>On the following lines, define your LCD properties. Our LCD display is 2&#215;16 (2 rows and 16 columns) LCD and the I2C address is 0x27. If your display has different dimensions or if it has a different address, modify the following lines.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code># Define the LCD I2C address and dimensions\nI2C_ADDR = 0x27\nI2C_NUM_ROWS = 2\nI2C_NUM_COLS = 16<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">I2C Communication<\/h4>\n\n\n\n<p>Then, we initialize I2C on GPIOs 4 and 5, the pins we\u2019re using to connect the LCD.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>i2c = SoftI2C(sda=Pin(4), scl=Pin(5), freq=400000)<\/code><\/pre>\n\n\n\n<p>After creating an I2C instance, we can initialize an I2C communication with the LCD using the following line.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>lcd = I2cLcd(i2c, I2C_ADDR, I2C_NUM_ROWS, I2C_NUM_COLS)<\/code><\/pre>\n\n\n\n<p>We create a new object called <span class=\"rnthl rntliteral\">lcd<\/span> using the <span class=\"rnthl rntliteral\">I2cLcd()<\/span> method and pass as arguments, the i2c instance, the address, and the number of rows and columns. We can now use <span class=\"rnthl rntliteral\">lcd<\/span> to refer to the LCD screen.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Writing Text<\/h4>\n\n\n\n<p>Now, that we have a communication established we can start writing text. Writing simple text is as easy as using the <span class=\"rnthl rntliteral\">putstr()<\/span> method on the <span class=\"rnthl rntliteral\">lcd<\/span> object and passing as an argument the text we want to display. For example:<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>lcd.putstr(\"It's working :)\")<\/code><\/pre>\n\n\n\n<p>This will display the \u201c<strong>It\u2019s working \ud83d\ude42<\/strong>\u201d message. Because we didn\u2019t specify a place, and the LCD screen is still empty, it will display the message at (0, 0) first row, first column.<\/p>\n\n\n\n<p>Then, we have a while loop that continuously displays &#8220;Hello World!&#8221; on the LCD, alternating between the top and bottom rows, creating a simple and repeating display pattern.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>while True:\n    # Clear the LCD\n    lcd.clear()\n    # Display two different messages on different lines\n    # By default, it will start at (0,0) if the display is empty\n    lcd.putstr(\"Hello World!\")\n    sleep(2)\n    lcd.clear()\n    # Starting at the second line (0, 1)\n    lcd.move_to(0, 1)\n    lcd.putstr(\"Hello World!\")\n    sleep(2)<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Clearing the Screen<\/h4>\n\n\n\n<p>Before writing new information, we clear the contents of the screen using the <span class=\"rnthl rntliteral\">clear()<\/span> method.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>lcd.clear()<\/code><\/pre>\n\n\n\n<p>Then, we display the string &#8220;Hello World!&#8221; on the LCD. By default, it starts at the top\u2011left corner of the display (position 0, 0).<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>lcd.putstr(\"Hello World!\")<\/code><\/pre>\n\n\n\n<p>This message will be on the screen for two seconds.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>sleep(2)<\/code><\/pre>\n\n\n\n<p>After that, we\u2019ll clear the screen again.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>lcd.clear()<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Moving the Cursor<\/h4>\n\n\n\n<p>After that, we\u2019ll use the <span class=\"rnthl rntliteral\">move_to()<\/span> method that accepts as arguments the row and column number, allowing us to choose where to start displaying text. In this case, we\u2019re setting the cursor position to the beginning of the second line (row 1, column 0) of the LCD. This allows us to display the second &#8220;Hello World!&#8221; message on the second line.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Turning Off the Backlight<\/h4>\n\n\n\n<p>We also add a snippet to turn off the LCD light in case the program is stopped by a keyboard interrupt. You can use the methods <span class=\"rnthl rntliteral\">backlight_off()<\/span> and <span class=\"rnthl rntliteral\">display_off()<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>except KeyboardInterrupt:\n    # Turn off the display\n    print(\"Keyboard interrupt\")\n    lcd.backlight_off()\n    lcd.display_off()<\/code><\/pre>\n\n\n\n<p>This simple example shows the most useful methods to interact with the LCD. We encourage you to take a look at the <em>pico_i2c_lcd.py<\/em> and <em>lcd_api.py<\/em> modules and check and test other methods you think might be useful.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Testing the Code<\/h3>\n\n\n\n<p>Run the previous code on your Raspberry Pi Pico board. You\u2019ll first get a message showing that it is working.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"750\" height=\"422\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/Raspberry-Pi-Pico-LCD-Test.jpg?resize=750%2C422&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Testing the LCD on a Raspberry Pi Pico\" class=\"wp-image-150527\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/Raspberry-Pi-Pico-LCD-Test.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/Raspberry-Pi-Pico-LCD-Test.jpg?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<p>After, it will display the Hello, World! message in the first row for two seconds, and then in the second row for another two seconds. Then, the loop repeats until you stop the program.<\/p>\n\n\n\n<div class=\"wp-block-jetpack-tiled-gallery aligncenter is-style-rectangular\"><div class=\"\"><div class=\"tiled-gallery__gallery\"><div class=\"tiled-gallery__row\"><div class=\"tiled-gallery__col\" style=\"flex-basis:50.00000%\"><figure class=\"tiled-gallery__item\"><img decoding=\"async\" srcset=\"https:\/\/i1.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/LCD-Raspberry-Pi-Pico-Hello-World-1.jpg?strip=info&#038;w=600&#038;ssl=1 600w, https:\/\/i1.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/LCD-Raspberry-Pi-Pico-Hello-World-1.jpg?strip=info&#038;w=750&#038;ssl=1 750w\" alt=\"\" data-height=\"422\" data-id=\"150528\" data-link=\"https:\/\/randomnerdtutorials.com\/?attachment_id=150528#main\" data-url=\"https:\/\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/LCD-Raspberry-Pi-Pico-Hello-World-1.jpg\" data-width=\"750\" src=\"https:\/\/i1.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/LCD-Raspberry-Pi-Pico-Hello-World-1.jpg?ssl=1\" data-amp-layout=\"responsive\"\/><\/figure><\/div><div class=\"tiled-gallery__col\" style=\"flex-basis:50.00000%\"><figure class=\"tiled-gallery__item\"><img decoding=\"async\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/LCD-Raspberry-Pi-Pico-Hello-World-2.jpg?strip=info&#038;w=600&#038;ssl=1 600w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/LCD-Raspberry-Pi-Pico-Hello-World-2.jpg?strip=info&#038;w=750&#038;ssl=1 750w\" alt=\"\" data-height=\"422\" data-id=\"150529\" data-link=\"https:\/\/randomnerdtutorials.com\/?attachment_id=150529#main\" data-url=\"https:\/\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/LCD-Raspberry-Pi-Pico-Hello-World-2.jpg\" data-width=\"750\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/LCD-Raspberry-Pi-Pico-Hello-World-2.jpg?ssl=1\" data-amp-layout=\"responsive\"\/><\/figure><\/div><\/div><\/div><\/div><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Troubleshooting<\/h3>\n\n\n\n<p>If the LCD has very little contrast and you can hardly see the characters, rotate the potentiometer at the back to adjust the contrast between the characters and the backlight.<\/p>\n\n\n\n<p>Additionally, make sure you\u2019re powering the LCD using 5V from the VBUS pin. Powering with 3V3 is not enough for most of these modules (unless otherwise specified in the datasheet).<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity is-style-wide\"\/>\n\n\n\n<h1 class=\"wp-block-heading\" id=\"scroll-text\">Displaying Scrolling Text<\/h1>\n\n\n\n<p>Scrolling text on the LCD is useful to display messages longer than your LCD width (in our case, longer than 16 characters).<\/p>\n\n\n\n<p>The library we\u2019re using doesn\u2019t come with a specific function to scroll the text, but you can build your own function by shifting the text to the left one position at a time. See the example below.<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-python\"># Rui Santos &amp; Sara Santos - Random Nerd Tutorials\n# Complete project details at https:\/\/RandomNerdTutorials.com\/raspberry-pi-pico-i2c-lcd-display-micropython\/\n\nfrom machine import Pin, SoftI2C\nfrom pico_i2c_lcd import I2cLcd\nfrom time import sleep\n\n# Define the LCD I2C address and dimensions\nI2C_ADDR = 0x27\nI2C_NUM_ROWS = 2\nI2C_NUM_COLS = 16\n\n# Initialize I2C and LCD objects\ni2c = SoftI2C(sda=Pin(4), scl=Pin(5), freq=400000)\nlcd = I2cLcd(i2c, I2C_ADDR, I2C_NUM_ROWS, I2C_NUM_COLS)\n\ndef scroll_message(message, delay=0.3):\n    # Add spaces to the beginning of the message to make it appear from the right\n    message = &quot; &quot; * I2C_NUM_COLS + message + &quot; &quot;\n    # Scroll through the message\n    for i in range(len(message) - I2C_NUM_COLS + 1):\n        lcd.move_to(0, 0)\n        lcd.putstr(message[i:i + I2C_NUM_COLS])\n        sleep(delay)\n\ntry:\n    lcd.putstr(&quot;Testing scroll!&quot;)\n    sleep(2)\n\n    # Define the message to be scrolled\n    message_scroll = &quot;This is a scrolling message with more than 16 characters&quot;\n\n    while True:\n        # Scroll the message on the LCD\n        lcd.clear()\n        scroll_message(message_scroll)\n\nexcept KeyboardInterrupt:\n    # Turn off the display when the code is interrupted by the user\n    print(&quot;Keyboard interrupt&quot;)\n    lcd.backlight_off()\n    lcd.display_off()\n<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/Random-Nerd-Tutorials\/raw\/master\/Projects\/Raspberry-Pi-Pico\/MicroPython\/LCD_Scrolling_Text.py\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">How the Code Works<\/h3>\n\n\n\n<p>In this example, we create a simple function called <span class=\"rnthl rntliteral\">scroll_message()<\/span> that accepts as arguments the message to be displayed and the delay between each shift. By default, we set the delay to 0.3 seconds, but you can adjust depending on how fast you want the text to scroll.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>def scroll_message(message, delay=0.3):\n    # Add spaces to the beginning of the message to make it appear from the right\n    message = \" \" * I2C_NUM_COLS + message + \" \"\n    # Scroll through the message\n    for i in range(len(message) - I2C_NUM_COLS + 1):\n        lcd.move_to(0, 0)\n        lcd.putstr(message&#091;i:i + I2C_NUM_COLS])\n        sleep(delay)<\/code><\/pre>\n\n\n\n<p>On that function, we start by adding a padding to our message that consists of as many blank spaces as the number of columns (<span class=\"rnthl rntliteral\">I2C_NUM_COLS<\/span>) and a final space at the end. We do this to create a space from where to start scrolling.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>message = \" \" * I2C_NUM_COLS + message + \" \"<\/code><\/pre>\n\n\n\n<p>Then, we have a for loop that will iterate through the characters of our message. We set the cursor position to the top-left corner of the LCD (column 0, row 0) to ensure that each iteration starts from the beginning of the LCD.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>lcd.move_to(0, 0)<\/code><\/pre>\n\n\n\n<p>Then, we display a portion of the message on the LCD, starting from the current iteration index <span class=\"rnthl rntliteral\">i<\/span> and covering the width of the LCD (<span class=\"rnthl rntliteral\">I2C_NUM_COLS<\/span> characters).<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>lcd.putstr(message&#091;i:i + I2C_NUM_COLS])<\/code><\/pre>\n\n\n\n<p>The following expression <span class=\"rnthl rntliteral\">message[i:i + I2C_NUM_COLS]<\/span> gets just a portion of the message starting at the character with index <span class=\"rnthl rntliteral\">i<\/span> and ending at character <span class=\"rnthl rntliteral\">i + IC2_NUM_COLS<\/span>. As we increase the value of <span class=\"rnthl rntliteral\">i<\/span>, we select a new portion of the message, making the scrolling effect.<\/p>\n\n\n\n<p>Finally, the delay at the end will determine the scrolling speed.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>sleep(delay)<\/code><\/pre>\n\n\n\n<p>To scroll the text, call the <span class=\"rnthl rntliteral\">scroll_message()<\/span> function and pass as arguments the message you want to scroll and the delay time.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>scroll_message(message_scroll, 0.4)<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Testing the Code<\/h3>\n\n\n\n<p>Run the previous code on your Raspberry Pi Pico. You should get a scrolling message. You can adjust the scrolling speed in the <span class=\"rnthl rntliteral\">delay<\/span> variable in the <span class=\"rnthl rntliteral\">scroll_message()<\/span> function.<\/p>\n\n\n\n<div class=\"wp-block-jetpack-tiled-gallery aligncenter is-style-rectangular\"><div class=\"\"><div class=\"tiled-gallery__gallery\"><div class=\"tiled-gallery__row\"><div class=\"tiled-gallery__col\" style=\"flex-basis:50.00000%\"><figure class=\"tiled-gallery__item\"><img decoding=\"async\" srcset=\"https:\/\/i2.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/Raspberry-Pi-Pico-LCD-Scrolling-Text-1.jpg?strip=info&#038;w=600&#038;ssl=1 600w, https:\/\/i2.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/Raspberry-Pi-Pico-LCD-Scrolling-Text-1.jpg?strip=info&#038;w=750&#038;ssl=1 750w\" alt=\"\" data-height=\"422\" data-id=\"150530\" data-link=\"https:\/\/randomnerdtutorials.com\/?attachment_id=150530#main\" data-url=\"https:\/\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/Raspberry-Pi-Pico-LCD-Scrolling-Text-1.jpg\" data-width=\"750\" src=\"https:\/\/i2.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/Raspberry-Pi-Pico-LCD-Scrolling-Text-1.jpg?ssl=1\" data-amp-layout=\"responsive\"\/><\/figure><\/div><div class=\"tiled-gallery__col\" style=\"flex-basis:50.00000%\"><figure class=\"tiled-gallery__item\"><img decoding=\"async\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/Raspberry-Pi-Pico-LCD-Scrolling-Text-2.jpg?strip=info&#038;w=600&#038;ssl=1 600w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/Raspberry-Pi-Pico-LCD-Scrolling-Text-2.jpg?strip=info&#038;w=750&#038;ssl=1 750w\" alt=\"\" data-height=\"422\" data-id=\"150531\" data-link=\"https:\/\/randomnerdtutorials.com\/?attachment_id=150531#main\" data-url=\"https:\/\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/Raspberry-Pi-Pico-LCD-Scrolling-Text-2.jpg\" data-width=\"750\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/Raspberry-Pi-Pico-LCD-Scrolling-Text-2.jpg?ssl=1\" data-amp-layout=\"responsive\"\/><\/figure><\/div><\/div><div class=\"tiled-gallery__row\"><div class=\"tiled-gallery__col\" style=\"flex-basis:50.00000%\"><figure class=\"tiled-gallery__item\"><img decoding=\"async\" srcset=\"https:\/\/i1.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/Raspberry-Pi-Pico-LCD-Scrolling-Text-3.jpg?strip=info&#038;w=600&#038;ssl=1 600w, https:\/\/i1.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/Raspberry-Pi-Pico-LCD-Scrolling-Text-3.jpg?strip=info&#038;w=750&#038;ssl=1 750w\" alt=\"\" data-height=\"422\" data-id=\"150532\" data-link=\"https:\/\/randomnerdtutorials.com\/?attachment_id=150532#main\" data-url=\"https:\/\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/Raspberry-Pi-Pico-LCD-Scrolling-Text-3.jpg\" data-width=\"750\" src=\"https:\/\/i1.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/Raspberry-Pi-Pico-LCD-Scrolling-Text-3.jpg?ssl=1\" data-amp-layout=\"responsive\"\/><\/figure><\/div><div class=\"tiled-gallery__col\" style=\"flex-basis:50.00000%\"><figure class=\"tiled-gallery__item\"><img decoding=\"async\" srcset=\"https:\/\/i2.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/Raspberry-Pi-Pico-LCD-Scrolling-Text-4.jpg?strip=info&#038;w=600&#038;ssl=1 600w, https:\/\/i2.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/Raspberry-Pi-Pico-LCD-Scrolling-Text-4.jpg?strip=info&#038;w=750&#038;ssl=1 750w\" alt=\"\" data-height=\"422\" data-id=\"150533\" data-link=\"https:\/\/randomnerdtutorials.com\/?attachment_id=150533#main\" data-url=\"https:\/\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/Raspberry-Pi-Pico-LCD-Scrolling-Text-4.jpg\" data-width=\"750\" src=\"https:\/\/i2.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/Raspberry-Pi-Pico-LCD-Scrolling-Text-4.jpg?ssl=1\" data-amp-layout=\"responsive\"\/><\/figure><\/div><\/div><\/div><\/div><\/div>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity is-style-wide\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"display-custom-characters\">Displaying Custom Characters<\/h2>\n\n\n\n<p>In a 16\u00d72 LCD, there are 32 blocks where you can display characters. Each block is made out of 5\u00d78 tiny pixels. You can display custom characters by defining the state of each tiny pixel. For that, you can create a byte array variable to hold the state of each pixel.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Creating Custom Characters<\/h3>\n\n\n\n<p>Most LCDs allow you to upload about 8 custom characters to the memory of the LCD that you can use later. Then, you can access the characters by their index (0 to 7).<\/p>\n\n\n\n<p>To create your custom character, you can go\u00a0<a href=\"https:\/\/maxpromer.github.io\/LCD-Character-Creator\/\" target=\"_blank\" rel=\"noopener\" title=\"\">here<\/a>\u00a0and design your custom character. Then, generate the byte array variable for your character. For example, a heart:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"911\" height=\"496\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/creating-hear-bytearray.png?resize=911%2C496&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Creating icons byte array for LCD\" class=\"wp-image-150535\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/creating-hear-bytearray.png?w=911&amp;quality=100&amp;strip=all&amp;ssl=1 911w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/creating-hear-bytearray.png?resize=300%2C163&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/creating-hear-bytearray.png?resize=768%2C418&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 911px) 100vw, 911px\" \/><\/figure><\/div>\n\n\n<p>The byte array is highlighted in yellow. Copy the byte array to a single line. For example, in the case of the heart character:<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>0x00, 0x0A, 0x1F, 0x0E, 0x04, 0x00, 0x00<\/code><\/pre>\n\n\n\n<p>Save your byte array because you\u2019ll use it later in the code.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Displaying Custom Characters &#8211; Code<\/h3>\n\n\n\n<p>The following code displays three custom characters, a thermometer, an umbrella, and a heart. You can display any character you want by using its byte array.<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-python\"># Rui Santos &amp; Sara Santos - Random Nerd Tutorials\n# Complete project details at https:\/\/RandomNerdTutorials.com\/raspberry-pi-pico-i2c-lcd-display-micropython\/\n\nfrom machine import Pin, SoftI2C\nfrom pico_i2c_lcd import I2cLcd\nfrom time import sleep\n\n# Define the LCD I2C address and dimensions\nI2C_ADDR = 0x27\nI2C_NUM_ROWS = 2\nI2C_NUM_COLS = 16\n\n# Initialize I2C and LCD objects\ni2c = SoftI2C(sda=Pin(4), scl=Pin(5), freq=400000)\nlcd = I2cLcd(i2c, I2C_ADDR, I2C_NUM_ROWS, I2C_NUM_COLS)\n\n# Create custom characters here: https:\/\/maxpromer.github.io\/LCD-Character-Creator\/\nthermometer = bytearray([0x04, 0x0A, 0x0A, 0x0A, 0x0A, 0x1B, 0x1F, 0x0E])\nlcd.custom_char(0, thermometer)\n\numbrella = bytearray([0x00, 0x04, 0x0E, 0x1F, 0x04, 0x04, 0x014, 0x0C])\nlcd.custom_char(1, umbrella)\n\nheart = bytearray([0x00, 0x0A, 0x1F, 0x1F, 0x0E, 0x04, 0x00, 0x00])\nlcd.custom_char(2, heart)\n\ntry:\n    lcd.putstr(&quot;Characters&quot;)\n    lcd.move_to(0, 1)\n    # Display thermometer\n    lcd.putchar(chr(0))\n    # Display umbrella\n    lcd.move_to(2, 1)\n    lcd.putchar(chr(1))\n    # Display heart\n    lcd.move_to(4, 1)\n    lcd.putchar(chr(2))\n \nexcept KeyboardInterrupt:\n    # Turn off the display when the code is interrupted by the user\n    print(&quot;Keyboard interrupt&quot;)\n    lcd.backlight_off()\n    lcd.display_off()\n<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/Random-Nerd-Tutorials\/raw\/master\/Projects\/Raspberry-Pi-Pico\/MicroPython\/LCD_Display_Custom_Characters.py\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">How the Code Works<\/h3>\n\n\n\n<p>First, you need to save your byte array in a variable as follows:<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>thermometer = bytearray(&#091;0x04, 0x0A, 0x0A, 0x0A, 0x0A, 0x1B, 0x1F, 0x0E])<\/code><\/pre>\n\n\n\n<p>Change the byte array for any other characters you may want to display. In our case, we also display an umbrella and a heart.<\/p>\n\n\n\n<p>Then, to save your character on the memory of your LCD, you need to use the <span class=\"rnthl rntliteral\">custom_char()<\/span> function on the <span class=\"rnthl rntliteral\">lcd<\/span> object and pass as argument the index where you want to save the character and the byte array for that character.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>lcd.custom_char (0, thermometer)<\/code><\/pre>\n\n\n\n<p>We do this previous process for all the custom characters we want to display, but each one is saved on a different <span class=\"rnthl rntliteral\">custom_char()<\/span> index.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>thermometer = bytearray(&#091;0x04, 0x0A, 0x0A, 0x0A, 0x0A, 0x1B, 0x1F, 0x0E])\nlcd.custom_char(0, thermometer)\n\numbrella = bytearray(&#091;0x00, 0x04, 0x0E, 0x1F, 0x04, 0x04, 0x014, 0x0C])\nlcd.custom_char(1, umbrella)\n\nheart = bytearray(&#091;0x00, 0x0A, 0x1F, 0x1F, 0x0E, 0x04, 0x00, 0x00])\nlcd.custom_char(2, heart)<\/code><\/pre>\n\n\n\n<p>Finally, to display your custom character you just need to use the <span class=\"rnthl rntliteral\">putchar()<\/span> function as follows:<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>lcd.putchar(chr(0))<\/code><\/pre>\n\n\n\n<p>In our case, <span class=\"rnthl rntliteral\">chr(0)<\/span> corresponds to the thermometer, the character that we saved on index 0. We proceed similarly for all the other characters. In our case, we display a static message on the first row, and then we display our custom characters on the second row.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>try:\n    lcd.putstr(\u201cCharacters\u201d)\n    lcd.move_to(0, 1)\n    # Display thermometer\n    lcd.putchar(chr(0))\n    # Display umbrella\n    lcd.move_to(2, 1)\n    lcd.putchar(chr(1))\n    # Display heart\n    lcd.move_to(4, 1)\n    lcd.putchar(chr(2))<\/code><\/pre>\n\n\n\n<p>As you can see, displaying custom characters is quite simple.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Testing the Code<\/h3>\n\n\n\n<p>Run the code on your Raspberry Pi Pico. The LCD will display your custom characters. Feel free to modify the code and display your own custom characters. You can also use several adjacent blocks to create a bigger icon on the display.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"750\" height=\"421\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/Raspberry-Pi-Pico-LCD-Custom-Characters.jpg?resize=750%2C421&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Raspberry Pi Pico with LCD - Display custom characters\" class=\"wp-image-150537\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/Raspberry-Pi-Pico-LCD-Custom-Characters.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/Raspberry-Pi-Pico-LCD-Custom-Characters.jpg?resize=300%2C168&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<h2 class=\"wp-block-heading\">Wrapping Up<\/h2>\n\n\n\n<p>In this tutorial, you learned how to use an I2C LCD with the Raspberry Pi Pico. We&#8217;ve taken a look at how to display static text, scrolling text, and custom characters.<\/p>\n\n\n\n<p>We have a similar guide for an OLED display, that you may find useful:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/raspberry-pi-pico-ssd1306-oled-micropython\/\">Raspberry Pi Pico: SSD1306 OLED Display (MicroPython)<\/a><\/li>\n<\/ul>\n\n\n\n<p>Now, you can use the LCD display to display useful data like sensor readings, time, data from the internet, and much more. We have guides for several sensors with the Raspberry Pi Pico that you may find useful:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/raspberry-pi-pico-bme280-micropython\/\">Raspberry Pi Pico: BME280 Get Temperature, Humidity, and Pressure (MicroPython)<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/raspberry-pi-pico-dht11-dht22-micropython\/\">Raspberry Pi Pico: DHT11\/DHT22 Temperature and Humidity Sensor (MicroPython)<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/raspberry-pi-pico-ds18b20-micropython\/\">Raspberry Pi Pico: DS18B20 Temperature Sensor (MicroPython) \u2013 Single and Multiple<\/a><\/li>\n<\/ul>\n\n\n\n<p>To learn more about the Raspberry Pi Pico, you can use our resources:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/raspberry-pi-pico-w-micropython-ebook\/\" title=\"\"><strong>Learn Raspberry Pi Pico with MicroPython eBook<\/strong><\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/projects-raspberry-pi-pico\/\" title=\"\">Free Raspberry Pi Pico projects and guides<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Learn how to use the I2C LCD (Liquid Crystal Display) with the Raspberry Pi Pico programmed with MicroPython. We&#8217;ll cover how to write static text, scrolling text, and how to &#8230; <\/p>\n<p class=\"read-more-container\"><a title=\"Raspberry Pi Pico with I2C LCD Display (MicroPython)\" class=\"read-more button\" href=\"https:\/\/randomnerdtutorials.com\/raspberry-pi-pico-i2c-lcd-display-micropython\/#more-150511\" aria-label=\"Read more about Raspberry Pi Pico with I2C LCD Display (MicroPython)\">CONTINUE READING \u00bb<\/a><\/p>\n","protected":false},"author":5,"featured_media":150541,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[324,326],"tags":[],"class_list":["post-150511","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-raspberry-pi-pico","category-raspberry-pi-pico-micropython"],"aioseo_notices":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/Raspberry-Pi-Pico-LCD-Micropython.jpg?fit=1920%2C1080&quality=100&strip=all&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/150511","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/comments?post=150511"}],"version-history":[{"count":15,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/150511\/revisions"}],"predecessor-version":[{"id":161800,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/150511\/revisions\/161800"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media\/150541"}],"wp:attachment":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media?parent=150511"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/categories?post=150511"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/tags?post=150511"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}