Introduction: Arduino GPS Speedometer With a Ks0108 - 128x64 GLCD (display)
I wanted to build a digital speedometer for my car. There was nothing wrong with the one already installed in my car, I just wanted to have a big LCD display that will be positioned in a more convenient position - right in front of me. And as I did not want to mess with my car's electronic parts in order to tap in and read the "speed" signal straight from the car's computer, I opted for the GPS version.
1. Arduino Uno (Nano or other Arduino boards might be fine as well)
2. GPS module, I got this one https://www.dfrobot.com/wiki/index.php?title=GPS_Module_With_Enclosure_(SKU:TEL0094) (if the link is not working when clicked, just copy and paste it into your browser's address bar)
3. Graphic LCD (http://www.aliexpress.com/item/20PIN-LCD12864-Grap...)
4. 10k trimpot for adjusting the contrast of the LCD
5. 4.7k potentiometer for adjusting the brightness of the LCD
6. 100 ohm resistor to limit the current for the LCD brightness
7. Wires, suction cup, self-adhesive velcro, kitchen aluminium foil (or similar), soldering iron, pliers, hot glue gun, etc.
8. USB cable for powering the Arduino board (and LCD) and separately the GPS module
9. 2 x USB (5V) car power adapters (at least 1A each)
10. Plastic enclosure (or you could build one)
11. and of course, a car with a battery to power the whole stuff
I would advise that you build a prototype version first, and only when tested and working start the actual building of the enclosure.
In order to be able to upload sketches to the Arduino board, the GPS module will have to be disconnected, as it uses the same RX and TX pins to communicate with the Arduino board as the Arduino IDE. While the GPS module was left connected, attempts to upload sketches failed in my case.
PS. As YukselV suggested, you could use SoftwareSerial instead of the "simple" Serial, in case you want to test other features which means uploading the sketch multiple times - you won't have to disconnect the GPS module in this case. Thanks YukselV! (https://www.arduino.cc/en/Reference/SoftwareSerial)
Similarly, the LCD power will have to be disconnected while uploading sketches to the Arduino board. This is due to the RESET pin being connected to the LCD, which interferes with the Arduino IDE. I read that one could simply connect the RESET pin of the LCD to +5V on the Arduino (permanently), or simply temporarily disconnect the RESET wire while uploading the sketch to the Arduino board. I simply disconnected the power supply when required.
First, because my LCD order would take a while to arrive, I started by testing the GPS module using a LED display.
*********** UPDATE 31.10.2016 ********************
I have attached the .INO sketch for using with a 4-Digit-7-Segment-LED-Display
*********** end of UPDATE 31.10.2016 ********************
When the LCD finally arrived, it took me a while finding out the correct wiring for the LCD. I found a tutorial in Italian (http://www.mauroalfieri.it/elettronica/lcd-grafico...) that shows the wiring (http://www.mauroalfieri.it/wp-content/uploads/2013...). That however was not working properly for me, so I had to change some stuff around:
- I had to change some wiring around the 10k trimpot (controlling the LCD contrast)
- I added another 4.7k potentiometer in series with a 100 ohm resistor, that will allow me to control the LCD brightness as well.
EDIT: Thanks to ibenkos for pointing out that the +5v engine in my original wiring image was connected to ground rail on the breadboard. It should of course be connected to the positive rail - updated picture uploaded.
Then I wanted for the speed to be displayed instantly after starting my car engine and moving off. However I didn't want to leave the whole stuff powered up all the time and risk for the car battery to go dead. Therefore I would power the Arduino board and the LCD only when I start the engine, while the GPS module would be powered all the time, even when the engine is off (so that it won't take "I don't care how many seconds to lock onto the positioning satellites for required data to be sent to Arduino for processing").
It's up to you however to locate the appropriate points where to get power from the fuse board.
Using one USB car power adapter I would get continuous 5V to power the GPS module, while the second USB car power adapter would give me 5V to power the Arduino and the LCD only when I start the car engine.
One more thing to note: I used fused wires to connect to both car power adapters, so that they will blow in case of a short circuit, and not some other car electronics.
Here I was testing the LCD wiring - note the resistors I was using instead of the trimpot, which I did not have at the time.
I cut a whole in the plastic enclosure (that I bought from a local shop) that will allow the LCD display to fit in, and then I hot-glued the LCD in place. I've cut a piece of plastic sheet and placed it on the back of the LCD then I added some aluminium foil on top. I also added aluminium foil all around the plastic enclosure, including the back cover, and connected everything to ground. The idea is: try to enclose the Arduino board inside an improvised Faraday cage (https://en.wikipedia.org/wiki/Faraday_cage) in order to prevent any interference from other electronic devices that could affect the functionality of the Arduino board. That's the idea, anyway :-) Is this really necessary? I don't know.
However, make sure that you are not shorting any contacts on either the LCD or Arduino.
Because I needed two different 5V power supplies (one for Arduino and LCD, the other for the GPS module), and another wire that will connect to the potentiometer controlling the LCD brightness - four wires in total, if we account for the ground as well - I decided that I will use an USB cable, which is conveniently screened.
I took the USB connector off the Arduino board (I didn't have another one at that time, and having uploaded and tested the whole thing before), I cut another hole in the plastic enclosure, and there I had my required power connection. You could use an additional USB connector, if you think you might need to upload updated sketches to the Arduino board.
Or of course, you could use another type of an electrical connector altogether if you wish. The idea is to get those four wires inside the box connected to the appropriate power source - continuous 5V, engine on 5V, LCD brightness signal coming from the potentiometer, and ground.
I happened to have a suction cup from an old sat nav, which I wasn't using anymore. This will hold the whole box onto the windscreen of the car. The GPS module is attached using some self-adhesive velcro, with a small hole allowing the four wires (5v, ground, TX, RX) to go and connect inside the box.
And there it is, the final product located onto the dashboard, connected by the USB cable to the power supply and the potentiometer conveniently located beside the steering wheel (please note, I have a left hand driving car, the steering wheel is located therefore on the right hand side of the car)
And you can watch it working here:
Sorry for the video going in and out of focus - I was using a compact camera, with no option for a fixed focus.
Now for the code...
First, you need to download two libraries (in case you don't have them already in your Arduino's library folder):
1. OpenGLCD - https://code.google.com/p/glcd-arduino/downloads/l...
(more information can be found here: http://playground.arduino.cc/Code/GLCDks0108 and here https://bitbucket.org/bperrybap/openglcd/wiki/Home)
2. TinyGPS - http://arduiniana.org/libraries/tinygps/
Unzip and copy them in your Arduino's library folder (normally C:\Program Files (x86)\Arduino\libraries\). If the Arduino IDE is open, you have to close and re-open it, to allow for the new libraries to be loaded.
Then I found it very awkward to generate new fonts (as high as the screen height) that will be displayed onto my LCD. Therefore what I did was to create bitmaps (numbers 0 to 9 plus a blank) that will be displayed on my LCD.
After "installing" the openGLCD library, look for the file name called "glcdMakeBitmap.pde", normally located here
C:\Program Files (x86)\Arduino\libraries\openGLCD\bitmaps\utils\glcdMakeBitmap\
EDIT - April 12th, 2016!!!!
Added OpenGLCD library, which already has the .h (header) files. You need to copy and unzip where your Arduino IDE is located - normally C:\Program Files (x86)\Arduino\libraries\
EDIT - April 12th, 2016!!!! [ends]
To run this file you will need to download and install an additional piece of free software, called Processing, which is very similar to Arduino IDE.
EDIT - March 14th, 2016!!!!
Thanks ab710 for pointing out that using some newer Processing versions will give an error while trying to run the code. Please use the link below to download Processing 2.2.1 which in my case allows for properly running of the code.
Alternate download link: https://drive.google.com/open?id=1LzcEr3DhHO4HFnq9u4e2AE--H4-x7VLd
EDIT - March 14th, 2016!!!! [ends]
Open "glcdMakeBitmap.pde" in Processing and click Run, in the top-left corner.
The purpose of "glcdMakeBitmap.pde" application is to allow you to "feed" it with image files (gif, jpg, bmp, tga, png), and then some .h (header) files will automatically be created within the "bitmaps" folder of the openGLCD library. They will eventually be used to display your numbers (as images) onto the LCD.
I have attached an archive file named "numbers.zip" which you can download, unzip, and then drag each one of those .BMP files onto the running "glcdMakeBitmap.pde" in order to create the 11 header files (0 to 9, plus blank). But if you wish, you can design your own numbers, using different fonts, save them as BMP or other supported image file extension, and use them to create the header files which will be displayed onto the LCD.
PS. In case you're wondering why did I not upload the header (.h) files instead of the .BMP files, and save you the trouble of downloading and installing Processing, and running "glcdMakeBitmap.pde": It's not enough to simply copy the .h files into "bitmaps" folder, as the files named "allBitmaps.h" will be automatically updated as well (by the Processing application) to refer to the new files. Plus, in case you don't like my numbers, you now know how to create your own :-)
And finally the sketch, which is not very complicated, and should be self-explanatory.
I have also attached the .ino sketch for your convenience.
#include //math library to use for round function
#include "TinyGPS.h" //GPS module library
#include // LCD library
TinyGPS gps; //create a gps object
float fLat, fLong; //floats for longitude and latitude; will be used to determine whether the GPS data is up to date or not
unsigned long fix_age; // returns +- latitude/longitude in degrees
int digit1, digit2, digit3; //integers to hold the three digits making up the speed
int iSpeed; //integer to hold the speed value from the GPS module
Serial.begin(9600); //start the serial communication
// initialise the library, non inverted writes pixels onto a clear screen
//incoming serial data from GPS
int c = Serial.read();
// process new gps info here, in case you want to display more details
gps.f_get_position(&fLat, &fLong, &fix_age); //get longitude and latitude, used to find if data is up to date
if (fix_age == TinyGPS::GPS_INVALID_AGE || fix_age > 2000)
//data was not updated for some time, assume that GPS connection is lost
iSpeed = 0;
//GPS connection is up to date, get the speed information, and round it to closest integer value
iSpeed = round(gps.f_speed_kmph()); // speed in km/h
//when not moving, the GPS module will still read some "speed" value, not necessarily zero
//in that case assume the car is not moving; only display values greater than 2
if (iSpeed == 1) iSpeed = 0;
displaySpeed(iSpeed); //call function to display the speed, digit by digit
void displaySpeed(int iSpeed)
//"simple" maths to extract each digit value
digit1 = iSpeed / 100;
iSpeed = iSpeed - (digit1 * 100);
digit2 = iSpeed / 10;
digit3 = iSpeed - (digit2 *10);
//display "blank" bitmap when necessary, instead of number zero
if (digit2 == 0 && digit1 == 0) digit2 = -1; //digit 2 is blank
if (digit1 == 0) digit1 = -1; //digit 1 is blank
//call function to display each digit, at their required position
void drawDigit(int digit, int pos)
GLCD.DrawBitmap(Number0, pos, 0);
GLCD.DrawBitmap(Number1, pos, 0);
GLCD.DrawBitmap(Number2, pos, 0);
GLCD.DrawBitmap(Number3, pos, 0);
GLCD.DrawBitmap(Number4, pos, 0);
GLCD.DrawBitmap(Number5, pos, 0);
GLCD.DrawBitmap(Number6, pos, 0);
GLCD.DrawBitmap(Number7, pos, 0);
GLCD.DrawBitmap(Number8, pos, 0);
GLCD.DrawBitmap(Number9, pos, 0);
GLCD.DrawBitmap(NumberBlank, pos, 0);
If you have any comments, questions or ideas, please let me know. And I hope you'll enjoy (as much as I did) building your own Arduino based GPS speedometer.