<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Robert Feliciano</title>
    <description>The latest articles on DEV Community by Robert Feliciano (@rfnyc).</description>
    <link>https://dev.to/rfnyc</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3828309%2Fca6ca21a-61d0-4e82-932c-c1bced83e0eb.jpeg</url>
      <title>DEV Community: Robert Feliciano</title>
      <link>https://dev.to/rfnyc</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rfnyc"/>
    <language>en</language>
    <item>
      <title>C++ Guide: Talking to an LCD1602 &amp; PCF8574 via i2c-dev</title>
      <dc:creator>Robert Feliciano</dc:creator>
      <pubDate>Sat, 28 Mar 2026 16:45:41 +0000</pubDate>
      <link>https://dev.to/rfnyc/c-guide-talking-to-an-lcd1602-pcf8574-via-i2c-dev-636</link>
      <guid>https://dev.to/rfnyc/c-guide-talking-to-an-lcd1602-pcf8574-via-i2c-dev-636</guid>
      <description>&lt;h2&gt;
  
  
  Preface
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;This guide will attempt to demystify the following:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;1.) How to find &amp;amp; map physical pins directly to C++ variables using binary literals (and how to use bitmasking to build instructions).&lt;/p&gt;

&lt;p&gt;2.) How to actually begin sending information to your LCD in C++.&lt;/p&gt;

&lt;p&gt;3.) How you can begin abstracting functions to minimize the amount of low-level instructions you have to write in your code.&lt;/p&gt;

&lt;p&gt;DISCLAIMER:&lt;br&gt;
&lt;em&gt;This is not an extensive guide on all the features the LCD has; it is meant to help bridge the gap between knowing nothing at all and sending your first instructions to the LCD.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I'm also very new &amp;amp; fully self taught. There might be errors which I haven't caught... With that being said, I hope this is helpful to somebody.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;References:&lt;br&gt;
&lt;a href="https://www.kernel.org/doc/html/v5.4/i2c/dev-interface.html" rel="noopener noreferrer"&gt;Kernel.org I2C Dev Interface (i2c-dev.h)&lt;/a&gt;&lt;br&gt;
&lt;a href="https://cdn.sparkfun.com/assets/9/5/f/7/b/HD44780.pdf" rel="noopener noreferrer"&gt;HD44780 Datasheet (RELEVANT PAGES: 23, 24, 25, 42, 46)&lt;/a&gt;&lt;br&gt;
&lt;a href="https://handsontec.com/dataspecs/module/I2C_1602_LCD.pdf" rel="noopener noreferrer"&gt;I2C 1602 LCD Specs (For device hex address)&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Background Information
&lt;/h2&gt;

&lt;p&gt;The reason I'm writing this is because most tutorials and guides out there are going to tell you how to use an Arduino and I wanted to change that with this post. In the industry arduino is &lt;em&gt;not&lt;/em&gt; the standard for everything, and aspiring students like me will sometimes be be expected to use devices where there are no premade solutions like the ones arduino offers. Sometimes we'll have no choice but to write our own driver. And so I wanted to simulate that struggle. I went down that route, and this is the knowledge I've gained from it.&lt;/p&gt;

&lt;p&gt;Now, when I was getting started with this thing, the biggest hurdle was this question… &lt;strong&gt;What do I actually write?&lt;/strong&gt;&lt;/p&gt;



&lt;p&gt;To answer that question, you need to know exactly what you’re working with first and what our code needs to do:&lt;/p&gt;

&lt;p&gt;Many &lt;strong&gt;LCD1602&lt;/strong&gt; modules come with a &lt;strong&gt;PCF8574 IO Expander&lt;/strong&gt; already soldered to the back of the unit. The &lt;strong&gt;LCD1602&lt;/strong&gt; has an &lt;strong&gt;HD44780U&lt;/strong&gt; microcontroller on board.&lt;/p&gt;

&lt;p&gt;The IO expander &amp;amp; i2c-dev header will allow us to implement I2C without having to handle the logic of the protocol ourselves. That leaves us with the relatively simple task of &lt;strong&gt;writing code that relays instructions to the LCD's microcontroller through the expander.&lt;/strong&gt; Here is a map of the expander’s pins &amp;amp; their roles in the context of our microcontroller:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fridye5x2yorid16o5zwd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fridye5x2yorid16o5zwd.png" alt=" " width="800" height="611"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 1: I2C LCD Adapter Schematic from &lt;a href="https://github.com/HvandeVen/PCF8574-Display" rel="noopener noreferrer"&gt;HvandeVen/PCF8574-Display&lt;/a&gt; on GitHub.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;Note: This is a common but not GUARANTEED mapping. Pin maps may vary.&lt;/em&gt;&lt;/p&gt;



&lt;p&gt;This schematic does some of the heavy lifting for us. In the image, it's clearly outlined which physical pin on the expander corresponds to what role it plays on the microcontroller. From the image &amp;amp; microcontroller's &lt;a href="https://cdn.sparkfun.com/assets/9/5/f/7/b/HD44780.pdf" rel="noopener noreferrer"&gt;datasheet&lt;/a&gt;, you can come up with the following table:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pin&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;P0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;RS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Register Select: 0 = Command, 1 = Data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;P1&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;RW&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Read/Write: 0 = Write, 1 = Read&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;P2&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;EN&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Enable: (Stage/Confirm Changes)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;P3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;BL&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Backlight: 1 = ON, 0 = OFF&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;P4&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;D4&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Data Bit 4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;P5&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;D5&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Data Bit 5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;P6&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;D6&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Data Bit 6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;P7&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;D7&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Data Bit 7&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Before moving on I want to make two crucial clarifications:&lt;/p&gt;

&lt;p&gt;1.) The PCF8574 only has 8 physical pins as shown by the table above. The first 4 of which are &lt;em&gt;always&lt;/em&gt; allocated to what I call "byte control", meaning they only refer to specific actions the LCD is going to perform. The remaining pins (D4-D7) are the pins we're going to use to send information. Think of each byte we send like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;DATA&lt;/span&gt; &lt;span class="n"&gt;CTRL&lt;/span&gt; &lt;span class="c1"&gt;// Four data bits, Four control bits&lt;/span&gt;
&lt;span class="mo"&gt;0000&lt;/span&gt; &lt;span class="mo"&gt;0000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2.) Because of this limitation, we're going to be using the LCD in a 4-bit mode, meaning it will expect 4 data bits at a time.&lt;/p&gt;

&lt;p&gt;However, that does not mean the data the LCD expects is 4-bit. The LCD's internal system will automatically &lt;em&gt;wait&lt;/em&gt; until it has received 2 sets of 4 &lt;em&gt;data&lt;/em&gt; bits before considering the communication complete and printing a new letter to the screen. The idea is that the control bits are discarded and the 4 data bits from both instructions are combined into a single 8-bit byte which then represents a full letter.&lt;/p&gt;




&lt;h2&gt;
  
  
  How communication works &amp;amp; building instructions
&lt;/h2&gt;

&lt;p&gt;Using the &lt;a href="https://www.kernel.org/doc/html/v5.4/i2c/dev-interface.html" rel="noopener noreferrer"&gt;i2c-dev header&lt;/a&gt;, you send one byte (8 bits) at a time to the IO expander. Each byte is a set of instructions telling the expander exactly which pins should be ON (1) or OFF (0).&lt;/p&gt;

&lt;p&gt;We use these 8 physical pins to send information. Think of it like this: Each pin state corresponds to a bit in that byte, we're using a controller with 8 buttons that can each be toggled on or off. We send instructions to toggle those buttons (turning a pin ON or OFF) and then take a snapshot of the pin state and send that information as an instruction.&lt;/p&gt;

&lt;p&gt;It’s not practical to manually synthesize binary for every instruction though. So to make this efficient, we treat the pins as their own bytes and abstract away the actual binary into variables. This way, we can use bitmasking to build the instructions we'll be sending to the LCD.&lt;/p&gt;

&lt;p&gt;In my code, I chose to do it like this above my main function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// CONTROL PINS&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;PIN0_RS&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mb"&gt;0b00000001&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;PIN1_RW&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mb"&gt;0b00000010&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt; &lt;span class="c1"&gt;// usually remains 0&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;PIN2_EN&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mb"&gt;0b00000100&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt; 
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;PIN3_BL&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mb"&gt;0b00001000&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt; &lt;span class="c1"&gt;// 1 for ON, 0 for OFF&lt;/span&gt;

&lt;span class="c1"&gt;// DATA PINS&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;PIN4_D4&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mb"&gt;0b00010000&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;PIN5_D5&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mb"&gt;0b00100000&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;PIN6_D6&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mb"&gt;0b01000000&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;PIN7_D7&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mb"&gt;0b10000000&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// More declarations later...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;I used binary literals here because when you're mapping software bits to physical GPIO pins on an expander, binary is more readable than Hex. No one wants to do extra math when referencing pins. And abstracting away hex, an abstraction of binary, is redundant in and of itself.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Now that we've abstracted our pins away, we can use some bitwise "OR" operations ( | ) to build instructions from the ground up. Here's an example of what that would look like now that we have our variables:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;uint8_t instruction&lt;/code&gt; = &lt;code&gt;PIN4_D4&lt;/code&gt; | &lt;code&gt;PIN0_RS&lt;/code&gt; | &lt;code&gt;PIN3_BL&lt;/code&gt;;&lt;/p&gt;

&lt;p&gt;There are two crucial pieces of logic that you need to understand before you can begin building instructions:&lt;/p&gt;

&lt;p&gt;First, take a look at the type. All your instructions need to be &lt;em&gt;8-bit unsigned integer types&lt;/em&gt;. An empty instruction byte, for example, should look like this: &lt;code&gt;0000 0000&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The second thing you need to understand is bitmasking with the "OR" ( | ) operator. Since you've abstracted each pin to a specific name, you can layer them one on top of the other to create a single instruction. It looks something like this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;0001 0000&lt;/code&gt; -&amp;gt; &lt;code&gt;PIN4_D4&lt;/code&gt;&lt;br&gt;
&lt;code&gt;0000 0001&lt;/code&gt; -&amp;gt; &lt;code&gt;PIN0_RS&lt;/code&gt;&lt;br&gt;
&lt;code&gt;0000 1000&lt;/code&gt; -&amp;gt; &lt;code&gt;PIN3_BL&lt;/code&gt;&lt;br&gt;
----------- +&lt;br&gt;
&lt;code&gt;0001 1001&lt;/code&gt; -&amp;gt; &lt;code&gt;instruction&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This is what the ( | ) operator does: it takes two or more bytes and returns a singular byte where a bit is set to 1 if it was 1 in any of the original bytes, effectively combining 3 instruction bytes into 1 instruction. The result &lt;code&gt;0001 1001&lt;/code&gt; is actually the result of the snippet I showed you before:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;uint8_t instruction&lt;/code&gt; = &lt;code&gt;PIN4_D4&lt;/code&gt; | &lt;code&gt;PIN0_RS&lt;/code&gt; | &lt;code&gt;PIN3_BL&lt;/code&gt;;&lt;/p&gt;

&lt;p&gt;If you wanted to turn a pin off, you simply just wouldn't include it in the next instruction. For example:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;uint8_t instruction&lt;/code&gt; = &lt;code&gt;PIN4_D4&lt;/code&gt; | &lt;code&gt;PIN0_RS&lt;/code&gt;; -&amp;gt; Backlight turns off.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;THIS&lt;/strong&gt; is what we're going to be sending to the LCD. And now that you know the &lt;em&gt;what&lt;/em&gt;, we can get into the &lt;em&gt;how&lt;/em&gt;. I'm going to structure this into three main blocks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Opening your I2C device&lt;/li&gt;
&lt;li&gt;Setting the LCD to 4-bit mode&lt;/li&gt;
&lt;li&gt;Sending 4-bit instruction bytes&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Opening your I2C device
&lt;/h2&gt;

&lt;p&gt;Now we can get into some code. If you want a full reference to what this header can do, you can check the official documentation &lt;a href="https://www.kernel.org/doc/html/v5.4/i2c/dev-interface.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;fcntl.h&amp;gt;&lt;/span&gt;&lt;span class="c1"&gt;     // open files&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;sys/ioctl.h&amp;gt;&lt;/span&gt;&lt;span class="c1"&gt; // input/output for files&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;linux/i2c-dev.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;unistd.h&amp;gt;&lt;/span&gt;&lt;span class="c1"&gt;    // write(), usleep()&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="c1"&gt;// ... FUNCTION &amp;amp; CONSTANTS DECLARATIONS HERE&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="c1"&gt;// --- LCD ---&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"/dev/i2c-1"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i2c_adapter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c_str&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;O_RDWR&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i2c_adapter&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"Failed to open bus."&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// You can find the address hex value in your LCD's data sheet or if it's&lt;/span&gt;
&lt;span class="c1"&gt;// already connected via GPIO you can find it via the `i2cdetect -y 1`&lt;/span&gt;
&lt;span class="c1"&gt;// command in your terminal&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;lcd_address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0x27&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ioctl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i2c_adapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;I2C_SLAVE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lcd_address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"Failed to reach I2C slave."&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this block of code, I am opening a connection to the physical I2C hardware bus on my Pi via the device file &lt;code&gt;"/dev/i2c-1"&lt;/code&gt;. This returns a file descriptor I’ve named &lt;code&gt;i2c_adapter&lt;/code&gt;. We then use an &lt;code&gt;ioctl&lt;/code&gt; (Input/Output Control) call to tell the driver that all future communications on this bus should be directed to the slave device at address &lt;code&gt;0x27&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Essentially, every time we want to write information, we're going to pass this &lt;code&gt;i2c_adapter&lt;/code&gt; handle as a sort of guide. When we pass this handle to the &lt;code&gt;write&lt;/code&gt; function, it's like saying write information to the slave associated with this adapter. And so we can build our first function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ---- FUNCTIONS ----&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;pulse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i2c_adapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;pin_state&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="c1"&gt;// Stage our instructions by flipping the pin up:&lt;/span&gt;
    &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;up_instruction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PIN2_EN&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;pin_state&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i2c_adapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;up_instruction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;usleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Confirm instructions by flipping the pin down:&lt;/span&gt;
    &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;down_instruction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pin_state&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i2c_adapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;down_instruction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;usleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before I talk about the code, I should clarify: &lt;code&gt;PIN2_EN&lt;/code&gt; is a special pin whose role is something I like to compare to staging and committing changes.&lt;/p&gt;

&lt;p&gt;Basically, for the IO expander to actually acknowledge the changes in pin state, the EN pin needs to be toggled up and down. Once to get the expander to look at the change in pin state (staging) and again to confirm the change in pin state (committing). This process is commonly referred to as a pulse, hence the name of the function.&lt;/p&gt;

&lt;p&gt;Before we do that, we should make a couple more declarations above our main function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// CONTROL PINS&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;PIN0_RS&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mb"&gt;0b00000001&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;PIN1_RW&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mb"&gt;0b00000010&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt; &lt;span class="c1"&gt;// usually remains 0&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;PIN2_EN&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mb"&gt;0b00000100&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt; 
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;PIN3_BL&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mb"&gt;0b00001000&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt; &lt;span class="c1"&gt;// 1 for ON, 0 for OFF&lt;/span&gt;

&lt;span class="c1"&gt;// DATA PINS&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;PIN4_D4&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mb"&gt;0b00010000&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;PIN5_D5&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mb"&gt;0b00100000&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;PIN6_D6&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mb"&gt;0b01000000&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;PIN7_D7&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mb"&gt;0b10000000&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// STARTUP COMMANDS PRESETS:&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;S_FUNCTION_SET&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mb"&gt;0b00101000&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;S_DISPLAY_SET&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mb"&gt;0b00001100&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;S_CHAR_ENTRY_SET&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mb"&gt;0b00000110&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// OTHER:&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;CLEAR_DISPLAY&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mb"&gt;0b00000001&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;I've chosen to include these specific pin states because they're common values that will be used during startup/other processes, and if they need to be changed, it's more convenient to change them here than writing them inline. It helps for readability, too.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Setting the LCD to 4-bit mode
&lt;/h2&gt;

&lt;p&gt;By default, the LCD will be set to run in an 8-bit state. Because we only have 4 data pins to work with, we have to change that during the initialization process. On page 46 of the MCU's datasheet, you can find the following diagram:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fckm7sgrbpnybfutyle5a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fckm7sgrbpnybfutyle5a.png" alt="Page 46 MCU Datasheet" width="738" height="747"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;This diagram shows the order in which we should use our pulse method to send instructions and properly wake the device. That little red arrow is the instruction which sets the LCD to 4-bit operation.&lt;/p&gt;

&lt;p&gt;The formatting looks strange because the datasheet omits two of the irrelevant control bits, but you can safely ignore it and assume that they are zero. From there, all we have to do is simulate the wake-up instructions given by page 46 in code with our &lt;code&gt;pulse&lt;/code&gt; method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;wake_lcd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i2c_adapter&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;

    &lt;span class="c1"&gt;// Wake up the LCD and set it to receive 4-bit instructions&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;wake_up&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PIN4_D4&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;PIN5_D5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;set_4_bit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PIN5_D5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;pulse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i2c_adapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;wake_up&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;usleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;pulse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i2c_adapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;wake_up&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;usleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;pulse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i2c_adapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;wake_up&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;usleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;pulse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i2c_adapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;set_4_bit&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Now that you have that complete, your main function should look a little something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;fcntl.h&amp;gt;&lt;/span&gt;&lt;span class="c1"&gt;     &lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;sys/ioctl.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;linux/i2c-dev.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;unistd.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"/dev/i2c-1"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i2c_adapter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c_str&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;O_RDWR&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i2c_adapter&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"Failed to open bus."&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;lcd_address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0x27&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ioctl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i2c_adapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;I2C_SLAVE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lcd_address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"Failed to reach I2C slave."&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;wake_lcd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i2c_adapter&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And at that point, you're almost done; the LCD is ready to be instructed via 4-bit operations. We just have to write one last crucial function before you can intuitively create more abstractions on your own. The last function we need to make is a 4-bit &lt;code&gt;send_byte&lt;/code&gt; method. I chose to do this using bit-shifting.&lt;/p&gt;




&lt;h2&gt;
  
  
  Sending 4-bit instruction bytes
&lt;/h2&gt;

&lt;p&gt;Recall what our instruction bytes should look like in 4-bit operation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;DATA&lt;/span&gt; &lt;span class="n"&gt;CTRL&lt;/span&gt; &lt;span class="c1"&gt;// Four data bits, Four control bits&lt;/span&gt;
&lt;span class="mo"&gt;0000&lt;/span&gt; &lt;span class="mo"&gt;0000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Like I said before, the first 4 bits of an instruction will ALWAYS be interpreted as control bytes; however, this causes problems because our letters will be in 8-bit format. Our solution is to send 2 instructions in one method. We're going to break up a letter into two halves and send them separately. The LCD will discard the control bits and only take the data bits.&lt;/p&gt;

&lt;p&gt;So here's how we're gonna do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;HALF2&lt;/span&gt; &lt;span class="n"&gt;HALF1&lt;/span&gt; &lt;span class="c1"&gt;// This is the binary representation of the letter H.&lt;/span&gt;
&lt;span class="mo"&gt;0100&lt;/span&gt;  &lt;span class="mi"&gt;1000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To implement this, we'll pass one letter to the function at a time and call it an instruction. We're going to apply bitmasking to the instruction. We're going to bit-shift the first 4-bits of the letter to the left such that we lose the latter half of the letter and we have space for both the first half of the letter and the control bits:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;DATA&lt;/span&gt;
&lt;span class="n"&gt;HALF1&lt;/span&gt; &lt;span class="n"&gt;CTRL&lt;/span&gt; &lt;span class="c1"&gt;// This is half the representation of the letter H.&lt;/span&gt;
&lt;span class="mi"&gt;1000&lt;/span&gt;  &lt;span class="mo"&gt;0000&lt;/span&gt; &lt;span class="c1"&gt;// The first half is shifted left to the data columns&lt;/span&gt;

&lt;span class="n"&gt;DATA&lt;/span&gt;
&lt;span class="n"&gt;HALF2&lt;/span&gt; &lt;span class="n"&gt;CTRL&lt;/span&gt; &lt;span class="c1"&gt;// This is the other half of the representation of the letter H.&lt;/span&gt;
&lt;span class="mo"&gt;0100&lt;/span&gt;  &lt;span class="mo"&gt;0000&lt;/span&gt; &lt;span class="c1"&gt;// The second half is already in position so nothing changes.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll then merge the basic instructions for writing a letter with the halves of the letters and send them as 2 sets of instructions. Here's how I implemented that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;send_byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i2c_adapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;rs_mode&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;half_one&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="mb"&gt;0b11110000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;PIN3_BL&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;rs_mode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;pulse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i2c_adapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;half_one&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;half_two&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="mb"&gt;0b11110000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;PIN3_BL&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;rs_mode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;pulse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i2c_adapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;half_two&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So what's happening? This function takes 2 new arguments: the &lt;code&gt;value&lt;/code&gt; or letter we intend to send in its 8-bit format, and another value &lt;code&gt;rs_mode&lt;/code&gt;.&lt;br&gt;
That argument refers to the state of &lt;code&gt;PIN0_RS&lt;/code&gt;. If you don't remember its function, here it is:&lt;br&gt;
&lt;code&gt;| P0 | RS | Register Select: 0 = Command, 1 = Data |&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In the cases where we're sending normal letter information, we'll be setting &lt;code&gt;rs_mode = 1&lt;/code&gt;. Otherwise, if we're working with the LCD's other functions (not covered by this post), we'd use 0.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;&amp;amp;&lt;/code&gt; operator filters out the first 4 bits of the given value and replaces them with our preset LCD actions (keeping the backlight on and giving an RS value). The bit-shifting allows us to use the same value except for different parts of it, as described before.&lt;/p&gt;

&lt;p&gt;We pulse both of those manipulated instructions and just like that, we've sent a value.&lt;/p&gt;

&lt;p&gt;With the &lt;code&gt;send_byte&lt;/code&gt; function finished we can expand our wake_lcd function to include the initialization steps for the LCD with the additional declarations we made before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;wake_lcd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i2c_adapter&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;

    &lt;span class="c1"&gt;// Wake up the LCD and set it to receive 4-bit instructions&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;wake_up&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PIN4_D4&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;PIN5_D5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;set_4_bit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PIN5_D5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;pulse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i2c_adapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;wake_up&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;usleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;15000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;pulse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i2c_adapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;wake_up&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;usleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;pulse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i2c_adapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;wake_up&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;usleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;pulse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i2c_adapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;set_4_bit&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Initialization:&lt;/span&gt;
&lt;span class="c1"&gt;// STARTUP ORDER: check page 23 for the values associated with each byte command shown here&lt;/span&gt;
    &lt;span class="c1"&gt;// 1.) FUNCTION SET&lt;/span&gt;
    &lt;span class="c1"&gt;// 2.) DISPLAY ON/OFF CONTROL&lt;/span&gt;
    &lt;span class="c1"&gt;// 3.) ENTRY MODE SET&lt;/span&gt;
    &lt;span class="c1"&gt;// 4.) CLEAR DISPLAY&lt;/span&gt;
    &lt;span class="c1"&gt;// --- READY FOR USE ---&lt;/span&gt;

    &lt;span class="c1"&gt;// Because we're sending an LCD command, rs_mode set to 0.&lt;/span&gt;
     &lt;span class="n"&gt;send_byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i2c_adapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;S_FUNCTION_SET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
     &lt;span class="n"&gt;send_byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i2c_adapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;S_DISPLAY_SET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
     &lt;span class="n"&gt;send_byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i2c_adapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;S_CHAR_ENTRY_SET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
     &lt;span class="n"&gt;send_byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i2c_adapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CLEAR_DISPLAY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;By the end of all this, if you're following along, this is how your main function should look so far:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;fcntl.h&amp;gt;&lt;/span&gt;&lt;span class="c1"&gt;     // open files&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;sys/ioctl.h&amp;gt;&lt;/span&gt;&lt;span class="c1"&gt; // input/output for files&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;linux/i2c-dev.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;unistd.h&amp;gt;&lt;/span&gt;&lt;span class="c1"&gt;    // write(), usleep()&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;&lt;span class="c1"&gt;      // Needed for std::string&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="c1"&gt;// --- CONSTANTS (Global scope so they are accessible to all functions) ---&lt;/span&gt;

&lt;span class="c1"&gt;// CONTROL PINS&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;PIN0_RS&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mb"&gt;0b00000001&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;PIN1_RW&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mb"&gt;0b00000010&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt; &lt;span class="c1"&gt;// usually remains 0&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;PIN2_EN&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mb"&gt;0b00000100&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt; 
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;PIN3_BL&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mb"&gt;0b00001000&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt; &lt;span class="c1"&gt;// 1 for ON, 0 for OFF&lt;/span&gt;

&lt;span class="c1"&gt;// DATA PINS&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;PIN4_D4&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mb"&gt;0b00010000&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;PIN5_D5&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mb"&gt;0b00100000&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;PIN6_D6&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mb"&gt;0b01000000&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;PIN7_D7&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mb"&gt;0b10000000&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// STARTUP COMMANDS PRESETS:&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;S_FUNCTION_SET&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mb"&gt;0b00101000&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;S_DISPLAY_SET&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mb"&gt;0b00001100&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;S_CHAR_ENTRY_SET&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mb"&gt;0b00000110&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// OTHER:&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;CLEAR_DISPLAY&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mb"&gt;0b00000001&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// ---- FUNCTIONS ----&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;pulse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i2c_adapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;pin_state&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="c1"&gt;// Stage our instructions by flipping the pin up:&lt;/span&gt;
    &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;up_instruction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PIN2_EN&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;pin_state&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i2c_adapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;up_instruction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;usleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Confirm instructions by flipping the pin down:&lt;/span&gt;
    &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;down_instruction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pin_state&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i2c_adapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;down_instruction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;usleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;send_byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i2c_adapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;rs_mode&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="c1"&gt;// Capture the high half (bits 7,6,5,4) and add control bits&lt;/span&gt;
    &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;half_one&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="mb"&gt;0b11110000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;PIN3_BL&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;rs_mode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;pulse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i2c_adapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;half_one&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Shift the low half (bits 3,2,1,0) into the high position (bits 7,6,5,4) &lt;/span&gt;
    &lt;span class="c1"&gt;// This is required because physical pins D4-D7 are on the expander's high pins&lt;/span&gt;
    &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;half_two&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="mb"&gt;0b11110000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;PIN3_BL&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;rs_mode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;pulse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i2c_adapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;half_two&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Clear display needs extra time (about 2ms) to finish internal processing&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;CLEAR_DISPLAY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;usleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;wake_lcd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i2c_adapter&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="c1"&gt;// Wake up the LCD and set it to receive 4-bit instructions&lt;/span&gt;
    &lt;span class="c1"&gt;// We send 0b0011 (3) in the data slots to reset the controller interface&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;wake_up&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PIN4_D4&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;PIN5_D5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;set_4_bit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PIN5_D5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;pulse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i2c_adapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;wake_up&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;usleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;15000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
    &lt;span class="n"&gt;pulse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i2c_adapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;wake_up&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;usleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;pulse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i2c_adapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;wake_up&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;usleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;pulse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i2c_adapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;set_4_bit&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Initialization:&lt;/span&gt;
    &lt;span class="c1"&gt;// STARTUP ORDER: check page 23 for the values associated with each byte command&lt;/span&gt;
    &lt;span class="c1"&gt;// 1.) FUNCTION SET&lt;/span&gt;
    &lt;span class="c1"&gt;// 2.) DISPLAY ON/OFF CONTROL&lt;/span&gt;
    &lt;span class="c1"&gt;// 3.) ENTRY MODE SET&lt;/span&gt;
    &lt;span class="c1"&gt;// 4.) CLEAR DISPLAY&lt;/span&gt;

    &lt;span class="c1"&gt;// Because we're sending an LCD command, rs_mode set to 0.&lt;/span&gt;
    &lt;span class="n"&gt;send_byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i2c_adapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;S_FUNCTION_SET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;send_byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i2c_adapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;S_DISPLAY_SET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;send_byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i2c_adapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;S_CHAR_ENTRY_SET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;send_byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i2c_adapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CLEAR_DISPLAY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="c1"&gt;// --- LCD ---&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"/dev/i2c-1"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i2c_adapter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c_str&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;O_RDWR&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i2c_adapter&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"Failed to open bus."&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// You can find the address hex value in your LCD's data sheet&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;lcd_address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0x27&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ioctl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i2c_adapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;I2C_SLAVE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lcd_address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"Failed to reach I2C slave."&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;wake_lcd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i2c_adapter&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Usually we'll have rs_mode set to 1 since we're sending data&lt;/span&gt;
    &lt;span class="c1"&gt;// Sending the character 'H' (Binary: 0100 1000)&lt;/span&gt;
    &lt;span class="n"&gt;send_byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i2c_adapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;'H'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PIN0_RS&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;send_byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i2c_adapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;'I'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PIN0_RS&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;send_byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i2c_adapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;'!'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PIN0_RS&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i2c_adapter&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you've reached this point you've officially bridged the point between datasheet and code that actually communicates with the LCD. &lt;/p&gt;

&lt;p&gt;If you go ahead and compile this (if all goes well) it should print the message "HI!". If you want to take it a step further and build a function to send full strings at a time you can do that using the send_byte function under the hood. Here's a simple way you could do that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;
  &lt;span class="c1"&gt;// Note that this doesn't cover edgecases.&lt;/span&gt;
  &lt;span class="c1"&gt;// Just meant to be an example for sending full strings.&lt;/span&gt;
  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;send_msg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i2c_adapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;character&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;  
            &lt;span class="n"&gt;send_byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i2c_adapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;character&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;That's pretty much it. If you followed along this far, thank you for reading. &lt;/p&gt;

&lt;p&gt;I want to make it apparent again that this is NOT a definitive guide on everything you can do with the LCD, and a likely didn't use any of the best practices either. I'm just trying to share what I learned in the hope I this post can be a reference point to someone else starting out with the same device. &lt;/p&gt;

&lt;p&gt;I'm self taught and still very new to embedded systems, so if you have any suggestions or spot any glaring errors I'm happy to acknowledge them!&lt;/p&gt;

</description>
      <category>programming</category>
      <category>learning</category>
      <category>cpp</category>
      <category>embedded</category>
    </item>
  </channel>
</rss>
