uint8_t *data[] = {9,8,7,6,5,4,3,2}; // Data pins
uint8_t pin_e   = 10;                // Enable pin
uint8_t pin_rw  = 11;                // Read/write pin
uint8_t pin_rs  = 12;                // Command select pin

char *message = "Hello world!";

#define RS 0x01 // Command select
#define RW 0X02 // Read/write
#define E 0X04  // Enable

/*
Set the control pins
*/
void set_control(uint8_t ctrl) {
  digitalWrite(pin_rs, (ctrl & RS)?HIGH:LOW);
  digitalWrite(pin_rw, (ctrl & RW)?HIGH:LOW);
  digitalWrite(pin_e, (ctrl & E)?HIGH:LOW);
}

/*
Set the data buss
*/
void set_data(uint8_t data_bits) {
  for (int i = 0; i < 8; i++) {
    digitalWrite(data[i], data_bits & 0x01);
    data_bits = data_bits >> 1;
  }
}

/*
Set data buss to output
*/
void set_data_output() {
  for (int i = 0; i < 8; i++) {
    pinMode(data[i], OUTPUT);
  }
}

/*
Set the data buss to input
*/
void set_data_input() {
  for (int i = 0; i < 8; i++) {
    pinMode(data[i], INPUT);
  }
}

/*
Wait for lcd to be ready
*/
void lcd_wait() {
lcd_wait:
  set_data_input();

  do {
  set_control(RW);
  set_control(RW|E);
  } while (digitalRead(data[7]) == HIGH);
  
  set_control(RW);
  set_data_output();
}

/*
Send and instruction
*/
void lcd_instruction(uint8_t inst) {
  lcd_wait();
  set_data(inst);
  set_control(9);  // Clear RS/RW/E bits
  set_control(E);  // Set E bit to send instruction
  set_control(9);  // Clear RS/RW/E bits
}

/*
Send a character
*/
void print_char(uint8_t chr) {
print_char:
  lcd_wait();
  set_data(chr);
  set_control(RS);   // Set RS; Clear RW/E bits
  set_control(RS|E); // Set E bit to send 
  set_control(RS);   // Clear E bits
}

/*
Start the program
*/
void start() {

  lcd_instruction(0b00111000); // Set 8-bit mode; 2-line display; 5x8 font
  lcd_instruction(0b00001110); // Display on; cursor on; blink off
  lcd_instruction(0b00000110); // Increment and shift cursor; don't shift display
  lcd_instruction(0b00000001); // Clear display

  // Send message
  char *msg_ptr = message;
  while (*msg_ptr != 0) {
    print_char(*msg_ptr);
    msg_ptr++;
  }
}

void setup() {
  set_data_output(); // Set the data buss to output
  pinMode(pin_e, OUTPUT);  // Set enable to output
  pinMode(pin_rw, OUTPUT); // Set read/write to output
  pinMode(pin_rs, OUTPUT); // Set command select to output

  start();
}

void loop() {
  delay(10);
}
$abcdeabcde151015202530354045505560fghijfghij
74HC138/74HC238Breakout
6116 2K RAMBreakout
2716 2K EPROMBreakout
6502Breakout
ClockBreakout
6532 RIOTBreakout