/*
NOTE: This program, although working perfectly simulated, has yet to be tested
in a practical, real-world set-up.
This project aims to reduce the amount of GPIO pins used when
controlling an LCD screen in 4 bit mode directly from an MCU by
using a 74HC595 8-Bit Shift Register.
Normally 6 pins are used
D4, D5, D6, D7
RS
E
Using the 74HC959, only 3 pins are used, those
are:
Data Pin
Latch Pin
Clock Pin
*/
#define E 12
#define DATA_PIN 11
#define LATCH_PIN 10
#define CLOCK_PIN 9
void setup() {
Serial.begin(115200);
pinMode(E, OUTPUT);
pinMode(LATCH_PIN, OUTPUT);
pinMode(DATA_PIN, OUTPUT);
pinMode(CLOCK_PIN, OUTPUT);
LCD_init();
LCD_setCursor(2, 0);
LCD_printString("74HC595 8BIT");
LCD_setCursor(5, 1);
LCD_printString("W/ LCD");
}
void loop() {
;
}
/*
Initiate the display
Commands:
1) Start in 4 bit mode
2) Set as 5x8 2 rows
3) Screen on, cursor off
4) Clear Display
*/
void LCD_init() {
LCD_command(0x02);
LCD_command(0x28);
LCD_command(0x0C);
LCD_command(0x01);
delay(3);
}
//Send Command
void LCD_command(byte cmd) {
LCD_sendData(cmd, LOW);
}
//Iterate String and send each Char
void LCD_printString(const String &str) {
for (size_t i = 0; i < str.length(); i++) {
LCD_sendData(str[i], HIGH);
}
}
/*
In 4 bit mode you have to send 2 packets (nibbles).
First, the 4 most significant bits, then the
4 least signifnca bits.
First packet
Q7 -> BIT 7
Q6 -> BIT 6
Q5 -> BIT 5
Q4 -> BIT 4
Second packet
Q7 -> BIT 3
Q6 -> BIT 2
Q5 -> BIT 1
Q4 -> BIT 0
*/
//mode is for the RS: LOW->COMMAND, HIGH->DATA
void LCD_sendData(byte data, int mode) {
byte packet1 = 0;
byte packet2 = 0;
packet1 |= ((data >> 7) & 0x01) << 7;
packet1 |= ((data >> 6) & 0x01) << 6;
packet1 |= ((data >> 5) & 0x01) << 5;
packet1 |= ((data >> 4) & 0x01) << 4;
packet2 |= ((data >> 3) & 0x01) << 7;
packet2 |= ((data >> 2) & 0x01) << 6;
packet2 |= ((data >> 1) & 0x01) << 5;
packet2 |= ((data >> 0) & 0x01) << 4;
setRS(packet1, mode);
//Send First packet
transfer(packet1);
//Toggle Read Data in D-PINS
pulseEnable(packet1);
setRS(packet2, mode);
//Send Second packet
transfer(packet2);
//Toggle Read Data in D-PINS
pulseEnable(packet2);
delay(3);
}
//Set LCD Cursor
void LCD_setCursor(byte col, byte row) {
byte rows[] = {0x80, 0xC0};
LCD_sendData(rows[row]+col, LOW);
}
void pulseEnable(byte &packet) {
bitWrite(packet, 1, HIGH);
transfer(packet);
delayMicroseconds(1);
bitWrite(packet, 1, LOW);
transfer(packet);
delayMicroseconds(50);
}
void transfer(int packet){
digitalWrite(LATCH_PIN, LOW);
shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, packet);
digitalWrite(LATCH_PIN, HIGH);
}
void setRS(byte &packet, int mode){
bitWrite(packet, 0, mode);
transfer(packet);
}