Custom Large Font For 16x2 LCDs by mpilchfamily
Featured
A couple of years ago i was learning to use the Ardiuno and started playing around with an Hitachi HD44780 based 16x2 LCD screen. I soon learned that the screen has 8 customizable character slots. I had found a project where someone used those slots to create there own custom characters that could then be used to form large character font using both rows of the screen. I didn't like the look of those characters and couldn't make since of the sketch that person wrote. So i decided i needed to create my own set and use my limited programming skills to create a more user friendly sketch to support my large character font.

In this Instructable i'll show you how i designed my large character font and break down the sketch to make it easier to understand. But first we need to set up the Arduino and LCD. 

Materials Needed:

- Arduino (i used a Nove)
- Hitachi HD44780 based 16x2 LCD
- Breadboard
- 5K Potentiometer
- button or switch
- jumper wires


This shows a revised version of the font.

Here is the finished font
 
Remove these adsRemove these ads by Signing Up

Step 1: Connecting the LCD to the Arduino

First i want to cover how to connect a Hitachi HD44780 based LCD screen to an Arduino. The first thing you need to do is identify Pin 1 on your display and figure out which pins you need. The first image shows a very simple layout for connecting the LCD to your Arduino. Here is the pin Layout for the LCD.
  • Pin 1 - Grd
  • Pin 2 - VCC
  • Pin 3 - Vee (controls screen contrast)
  • Pin 4 - RS (controls where in the LCD's memory your writing too)
  • Pin 5 - RW (controls weather your Reading or Writing to the LCD)
  • Pin 6 - E (enables writing to the register)
  • Pin 7 - D0 (not used)
  • Pin 8 - D1 (not used)
  • Pin 9 - D2 (not used)
  • Pin 10 - D3 (not used)
  • Pin 11 - D4
  • Pin 12 - D5
  • Pin 13 - D6
  • Pin 14 - D7
  • Pin 15 - LED+ (LCD back light)
  • Pin 16 - LED-  (Grd)

My LCD only had 15 pins which is fine since 16 should be tied to ground anyway. As you can see in the picture Vee is tied into a potentiometer. This controls the contrast of the screen. The data pins are the individual bits your writing to or reading from the register.

For the purposes of keeping things simple i wired mine up a bit differently. I like to use ribbon cable whenever possible to keep the clutter of wires down. I makes keeping track of the connections allot easier too. 
  • RS pin to D7
  • E pin to D6
  • D4 pin to D5
  • D5 pin to D4
  • D6 pin to D3
  • D7 pin to D2
  • V0 tied to a pot to control brightness
  • Grd and R/W tied to ground
  • Vcc to +5V
  • pin 15 to push button/switch that is tied to ground for control of back light
With everything connected we can now go over how i created the fonts.
antennas says: Apr 29, 2013. 8:17 AM
I just found this. Thanks great work. I am trying to build a large font display for an antenna rotor for a friend who can't see the small analogue needle. So I got my display reading my pot input as 0-360 , but how do I get it to display the large fonts??
Thanks again.
mpilchfamily (author) says: Apr 29, 2013. 10:55 AM
Take a look at step 5 again and see the sketch posted there. Most of the code sets up each letter and number as custom calls. Then the void letters set up which characters i want on the screen. The in the void loop we bring it all together using for statements to have the full set of characters scroll across the screen.

Any sketch you create will have to call to the correct void custom to bring up the letter or number you want to display. You will need to take the number you want to display and have a translator function that can break 360 down to 3, 6, and 0 each being stored to there own variable. Then make comparisons between the variable and each number. When a match is found call to that custom character and display it. It's also important to have the correct number of cursor spaces between the first column of the first character and the first column of the next character. Characters like the 'M' and 'W' are wider then the rest.

Course all of this makes your code much longer and slower. So if you don't want any kind of delay between moving your pot and getting the readout then this may not be the best option for you.
antennas says: Apr 29, 2013. 7:31 PM
Ok sounds interesting. ANy ideas on how to do that? (You knew I'd ask...LOL) I looked at converting to a String and you can get character/number positions out of it but I don't know how yet.
mpilchfamily (author) says: Apr 29, 2013. 8:37 PM
Think about a math problem that will be able to get rid of the other digits. May have to be a series of equations that will pull it off. Take the variable and subtract 100. If the variable is greater than 100 add 1 to a tracking variable and loop back to subtract 100 again. If the variable is less than 100 store the tracking variable to the variable for displaying the hundreds and move on to doing a similar equation for the tens and ones. By the end of it all you will have a variable for the hundreds, tens, and ones that match the original number and can make calls to the appropriate character to be displayed.

There is likely a much simpler way of doing it but that is the first thing to come to mind.

Quick code of the hundreds breakdown:
int analog = ??? //value read from the pot input
int track = 0 //tracking variable
int hund = 0 //hundreds place
int ten = 0 //tens place
int one = 0 //ones place
int comp = analog //for storing analog variable after numbers have been subtracted

viod breakhund()
if comp >100
comp = analog-100
track++
breakhun
end

if comp < 100
hund = track
track = 0
breakten

void breakten()



Of course punctuation is missing but that should give you an idea. The tens and ones will follow in the same fashion. You can pretty much copy and past the same code just drop a zero each time. 
antennas says: May 11, 2013. 6:11 AM
Thanks. I finally got some time and I got it to work as you indicated. (Or very close) so I have it displaying 0-360 like I need. I can't get it to clear the numbers properly, such as when you change from 0 to 1 it still displays bits of the 0 along with the 1. I tried using the lcd.write(" "); but it didn't work, I put it into the spot where it prints characters in the function that is called to print a custom character. I also tried the lcd.clear but it is either too fast to see the characters or too slow and they blink.
I thought I'd pick your brain a bit to see if you have an idea.
Thanks for your help so far!!

Here is the code..

// These constants won't change. They're used to give names
// to the pins used:
const int analogInPin = A0; // Analog input pin that the potentiometer is attached to

int sensorValue = 0; // value read from the pot
int outputValue = 0; // value output to the PWM (analog out)
//char outputValueChar[5];
int hundreds;
int tens;
int ones;
#include
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);


// the 8 arrays that form each segment of the custom numbers
byte LT[8] =
{
B00111,
B01111,
B11111,
B11111,
B11111,
B11111,
B11111,
B11111
};
byte UB[8] =
{
B11111,
B11111,
B11111,
B00000,
B00000,
B00000,
B00000,
B00000
};
byte RT[8] =
{
B11100,
B11110,
B11111,
B11111,
B11111,
B11111,
B11111,
B11111
};
byte LL[8] =
{
B11111,
B11111,
B11111,
B11111,
B11111,
B11111,
B01111,
B00111
};
byte LB[8] =
{
B00000,
B00000,
B00000,
B00000,
B00000,
B11111,
B11111,
B11111
};
byte LR[8] =
{
B11111,
B11111,
B11111,
B11111,
B11111,
B11111,
B11110,
B11100
};
byte UMB[8] =
{
B11111,
B11111,
B11111,
B00000,
B00000,
B00000,
B11111,
B11111
};
byte LMB[8] =
{
B11111,
B00000,
B00000,
B00000,
B00000,
B11111,
B11111,
B11111
};

// loop counter
int x = 0;


void setup()
{
Serial.begin(9600);
// assignes each segment a write number
lcd.createChar(0,LT);
lcd.createChar(1,UB);
lcd.createChar(2,RT);
lcd.createChar(3,LL);
lcd.createChar(4,LB);
lcd.createChar(5,LR);
lcd.createChar(6,UMB);
lcd.createChar(7,LMB);


// sets the LCD's rows and colums:
lcd.begin(16, 2);

}

void custom0()
{ // uses segments to build the number 0
lcd.setCursor(x, 0); // set cursor to column 0, line 0 (first row)
lcd.write((byte)0); // call each segment to create
lcd.write(1); // top half of the number
lcd.write(2);
lcd.setCursor(x, 1); // set cursor to colum 0, line 1 (second row)
lcd.write(3); // call each segment to create
lcd.write(4); // bottom half of the number
lcd.write(5);
}

void custom1()
{
lcd.setCursor(x,0);
lcd.write(1);
lcd.write(2);
lcd.setCursor(x+1,1);
lcd.write(5);
}

void custom2()
{
lcd.setCursor(x,0);
lcd.write(6);
lcd.write(6);
lcd.write(2);
lcd.setCursor(x, 1);
lcd.write(3);
lcd.write(7);
lcd.write(7);
}

void custom3()
{
lcd.setCursor(x,0);
lcd.write(6);
lcd.write(6);
lcd.write(2);
lcd.setCursor(x, 1);
lcd.write(7);
lcd.write(7);
lcd.write(5);
}

void custom4()
{
lcd.setCursor(x,0);
lcd.write(3);
lcd.write(4);
lcd.write(2);
lcd.setCursor(x+2, 1);
lcd.write(5);
}

void custom5()
{
lcd.setCursor(x,0);
lcd.write((byte)0);
lcd.write(6);
lcd.write(6);
lcd.setCursor(x, 1);
lcd.write(7);
lcd.write(7);
lcd.write(5);
}

void custom6()
{
lcd.setCursor(x,0);
lcd.write((byte)0);
lcd.write(6);
lcd.write(6);
lcd.setCursor(x, 1);
lcd.write(3);
lcd.write(7);
lcd.write(5);
}

void custom7()
{
lcd.setCursor(x,0);
lcd.write(1);
lcd.write(1);
lcd.write(2);
lcd.setCursor(x+1, 1);
lcd.write((byte)0);
}

void custom8()
{
lcd.setCursor(x,0);
lcd.write((byte)0);
lcd.write(6);
lcd.write(2);
lcd.setCursor(x, 1);
lcd.write(3);
lcd.write(7);
lcd.write(5);
}

void custom9()
{
lcd.setCursor(x,0);
lcd.write((byte)0);
lcd.write(6);
lcd.write(2);
lcd.setCursor(x+2, 1);
lcd.write(5);
}





void loop() {
// read the analog in value:
sensorValue = analogRead(analogInPin);
// map it to the range of the analog out:
outputValue = map(sensorValue, 0, 1023, 0, 360);

// print the results to the serial monitor:
Serial.print("sensor = " );
Serial.print(sensorValue);
Serial.print("\t output = ");
Serial.println(outputValue);

String stringOne = String(outputValue);
// prints the value of outputValue
//Serial.print("Output value string is ");
//Serial.println(stringOne);
x=0;
hundreds = outputValue /100;
//Serial.print(hundreds);
delay(500);

switch (hundreds) {
case 3:
custom3();
break;

case 2:

custom2();
break;

case 1:

custom1();
break;

case 0:

custom0();
break;

}

tens=outputValue /10;
tens=tens%10;
//Serial.println(tens);

switch (tens) {
case 9:
x=x+3;

custom9();
break;

case 8:
x=x+3;

custom8();
break;

case 7:
x=x+2;

custom7();
break;

case 6:
x=x+3;

custom6();
break;

case 5:
x=x+3;

custom5();
break;

case 4:
x=x+3;

custom4();
break;

case 3:
x=x+3;

custom3();
break;

case 2:
x=x+3;

custom2();
break;

case 1:
x=x+3;

custom1();
break;

if (outputValue<10)
{
//case 0:
x=x+3;

custom0();
break;
}

case 0:
x=x+3;

custom0();
break;
}

ones=outputValue%10;
//ones=ones%100;
// Serial.println(ones);

switch (ones) {
case 9:
x=x+3;

custom9();
break;

case 8:
x=x+3;

custom8();
break;

case 7:
x=x+3;

custom7();
break;

case 6:
x=x+3;

custom6();
break;

case 5:
x=x+3;

custom5();
break;

case 4:
x=x+3;

custom4();
break;

case 3:
x=x+3;

custom3();
break;

case 2:
x=x+3;

custom2();
break;

case 1:
x=x+3;

custom1();
break;

case 0:
x=x+3;

custom0();
break;

}
/*
delay(500);
lcd.setCursor(0,1);
lcd.print(outputValue); */
//delay(300);
//lcd.clear();

//if (outputValue < 100)
// {
// x=0;
// lcd.print(" ");
// }

// wait 2 milliseconds before the next loop
// for the analog-to-digital converter to settle
// after the last reading:
//delay(10);


}
mpilchfamily (author) says: May 11, 2013. 7:20 AM
Put the lcd.clear before the set cursor and drop the delay before the set cursor. Keep and play around with the delay after the lcd.print. Should smooth things out for you a bit.

There is already a delay with the processing leading up to the print update. So that combined with the delay after the print leaves the display showing strong. Then it get through the processing and clears the screen a millisecond before it prints again causing an imperceptible update.
antennas says: May 12, 2013. 9:02 AM
Looks like I got it, I found a lcd.clear rate that works and no (" ") needed. I also "fixed" what I didn't care for with the 1 digit. So it looks all good now. All with your help though!! Thank you very much!!!
Roby91 says: Apr 4, 2012. 11:32 PM
Please, what's the name of that the schematic 3d generator software?
Lindafr says: Apr 11, 2012. 8:34 AM
The image above was created with http://fritzing.org
megaduty says: Feb 24, 2012. 9:39 AM
Thanks for the run down man; I have two 16x2 IM161 Microtivity units I'm playing with currently on various Arduino projects.
MegaTank.PNG
Pro

Get More Out of Instructables

Already have an Account?

close

PDF Downloads
As a Pro member, you will gain access to download any Instructable in the PDF format. You also have the ability to customize your PDF download.

Upgrade to Pro today!