Hi there. I've been trying to get this LCD module up and running. It's a backlit, 12-pin model with 4-bit operation mode only.
Arduino Model: Arduino Uno WiFi Rev2 (Atmega 4809)
LCD Model: NHD-0108HZ-FSW-GBW
Controller: ST7066U
Link to Datasheet [PDF]
Link to Setup Images [Imgur.com]
I am only using the Arduino to prototype and test the LCD we are using for a larger embedded device later on. The LCD uses +3.3V power supply for logic and backlight LED, not +5V.
Using the Arduino LiquidCrystal.h library produced very weird and inconsistent results. Ultimately, I will be using this LCD in an embedded device, so felt it would be worthwhile to abandon the arduino library now since I will have to program it 'manually' later on the device. I figured this wouldn't be a straightforward endeavor, but at this point I'm getting nowhere in trying to diagnose why this isn't working on my own. This is my first attempt at programming an LCD in this manner, and interpreting the data sheet proved to be difficult, so I'm sure there are some gaps in my understanding that hopefully some of you may be able to point out.
My code is posted below. I tried to adapt it best to fit the example 4-bit initialization program provided in both linked datasheets. I used analogWrite() to make the DB pins 3.3V instead of 5, but not sure if this actually is viable. Regardless, running the program below produces a blank display.
const int volts = ((3.3/5.0)*255);
//const int volts = 200;
const int RS = 3;
const int EN = 2;
const int D4 = 5;
const int D5 = 6;
const int D6 = 9;
const int D7 = 10;
const int BACKLIGHT = 11;
int ct = 0;
char buffer[40];
char tempStr[10];
void setup()
{
Serial.begin(115200);
while(!Serial) {
; // Wait for serial to connect
}
Serial.print("Starting Program ~ \n");
pinMode(BACKLIGHT, OUTPUT);
pinMode(RS, OUTPUT);
pinMode(EN, OUTPUT);
pinMode(D4, OUTPUT);
pinMode(D5, OUTPUT);
pinMode(D6, OUTPUT);
pinMode(D7, OUTPUT);
analogWrite(BACKLIGHT, volts);
// Set all pins to low to reset/init device
putData(0x00);
putData(0x00);
delay(100); // Wait > 40ms after power is supplied
Serial.println("\nWake Up Sequence\n-------------------");
Serial.flush();
putData(0x30); // Put wake up command on data port
delay(30);
Nybble(); // wake up #1
delay(10);
Nybble(); // wake up #2
delay(10);
Nybble(); // wake up #3
delay(10);
Serial.println("\nSet 4-bit Operation\n----------------");
Serial.flush();
putData(0x20); // Put 4bit operation mode
Nybble();
Serial.println("\nSet 4-bit 2 Rows\n----------------");
Serial.flush();
cmd(0x28); // Set 4-bit 2 rows
Serial.println("\nSet Cursor\n----------------");
Serial.flush();
cmd(0x10); // Set cursor
Serial.println("\nDisplay ON; Blinking Cursor\n----------------");
Serial.flush();
cmd(0x0F); // Display ON; Blinking cursor
Serial.println("\nSet Entry Mode\n----------------");
Serial.flush();
cmd(0x06); // Entry mode set
delay(2000);
lcdWrite('h');
}
void loop() {
}
// Low Level LCD Commands
void putData (uint8_t c)
{
uint8_t binArr[8];
for (uint8_t i = 0; i < 8; i++) {
binArr[7-i] = c & (1 << i);
}
for (uint8_t i = 0; i < 4; i++) {
if (i == 0) {
analogWrite(D7, ((binArr[i] == 0) ? 0 : volts));
} else if (i == 1) {
analogWrite(D6, ((binArr[i] == 0) ? 0 : volts));
}
else if (i == 2) {
analogWrite(D5, ((binArr[i] == 0) ? 0 : volts));
} else {
analogWrite(D4, ((binArr[i] == 0) ? 0 : volts));
}
}
}
void Nybble() {
digitalWrite(EN, HIGH);
delay(2); // Enable pulse width >= 1200 ns
digitalWrite(EN, LOW); // Clock enable: falling edge -> Sends data in output port (D4 - D7)
}
void cmd (char c)
{
digitalWrite(RS, LOW); // RS=LOW: For sending instructions
putData(c); // Put first nybble on output port
// RW = 0 // RW pin not used - always low because connected to ground
Nybble(); // Send first nybble (4 bits) of data to LCD
c = c << 4; // Shift char by 4 bits so next nybble gets loaded into data pins (4 bit mode only)
putData(c); // Put last nybble on output port
Nybble(); // Send last nybble (4 bits) of data to LCD
}
void lcdWrite (char c) {
analogWrite(RS, volts); // RS=HIGH: Send data
putData(c); // Put first nybble on output port
// RW = 0 // RW pin not used
Nybble(); // Send first nybble to LCD
c = c << 4; // Bit shift char by 4 bits so next nybble gets loaded into data pins
putData(c); // Put last nybble on output port
Nybble(); // Send last nybble to LCD
}