Hd44780 decoder

The code is an Arduino-based implementation which intercepts and decodes data intended for an HD44780 LCD screen operating in 4-bit mode. The key use case is to allow you to monitor the data being sent to the LCD, which can be especially useful for troubleshooting, debugging, or enhancing functionality of systems where you don't have direct control over the software that is driving the LCD.

In the setup function, we initialize the Serial communication, define the control and data pins as input and setup an interrupt which is triggered on the falling edge of the EN (Enable) pin. The control pins include RS (Register Select), RW (Read/Write) and EN (Enable) pins.

The loop function checks whether the data is ready to be read. If it is, it prints the corresponding ASCII character to the Serial port and resets the data ready flag.

The readData function, which is called when the interrupt is triggered, first checks if the operation is a write operation and if data is being sent. If it is, it reads the 4-bit part of data from the data pins.

Note: This code assumes that all operations are write operations, i.e., data is always being sent to the LCD. If the device also reads from the LCD, modifications would be needed to handle those operations properly.

// HD44780 DECODER, WRITTEN BY LEONARDO MARTINS 19/01/2019

#define RS_PIN 12 // RS (Register Select) pin
#define RW_PIN 11 // RW (Read/Write) pin
#define EN_PIN 13 // EN (Enable) pin
#define DATA_PINS {33, 32, 35, 34} // Data pins D4, D5, D6 and D7

bool previousEn = LOW; // Previous state of the EN pin
volatile byte data = 0; // Storage for data
volatile bool dataReady = false; // Flag to indicate when data is ready to read
volatile bool highBits = true; // Flag to indicate if we are reading high or low bits

void setup() {
  Serial.begin(9600); // Start serial communication

  // Set control pins as input
  pinMode(RS_PIN, INPUT);
  pinMode(RW_PIN, INPUT);
  pinMode(EN_PIN, INPUT);

  // Set data pins as input
  int dataPins[] = DATA_PINS;
  for (int i = 0; i < 4; i++) {
    pinMode(dataPins[i], INPUT_PULLUP);
  }

  // Setup the interrupt
  attachInterrupt(digitalPinToInterrupt(EN_PIN), readData, FALLING);
}

void loop() {
  if (dataReady) {
    // Print the corresponding ASCII character to the Serial
    Serial.print((char)data);
    dataReady = false; // Reset the data ready flag
  }
}

void readData() {
  // Check if it's a write operation (RW == 0) and data is being sent (RS == 1)
  if (digitalRead(RS_PIN) == HIGH) {
    // Read the 4-bit part of data
    int dataPins[] = DATA_PINS;
    byte part = 0;
    for (int i = 0; i < 4; i++) {
      part |= digitalRead(dataPins[i]) << i;
    }

    if (highBits) {
      // This is the high bits part
      data = part << 4;
    } else {
      // This is the low bits part
      data |= part;
      dataReady = true; // Indicate that data is ready to read
    }

    // Flip the highBits flag
    highBits = !highBits;
  }
}

I guess it's not a question and you are sharing something working, right?
May be it would be a better fit into the Device Hacking - Arduino Forum category?

I have placed @leonardo1976's decoder into a simulation.

The simulation sketch originally was a demo from the boys at wokwi. I wondered if the decoder could run on the same Arduino board as the LCD project it was, um, decoding.

I had to make the ISR hold multiple data bytes, but it appears to work.


Wokwi_badge HD74480Decoder Demo


// https://forum.arduino.cc/t/hd44780-decoder/1143429
// https://wokwi.com/projects/369059701985585153

// LCD2004 Tiny Pacman on Wokwi

#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 27, 29, 31, 33);

uint8_t pacman[8] = {
  0b00000,
  0b00000,
  0b01110,
  0b11011,
  0b11111,
  0b01110,
  0b00000,
  0b00000
};

uint8_t pacmanOpen[] = {
  0b00000,
  0b00000,
  0b01110,
  0b11011,
  0b11100,
  0b01110,
  0b00000,
  0b00000
};

uint8_t dot[] = {
  0b00000,
  0b00000,
  0b00000,
  0b00110,
  0b00110,
  0b00000,
  0b00000,
  0b00000
};

void setup() {
  lcd.createChar(1, pacman);
  lcd.createChar(2, dot);
  lcd.begin(20, 4);
  lcd.setCursor(3, 0);
  lcd.print("wokwi-lcd2004");
  lcd.setCursor(2, 2);
  lcd.print("4 lines, 20 cols");

  decoderSetup();
}

void loop() {
  for (int i = 3; i < 16; i++) {
    lcd.setCursor(i, 3);
    lcd.print("\1");
    for (int j = i + 1; j < 16; j++) {
      lcd.setCursor(j, 3);
      lcd.print("\2");
    }
    lcd.createChar(1, pacman);
    delay(200);
    lcd.createChar(1, pacmanOpen);
    delay(200);
    lcd.setCursor(i, 3);
    lcd.print(" ");
  }
  delay(1000);

  dataSpill();
}

// HD44780 DECODER, WRITTEN BY LEONARDO MARTINS 19/01/2019

# define RS_PIN 23 // RS (Register Select) pin
// # define RW_PIN 11 // RW (Read/Write) pin
# define EN_PIN 21 // EN (Enable) pin
# define DATA_PINS {37, 39, 41, 43} // Data pins D4, D5, D6 and D7

bool previousEn = LOW; // Previous state of the EN pin
volatile byte data = 0; // Storage for data
volatile bool highBits = true; // Flag to indicate if we are reading high or low bits
volatile bool dataReady = false; // Flag to indicate when data is ready to read

void decoderSetup() {
  Serial.begin(9600); // Start serial communication

  // Set control pins as input
  pinMode(RS_PIN, INPUT);
//  pinMode(RW_PIN, INPUT);
  pinMode(EN_PIN, INPUT);

  // Set data pins as input
  int dataPins[] = DATA_PINS;
  for (int i = 0; i < 4; i++) {
    pinMode(dataPins[i], INPUT_PULLUP);
  }

  // Setup the interrupt
  attachInterrupt(digitalPinToInterrupt(EN_PIN), readData, FALLING);

// Serial.println(digitalPinToInterrupt(EN_PIN));
//  for (; ; );
}

void loopTEST() {
  if (dataReady) {
    // Print the corresponding ASCII character to the Serial
    Serial.print(data);
    dataReady = false; // Reset the data ready flag
  }
}

volatile char dataBuffer[128];
volatile byte charCount;

void readData() {
  // Check if it's a write operation (RW == 0) and data is being sent (RS == 1)
  if (digitalRead(RS_PIN) == HIGH) {
    // Read the 4-bit part of data
    int dataPins[] = DATA_PINS;
    byte part = 0;
    for (int i = 0; i < 4; i++) {
      part |= digitalRead(dataPins[i]) << i;
    }

    if (highBits) {
      // This is the high bits part
      data = part << 4;
    } else {
      // This is the low bits part
      data |= part;
      dataReady = true; // Indicate that data is ready to read

      dataBuffer[charCount] = data;
      charCount++;
    }

    // Flip the highBits flag
    highBits = !highBits;
  }
}

void dataSpill()
{
  if (!dataReady)
    return;

  noInterrupts();
  int myCount = charCount;
  charCount = 0;
  dataReady = false;
  interrupts();

  Serial.print("data ");

  for (unsigned char tt = 0; tt < myCount; tt++) {
//    Serial.print("0x");
    Serial.print((byte) dataBuffer[tt], HEX);
    Serial.print(" ");
  }

  Serial.println(".");
}

Just for fun. Now off to the beach. Find the errors and make improvements while I'm away. :expressionless:

a7

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.