--- /dev/null
+#define RS 12
+#define EN 11
+#define D4 5
+#define D5 4
+#define D6 3
+#define D7 2
+
+#define COLS 16
+#define ROWS 2
+
+void lcd_cmd(uint8_t _data, bool _type);
+void lcd_init(void);
+void lcd_set_cursor(uint8_t col, uint8_t row);
+void lcd_show_char(char chr);
+void lcd_show_text(char *text, uint8_t len);
+void lcd_show_text_vmks(void);
+
+void setup() {
+ // Initialize LCD screen and IF GPIO
+ lcd_init();
+
+ // Center the text on the second line => Move cursor to
+ // (second line offset + half the line size - half the text size)
+ // (0x40 + 16/2 - 4/2) = (0x40 + 8 - 2) = (0x40 + 6) = 0x46
+ // Line 1 => 0x00 to 0x27
+ // Line 2 => 0x40 to 0x67
+ //lcd_cmd(B1100, 0); lcd_cmd(B0110, 0); // manually set DDRAM to cursor position = 0x46 = B 0100 0110
+ lcd_set_cursor(6, 2); // the same but using the function
+
+ // Show text
+ //lcd_show_text_vmks(); // Show hardcoded text "VMKS"
+ //lcd_show_char('T'); lcd_show_char('U'); lcd_show_char('E'); lcd_show_char('S');
+ lcd_show_text("VMKS", 4); // This is actually String object converting to char array but works for the demo
+}
+
+void loop() {
+ delay(5000);
+ lcd_cmd(B0000, 0); lcd_cmd(B0001, 0); delayMicroseconds(1530); // clear display - set all characters to space(' ') and return home
+ lcd_set_cursor(6, 1);
+ lcd_show_text_vmks();
+ lcd_set_cursor(6, 2);
+ lcd_show_char('T'); lcd_show_char('U'); lcd_show_char('E'); lcd_show_char('S');
+ while (1) {};
+}
+
+void lcd_init(void) {
+ // Set IF GPIO mode
+ pinMode(RS, OUTPUT);
+ pinMode(EN, OUTPUT);
+ pinMode(D4, OUTPUT);
+ pinMode(D5, OUTPUT);
+ pinMode(D6, OUTPUT);
+ pinMode(D7, OUTPUT);
+
+ // LCD Power-On Reset (POR) initialization wait
+ delay(40);
+
+ // Initialize controller HD44780
+ lcd_cmd(B0010, 0); // lcd_cmd(B1000, 0); delayMicroseconds(39); // Function set => 4-bit data bus mode, 1-line, 5x8 dots
+ lcd_cmd(B0010, 0); lcd_cmd(B1000, 0); delayMicroseconds(39); // Function set => 4-bit data bus mode, 2-line, 5x8 dots
+ lcd_cmd(B0000, 0); lcd_cmd(B0001, 0); delayMicroseconds(1530); // clear display - set all characters to space(' ') and return home
+ lcd_cmd(B0000, 0); lcd_cmd(B1100, 0); delayMicroseconds(39); // turn display on
+ lcd_cmd(B0000, 0); lcd_cmd(B0010, 0); delayMicroseconds(1530); // return home - move cursor to begining of first line
+ lcd_cmd(B0000, 0); lcd_cmd(B0110, 0); delayMicroseconds(39); // entry mode set = left-justified, left-to-right, no shift text
+}
+
+// There is no parameter validation
+// COL and ROW start from 1
+void lcd_set_cursor(uint8_t col, uint8_t row) {
+ uint8_t row_offset[2] = {0x00, 0x40};
+ uint8_t pos = (col) + row_offset[row - 1];
+ pos = (pos & 0x7F) | 0x80; // Add cursor position change command code
+ uint8_t upper = (pos & 0xF0) >> 4;
+ uint8_t lower = (pos & 0x0F) >> 0;
+ lcd_cmd(upper, 0); lcd_cmd(lower, 0);
+}
+
+// Send ASCII char
+void lcd_show_char(char chr) {
+ uint8_t upper = ((uint8_t)chr & 0xF0) >> 4;
+ uint8_t lower = ((uint8_t)chr & 0x0F) >> 0;
+
+ lcd_cmd(upper, 1); lcd_cmd(lower, 1);
+}
+
+// Send ASCII text
+void lcd_show_text(char *text, uint8_t len) {
+ for (uint8_t cnt = 0; cnt < len; cnt++) {
+ lcd_show_char(text[cnt]);
+ }
+}
+
+// Send hardcoded ASCII text "VMKS"
+void lcd_show_text_vmks(void) {
+ lcd_cmd(B0101, 1); lcd_cmd(B0110, 1); // V = 0x56 = B 0101 0110
+ lcd_cmd(B0100, 1); lcd_cmd(B1101, 1); // M = 0x4D = B 0100 1101
+ lcd_cmd(B0100, 1); lcd_cmd(B1011, 1); // K = 0x4B = B 0100 1011
+ lcd_cmd(B0101, 1); lcd_cmd(B0011, 1); // S = 0x53 = B 0101 0011
+}
+
+// Data = 4-bit data to send (use lower 4 bits)
+// Type 0 = Instruction || Type 1 = Data
+// example delays are only to show the idea - they really should be in [ns] but there is no such function
+void lcd_cmd(uint8_t _data, bool _type) {
+ // Set RS
+ digitalWrite(RS, _type);
+
+ // Set Data value
+ digitalWrite(D4, (_data & 0x01));
+ digitalWrite(D5, (_data & 0x02));
+ digitalWrite(D6, (_data & 0x04));
+ digitalWrite(D7, (_data & 0x08));
+
+ // Time to select the register
+ delayMicroseconds(120);
+ // Data setup time = 60~90ns after the above delay
+ // In this example data is already set before that
+
+ // Pulse Enable
+ digitalWrite(EN, HIGH);
+ delayMicroseconds(320); // Enable pulse duration
+ digitalWrite(EN, LOW);
+
+ // Wait
+ delayMicroseconds(30); // Data hold time
+}
--- /dev/null
+#define RS 12
+#define EN 11
+#define D4 5
+#define D5 4
+#define D6 3
+#define D7 2
+
+#define COLS 16
+#define ROWS 2
+
+void setup() {
+ // Initialize LCD screen and IF GPIO
+ lcd_init();
+
+ // Show hardcoded text "VMKS"
+ lcd_show_text_vmks();
+}
+
+void loop() {
+ // put your main code here, to run repeatedly:
+}
+
+void lcd_init() {
+ // Set IF GPIO mode
+ pinMode(RS, OUTPUT);
+ pinMode(EN, OUTPUT);
+ pinMode(D4, OUTPUT);
+ pinMode(D5, OUTPUT);
+ pinMode(D6, OUTPUT);
+ pinMode(D7, OUTPUT);
+
+ // LCD Power-On Reset (POR) initialization wait
+ delay(40);
+
+ // Initialize controller HD44780
+ lcd_cmd(B0010, 0); // Function set => 4-bit data bus mode, 1-line, 5x8 dots
+ lcd_cmd(B0000, 0); lcd_cmd(B0001, 0); // clear display - set all characters to space(' ') and return cursor to begining of first row (return home)
+ lcd_cmd(B0000, 0); lcd_cmd(B1100, 0); // turn display on
+}
+
+// Send ASCII text "VMKS"
+void lcd_show_text_vmks() {
+ lcd_cmd(B0101, 1); lcd_cmd(B0110, 1); // V = 0x56 = B 0101 0110
+ lcd_cmd(B0100, 1); lcd_cmd(B1101, 1); // M = 0x4D = B 0100 1101
+ lcd_cmd(B0100, 1); lcd_cmd(B1011, 1); // K = 0x4B = B 0100 1011
+ lcd_cmd(B0101, 1); lcd_cmd(B0011, 1); // S = 0x53 = B 0101 0011
+}
+
+// Data = 4-bit data to send (use lower 4 bits)
+// Type 0 = Instruction || Type 1 = Data
+void lcd_cmd(uint8_t _data, bool _type) {
+ // Set RS
+ digitalWrite(RS, _type);
+
+ // Set Data value
+ digitalWrite(D4, (_data & 0x01));
+ digitalWrite(D5, (_data & 0x02));
+ digitalWrite(D6, (_data & 0x04));
+ digitalWrite(D7, (_data & 0x08));
+
+ // Time to select the register
+ delayMicroseconds(120);
+ // Data setup time = 60~90ns after the above delay
+ // In this example data is already set before that
+
+ // Pulse Enable
+ digitalWrite(EN, HIGH);
+ delayMicroseconds(320); // Enable pulse duration
+ digitalWrite(EN, LOW);
+
+ // Wait
+ delayMicroseconds(30); // Data hold time
+}
--- /dev/null
+lcd.begin(COLS,ROWS,LCD_5x8DOTS)
+
+VMKS
+
+V = 0x56 = B 0101 0110
+M = 0x4D = B 0100 1101
+K = 0x4B = B 0100 1011
+S = 0x53 = B 0101 0011
+
+Steps to send command:
+0. Set RS
+1. Set Data value
+2. Wait >=100ns
+3. Set E high
+4. Wait >=300ns (can alse use this time to set Data value)
+5. Set E low
+6. Wait >=10ns
+7. Can change Data and repeat
+
+Steps to show text - from YouTube video:
+1. Set 4-bit mode and 1-line
+2. Clear display
+3. Return home
+4. Turn display on
+5. Send text in ASCII
+
+==================================================
+
+Steps to initialise the screen - from the library:
+1. Set 4-bit 2-line 5x8-dot mode
+2. Turn display-on, cursor-off, blinking-off
+3. Clear display
+4. Set autoincrement left-to-right, left-justified
+
+// When the display powers up, it is configured as follows:
+//
+// 1. Display clear
+// 2. Function set:
+// DL = 1; 8-bit interface data
+// N = 0; 1-line display
+// F = 0; 5x8 dot character font
+// 3. Display on/off control:
+// D = 0; Display off
+// C = 0; Cursor off
+// B = 0; Blinking off
+// 4. Entry mode set:
+// I/D = 1; Increment by 1
+// S = 0; No shift
+//
+// Note, however, that resetting the Arduino doesn't reset the LCD, so we
+// can't assume that its in that state when a sketch starts (and the
+// LiquidCrystal constructor is called).