HOME > > ARDUINO LANGUAGE COURSE  t.o.c.      Delicious Bookmark this on Delicious Recommend to StumbleUpon

Serial Monitor, LCD usage, the "map" function... etc!

This is one of a collection of pages which, together, attempt to show you "everything" about the Arduino's programming language.

There is a page for you with more information about the project in general, and the way these pages are organized, if you want that.

Please visit my page about power browsing notes sometime.


Fasten your seatbelt....

Do not start this tutorial if you are not fresh! It is a big one... but it introduces some great stuff.

If you just want to know how to connect an LCD panel, without much "teaching" along the way, visit my How To Connect LCD panel page.

If you read what follows you can learn how to connect the "serial monitor". You already it. ("the serial monitor"... it is part of the Arduino IDE.) With it, you can get numbers or text from your Arduino programs to appear on the PC you are using to write those programs. Very helpful while debugging.

Of course, usually you won't want to keep a PC permanently connected to your Arduino. Once the programming is complete, the Arduino is probably going to be disconnected from the PC and sent out into the cold cruel world to earn its keep, doing something useful. LEDs are fine for some simple messages from the Arduino, but what if you, like Master Twist, want MORE? This tutorial shows you an easy way to hook up an LCD panel, on which the Arduino can display numbers and text. (Sadly, you will have to buy an LCD panel and controller.... but they can be had for around $25).

We'll also look at the useful "map" function. Sundry other incidental things, such as pin usage recommendations, crop up too!

I'm sorry this tutorial is so long, but one thing led to another so well.

Along the way, we will be making a pretty little LED flasher which changes how fast the lights flash depending on the position of a potentiometer. (A potentiometer is a cheap variable resistor, of the sort used in the volume control of a radio.)

One more thing before we start: A WARNING!! ....

"Serial" and "RS-232" are NOT just two ways of saying the same thing. RS-232 comms do use serial data, so you might think that you can hook up the serial "stuff" I'm going to talk about... including your Arduino... to RS-232 devices. Or to the RS-232 port of a big PC. NOT SO!!

All the ins and outs of that are beyond the scope of this tutorial. I've inserted this warning just in case someone is tempted to "extend" the ideas here, hook an Arduino directly to something RS-232... and fry their Arduino! (If you want to connect to RS-232, search on "Arduino MAX323".)

Messages from the interior...

So far, we've contented ourselves with crude but simple things. In this one, we are going to demand more.

Before I start, I'd like to thank the author of the tutorials at LadyAda. The notes there on using the serial library saved me some stumbling around in the dark along the road to using the serial monitor. They cover some of the points of Arduino work that I cover, if you are looking for another attempt to convey that material. There is little there that is not covered here, but it is explained differently, if you are unhappy here. Those tutorials are not as comprehensive as these.

The Serial Monitor

First I'm going to show you a way to get "answers" out of the Arduino to your PC's screen. It is unlikely that you will make many finished projects requiring a PC in the final result, but what I am going to show you will be useful in development work. Later I will show you another way to get information out of the Arduino.

The new program is...

28 Dec 09

Expects an analog input to "A0"
Passes reading to a PC over the serial monitor*/

int intAnValue=0;
const byte AnInputPin=0;

void setup()
  Serial.begin(9600);//  setup serial

void loop()
delay(1000);//To slow down how rapidly readings are taken.

The program above is basically our original, very simple program for ADC, with just three new lines. That program, remember, read the voltage on the ADC pin "A0".

The "Serial.begin(9600);" in the "setup" function can be thought of as an "abracadabra" to "turn on" the connection between the Arduino and the PC you are using for programming it. The connection is the same USB cable as is used for sending programs to the Arduino. "begin" is a procedure within the "Serial" thing (I'm not sure of the correct noun!) which is built into every Arduino. The "9600" has to do with how fast the Arduino will "speak"... use 9600, and all will be well without having to fiddle with other things elsewhere.

We only have to do a "Serial.begin(9600);", once, somewhere. After that, if we do a "Serial.println(555);", the Arduino will send "555" "up" the USB cable to the host PC. How do we see the "555"??? All we need to do, once the process is taking place, is to open the serial monitor. We do this from the Arduino IDE window (the one with the code editor and the buttons for saving and uploading our work). The serial monitor is opened by clicking on the right-hand-most of the small buttons on the toolbar immediately below the IDE's menu bar. The icon looks like a rectangle with a small circle outside and touching the middle of the upper edge.

A bunch of "555"s would be pretty useless. Happily, not only can we say "Serial.println(555);", but we can also say things like....


... in which case whatever is in the variable intAnValue is passed to the host computer, and displayed in the serial monitor window there.

Run the program above. Turn the knob on the potentiometer. You should see numbers from 0 to 1023 appearing in the serial monitor window.

Remember: Many sensors of interesting things create analog outputs. A boring old potentiometer is not the extent of things that can be connected to the ADCs.

A $25 alphanumeric LCD (liquid crystal display)

What if you want to see the numbers of the readings from the ADC, and you don't want to leave a $500 PC connected to the Arduino while it is doing this data collection work?

One answer is an LCD panel. They cost more than a few dollars, but not a LOT more, and have many uses. Go on, treat yourself... you know you want to! (Perhaps $25, if you are happy to do a little soldering.)

Once you have an LCD panel, the program to send the ADC numbers to it is almost the same as the program to send the numbers to the PC's serial monitor.

I use a LCD panel from ModernDevice.com, based on a pre-programmed PIC from Peter Anderson. I've written a tutorial that covers the LCD hookup, and a lot more. Between the LCD panel and your Arduino, you need to connect the 5v line, the ground line, and one data line to take messages from the Arduino to the LCD controller.

Some of what is in the following may "scare" you, but don't let it... is isn't so terrible, and you don't really have to fully understand it all.

For the Answers-To-LCD version of the Watch-The-ADC program you only need...

The LCD module will need to draw 5v from the Arduino. Don't worry, it doesn't draw much current. So there's one wire for that, and the complementary connection to the Arduino's ground (aka zero volt line). In addition, you need to connect a wire from a data pin of the Arduino. Which is up to you. I've used pin 8. You also, for the quiet life, need to set one Arduino pin aside and not use it. It CAN be used, if you really need to, but it if you are going to use it, you need to take care on several points. I've never been caught needing every Arduino pin, but will be able to cope when the day arises that I do have to "get clever" on this point. In this instance, I've set pin 7 aside to be left unused.

The code follows. If you look through it, you will find many elements which you have encountered before. Following the code, I will discuss the new lines.

28 Dec 09

Expects an analog input to "A0"
Displays reading on a LCD panel,
via a ModernDevice.com/ Peter Anderson LCD controller
(Kit LCD117)
The controller is driven by one digital output from
Arduino, plus one more pin should be set aside for an
unused RX channel

#include <SoftwareSerial.h>

int intAnValue=0;
const byte AnInputPin=0;//ADC pin that voltages will be fed to
const byte txLCDPin=8;//Pin messages for LCD will be sent on
const byte rxLCDPin=7;//Pin messages from LCD could be sent on... We
//aren't going to make any connections to this pin, or use any messages
//from the LCD.. but we have to provide a number to the software
//AS IF we might be making the connection/ reading the messages.

SoftwareSerial myLCDSerial =  SoftwareSerial(rxLCDPin, txLCDPin);

void setup()
  pinMode(txLCDPin, OUTPUT);
  pinMode(rxLCDPin, INPUT);
  myLCDSerial.begin(9600);//  setup connection to LCD
  myLCDSerial.print("?f");//Clear LCD screen

void loop()


The "#include <SoftwareSerial.h>" line causes the compiler to access a library of goodies. The library comes with the standard Arduino install. You don't have to track it down; you don't have to worry about "non-standard" things in it clashing with your "basic" Arduino work.

The lines...

const byte txLCDPin=8;
const byte rxLCDPin=7;

... are just like other "const" lines we've used to assign human friendly (well, almost) "names" to things that would otherwise be un-memorable mere numbers. And, like the connections to LEDs, using consts thus allows us to adapt programs quickly, easily. The names, as you can see, start "tx" and "rx". These are traditional abbreviations for "transmit" and "receive". The constants relate to the pins we will transmit TO the LCD module over, and receive things from the LCD module on. As ever with tx/rx pairs, don't become confused. The names are from the point of view of the Arduino. If we tx TO the LCD, the LCD is rx'ing, isn't it? (That's how people get confused!) Also... we aren't going to actually USE the rxLCDPin... but we still need to set one aside, to keep the software happy.

Confession time: I don't FULLY understand the line....

SoftwareSerial myLCDSerial =  SoftwareSerial(rxLCDPin, txLCDPin);

I DO know that it WORKS. What it does is create a virtual serial port, through which we can send things to the LCD monitor. I chose the three words which are not "SoftwareSerial"... i.e. I chose "myLCDSerial" (name for referring to the connection), "rxLCDpin" and "txLCDpin" (names for the pins the connection is going to be on.) You can, in your own work, in those spots, use whatever names are meaningful to you and appropriate to the project you are working on.

Moving on....

The "myLCDSerial.begin(9600);" is like the "Serial.begin(9600);" in the program which sent the ADC readings to the Arduino IDE's serial monitor. It "opens the door" for communications across the serial port created a moment ago... a new serial port, different and separate from the one that operates (still) through the USB cable you use for programming the Arduino.

The line....

myLCDSerial.print("Hello World");

...would put "Hello World" (without the quotation marks) on the LCD display.



... should, you would think, put "?f" on the screen, and you would be right. But! The LCD module has a few trick up its sleeve. When it sees a question mark it treats what comes next as a code. The code "?f" clears the LCD screen.

Now we come to the material in the "loop" function.... most of it old hat. We use the analogRead function to make a reading of the ADC. The answer, a number from 0 - 1023 goes into the variable intAnValue, just as before.


... causes that number to appear on the LCD module. myLCDSerial is an "object". We created it with the line I said earlier I can't fully explain. However, I do know that one of the parts of that object is its "print" function. And when you do myLCDSerial.print(intAnValue);, whatever is in intAnValue appears on the LCD.


... uses the LCD module's cleverness with "?"s. This time, the code means "start a new line".

And that's all there is to it! Some bits not intuitive, perhaps, but the display-things-on-the-LCD-module "tricks" are not very difficult, and the modules are not very expensive, nor do they "cost" a lot to use in ways other than cash, e.g. pins used up.

Diversion: The Arduino's pins

This would be a good place to take an important little diversion to talk about pin usage.

First of all, don't get confused between "pin 1" of the chip at the heart of the Arduino, and "pin 1" in terms of the connections to the outside world offered by "the Arduino", i.e. that chip plus the resistors, etc, on it's little PCB. Just to HELP you get confused, of course, there are sundry things, like the fact that the actual chip doesn't have a "pin 0", but the Arduino's complement of connections to the outside world DOES include a "pin 0". Unless you get into very advanced matters, I don't think you are likely to be considering the pins of the chip. The "Arduino connections to outside world" type pins are sometimes called its digital pins, which is helpful... but sometimes the word "digital" is omitted.

Then there's the fact to keep clear that the Arduino has "pin 0" and a pin "A0". The "A" prefix signifying that we are talking about one of the ADC inputs. To help you get confused here, there is the fact that, if you are desperate for additional general purpose digital input/ output pins, you CAN use pin "A0", and it's siblings "A1", "A2", etc. for general digital I/O. ("A0" can be used as pin "14"... but I wouldn't recommend it, if you are still an Arduino novice! There are no great perils to avoid, but you just don't need the extra confusion at this time, do you?)

Confused yet? Don't be! I'm just trying to cover ALL of the odds and ends you may stumble upon in your Arduino adventures.

Furthermore: In general: Avoid using pins 0 and 1. When you have the Arduino connected to a PC to program it, or to use the serial monitor, the Arduino and the PC will be using those two pins for those communications. You have lots of other pins to use. If you really, really need to use pins 0 and 1, try at least to use pin 0 for input and pin 1 for output. That way the circuitry you are connecting and the circuitry of the serial-over-USB port will be less likely to clash.

There are some other pins that you may one day want to reserve for special consideration, but avoiding pins 0 and 1 will do for now. Maybe avoid pins 2 and 3, while you're at it... but that won't be important until you are into attaching interrupts.

Here ends the "pins" diversion, and it was important.

Another little diversion: The Arduino's "map" function

Here begins the "map function" diversion, and it is NOT important.

In our program reporting what the ADC returned via three LEDs, we had....

if (intAnValue>299) setLEDs(0,0,1);
if (intAnValue>500) setLEDs(0,1,0);
if (intAnValue>700) setLEDs(1,0,0);

We knew (well, I told you!) that the ADC returned a number from 0 to 1023 (inclusive) The code above ROUGHLY splits that range up into four ranges.

The Arduino comes with a neat little function called "map" which we don't actually "need", but as it is there, we might as well use it.

Before we look at map, a little "computer arithmetic" I haven't gone into before.

Suppose I have an integer type variable called intTmp

If I do, I can say....


... to put 100 into that variable.

If I then do....


... the computer does the following. It looks at what is to the right of the equals sign first. It sees intTmp, which at the moment is "worth" 100. It sees "+3", so it adds three to 100, arriving at 103. It then puts that (103) in intTmp.

Remember: The equals sign doesn't mean what it meant when you were learning arithmetic when you were 8. It is best to read it as "becomes", so the line above reads....

"What is in intTmp BECOMES what WAS in intTmp, with three added."

(Remember also that you sometimes get a double equals sign, as in....

if (intTmp==103) {setLEDs(1,1,1)}

In such cases (the double equals sign) we are asking a question. "Does what is in intTmp EQUAL 103?". The whole think inside the parentheses is called a "condition". It boils down to "true" (intTmp DOES hold 103) or "false" (it doesn't).)

Hang in there... we'll get through this.

Suppose I do....


Because intTmp is an integer type datum, it can only hold whole numbers. 103 / 2 comes to 51, because the "half" is thrown away. That little gem of information to prepare you for the fact that "map", which we will come to, isn't "perfect". In some cases it will be quite approximate. But it isn't so lame as to be useless.

Cast your mind back to our ADC work. The initial answer in intAnValue could be anything from 0 to 1023... a pretty broad range.

If we did....


... we would have "chopped it down" to a more manageable, perhaps, 0-102. With map, we can do something even more clever.


will convert whatever is in intAnValue from something that can run from 0-1023 to values from 0-3.

If we add that use of the map function to our program, we can alter the "setLEDs" lines to the following, which is perhaps more transparent?

if (intAnValue==1) setLEDs(0,0,1);
if (intAnValue==2) setLEDs(0,1,0);
if (intAnValue==3) setLEDs(1,0,0);

Okay so far? you shouldn't be! There's a mistake in that, which you should be able to spot, if you think.

Map "translates" numbers from one range to another. In our example we had numbers that ranged from 0 - 1023, and we wanted to "squeeze" them onto a narrower range. When we said....


...we were saying "take what's in intAnValue, and do to it what would change numbers from 0-1023 to a range of 0-3. In the numbers we are starting with, the top number is 1023. In the numbers we want that range mapped to, the top number is 3... and only 1023 will translate to 3. If we wanted to "chop up" 0-1023 into four bands, we should have said....


Now, as we turn the potentiometer from low to high, the result will be 0 for about a quarter of the process, 1 for a quarter, 2 for a quarter, 3 for the last quarter, and, right at the end, when the potentiometer returns "1023", after mapping we will get 4.

Which is a slight nuisance, as our nice neat code is messed up a little, as follows:

if (intAnValue==1) setLEDs(0,0,1);
if (intAnValue==2) setLEDs(0,1,0);
if (intAnValue==3) setLEDs(1,0,0);
if (intAnValue==4) setLEDs(1,0,0);

That extra line should annoy you. Yes, the code works, but it is a little oddity for your mind to trip over if you even have to go back and revisit this code.

One solution would be....

if (intAnValue==1) setLEDs(0,0,1);
if (intAnValue==2) setLEDs(0,1,0);
if (intAnValue>2) setLEDs(1,0,0);

... which isn't perfect, but has some advantages. Sigh.

Here ends "map function" diversion... and this long tutorial! When you have had a break to recover, and come back for more: No more skimming! Back to your usual careful "read, mark, learn mode", please. Things that may seem "unimportant" to you now may be more important than you realize!

   Search this site or the web      powered by FreeFind

Site search Web search
Site Map    What's New    Search




Click here to return to Arduino COURSE table of contents.
Click here to go to the author's home page.

Click here to visit editor's freeware, shareware page.

