- [Instructor] Are you trying
to send numerical values over the serial port using
parseInt with Arduino, like you're trying to send
integers or something like that? Maybe you're struggling to
understand the difference between serial.read and serial.parseInt and how they can work for you. Do you just need to convert
multiple digit characters to one integer? Well, in this lesson,
you will learn exactly how to use parseInt from
the Arduino serial library to convert characters into an integer. Get ready (lighthearted music) Subscribe to our YouTube channel to get more videos like this. Are you learning Arduino programming? Check out our membership
program to learn the software and hardware skills you'll need
to build your own projects. You will get an all-access pass to our high-quality video training that covers everything from
the basics of programming like variables and control structures up to using interrupts, arrays, and more. Follow the link in the
description to sign up today. All right, let's talk about
what we're gonna cover. First, we'll do a quick overview
of serial communication. We'll compare serial.read
with serial.parseInt. We'll play around with some code for converting characters
to integers with parse.Int. And then we're gonna talk about the several parseInt
details, like setTimeout, lookahead mode, and ignore. If you've already watched our
lesson on using serial.read, then you already know one
method of taking serial input and converting the
characters into an integer by putting all the incoming
bytes into a character array. If you wanna learn that method, make sure to check out
the lesson on serial.read. Now, that code worked great,
but it was somewhat lengthy. In this lesson, we're gonna talk about
a different way to do it and we'll be using the function from the serial library called parseInt. So let's do a quick review of how serial communication
works with Arduino. Your Arduino has some hardware on it that will allow you to receive
data serially over USB. It will store that data in a buffer called the
serial receive buffer. Now, if the word buffer throws
you off, don't sweat it. You can think of a buffer
like a bunch of horse stalls in a stable. Some stables are big and
have a bunch of stalls. You can put a bunch of horses in there. Other stables are quite small and you only have room for so many horses. You can't take in more
horses than you have stalls. A buffer is like a stable, but instead of having horse stalls, it has spaces and memory
where the data can be stored. Generally speaking, a
buffer is a transient place for data storage in a program. Usually you're gonna be
receiving data into a buffer and then reading it out pretty quickly because more data is gonna be coming in and you need to make space for it. This isn't some hard and fast rule though. The serial receive buffer
has room for 64 bytes. So when data comes to
your Arduino over serial, each byte will end up in
this serial receive buffer. It's your job as the programmer to read the data out of
the serial receive buffer and actually do something with it. Say your Arduino is attached
to your Raspberry PI and the Raspberry PI has a
program sending serial data to your Arduino. You've got to do something
with that serial data that's ending up in the
serial receive buffer. But how do you do that? Well, it turns out
there's quite a few ways. If you wanna take out each byte at a time, then you can use the serial.read function. When you use serial.read, it takes out the first
byte in the serial buffer. And that's what it returns. The rest of the bytes then shift over. If your serial received buffer was filled with the
characters, SeaBiscuit, and you call serial.read once, then the capital S would be read out and eaBiscuit would be left, every character having shifted over so that now the lower cased
E is the next in line. Serial.read is great if you
wanna read in each character at a time and then maybe do some things based on different
characters that come in. But what if you wanna get
a whole number like 1776? If you use serial.read, you'd get a one and then you'd get a seven and
then you'd get another seven and finally you'd get a six. Plus, they'd all be stored as
characters, not as integers. And you don't want one
digit integers all the time. You might want the whole number
1776 saved as an integer. Now, as I mentioned before, we talked about how to accomplish
this in the last lesson using a character array
and the atoi function. But there's a somewhat simpler method if all you wanna do is
convert the character input into an integer. That's where the parseInt
or parseInteger function from the serial library comes in. What the parseInt function will do is scan down the serial receive buffer one byte at a time in search of the first
valid numerical digit. So if you have the characters, 314, in the serial receive buffer, you'd get 314 returned the first time you call serial.parseInt. If you had "I ate 314 tacos" in the serial receive buffer, you'd only get 314 returned the first time you call serial.parseInt. So parseInt is looking at the first item in the serial receive
buffer and it's checking, "Hey, is this character
a numerical character like zero through nine or a negative sign? If it is, I'm gonna go
ahead and start reading in until I get to a non-numerical character." This scanning that parseInt does allows you to grab an entire integer out of the serial receive buffer. What does serial.parseInteger do with non-numeric values in
the serial receive buffer? If the non-numeric values are only before a valid numerical digit, what it does is it tosses them out. It grabs those numerical digits. Then it leaves the rest in
the serial receive buffer. So if in our serial receive buffer we had "I ate 314 tacos," when we call serial.parseIn
the first time, it's gonna skip over I ate. It's gonna grab the 314 and
combine them into one integer. And then it's going to
leave the space tacos in the serial receive buffer. It's not gonna touch that. What does parseInteger do if
there's only non-numeric values in the serial receive buffer. If all parseInteger can see
in the serial receive buffer are non-numeric values,
it's gonna return a zero and it's gonna leave
all those values sitting in the serial receive buffer. It's probably like, "Hey,
why are you calling me? There's no numbers in the
serial receive buffer. That's what I'm for, getting
the integers, not this stuff." Now, if you start getting a bunch of zeros returned from parseInt
and you're not sure why, remember that newlines and
carriage returns maybe added when using the serial monitor
window in the Arduino IDE, even though you're not
actually gonna see them in the send section
where you enter the text. If you don't want these
terminating characters, make sure to select No line
ending from the dropdown. Now, a common method of using
parseInteger is to pair it with a while loop and serial available. So that the only time you
check for a new integer is when data has actually
arrived at the serial port. Now, if this code
structure looks odd to you, then check out the lesson
that we did on serial.read because it explains it in depth. So this code construct here
is how you can convert data coming in over serial in
the form of characters into a whole integer. But there's a couple
really important things you need to know about
the parseInteger function. As they say, the devil is in the details, and parseInt has a couple
of really neat details. The first of these interesting
details is that parseInteger actually returns a long data type. It's not an integer data type. So if you've got a big number coming in, you can save it into a
long data type variable. Second is the fact that
parseInteger will time out after a given programmable set point. The default set point is one second or a thousand millisecond. Let's say, for example, it takes awhile for your data to arrive
at the serial port. Like maybe every 300 milliseconds,
you get a new character, maybe you get the three digit, 300 milliseconds later
you get the one digit, 300 milliseconds later
you get the four digit, 300 milliseconds later you get the five. So the total time to
receive the value 3145 is 900 milliseconds. Instead of just reading
out each of those values as it arrives, parseInteger is gonna wait
that set amount of time before it returns the
integer that it's found. To adjust the timeout period, you use the function serial.setTimeout, and you parse in the amount of time that you want parseInteger to wait. So in the example above, parseInteger would read out
the three as soon as it came. It's still in that timeout period. And then when the one came
up, it would read the one out and add that to the end of the three. So now we'd have 31. It'd still be waiting. The timeout period's still going. It grabbed that four when it
came in, added to the end. So we'd have 314. And then finally, the five came
in just in the nick of time and then it put the five at the end. And it would return the integer 3145 or 3,145 as one integer. But what if the delay was even longer for incoming characters,
say 400 milliseconds? So we'd be able to get the 314 but then that last digit
five would still be sitting in the serial receive buffer because it didn't make it in in time. So the first time parseInteger
is called, we get 314. The next time we call
parseInteger, then we get the five. Again, the devil's in the details. This set timeout function is something you'll
definitely want to explore. It's kind of interesting to play around with that timeout period and
see what results you get. Another interesting detail
of the parseInteger function is that you can call it
with optional parameters. The first optional parameter
is called lookahead mode. And there are three predetermined
lookahead mode values that you can send, skip,
skip_all, and skip_whitespace. Skip_all is the default mode which is used when you call serial.parseInt
and you don't parse anything. So you could use it explicitly like serial.parseInt skip_all. That would be the same thing as just calling serial.parseInt. So it's the default mode. With the skip_all mode, all characters other than numerical digits in a minus sign are ignored as parseInteger scans down
the serial receive buffer in look of its first numerical digit. This is the behavior that
we've already explored. If you use the skip_none mode, what this does is tell parseInteger, as it scans down the serial buffer, not to skip any of the items. So basically what it's saying is, "Hey, when you look at that first value, if it is not a numerical
digit or a negative sign, then we're not gonna mess with anything in the serial receive buffer,
and it would return a zero." So let's say your serial buffer you had "You ate 314 tacos." If you call parseInt,
it's gonna return a zero. It's going to say, "Hey,
you told me to skip none. The letter capital Y is
not a numerical digit, so I'm not even gonna mess with this." Finally, with lookahead
mode set to skip_whitespace, then only tabs, spaces, line feeds, and carriage returns are skipped. Now, tabs, spaces, line
feeds, carriage returns, they are all represented in ASCII. So they all have ASCII values. And those ASCII values are
what is going to be skipped when we use skip_whitespace. So let's say your serial receive buffer you had a bunch of spaces. So again, there's an
ASCII code for a space. So you have a bunch of spaces. Then you have the numerical numbers, 314, another space and then tacos, exclamation. If you call parseInt with
skip_whitespace's lookahead mode, it's gonna skip all that white space and then grab the 314 for you. This lookahead feature is pretty cool, especially if the data you're receiving has a bunch of mixed things, like maybe you're sending
character commands like turn on and turn off, but you're also sending numerical values like 314 or whatever. These options give you
one way to differentiate between that incoming serial data. But is there a way to
ignore specific characters coming into the serial port and just grab the numerical values? Well, in fact, there is because parseInteger has
another optional parameter that you can parse. So first, we have the lookahead
mode that we can parse. And after that, we can send a character that we want to ignore. For example, maybe you've got commas on the incoming data stream or any character for that matter. You can parse that character
as the ignore value. So if in the serial buffer you had 3,142 and you had a comma in there, parseInt would ignore the comma and grab out the 3,142 for you. That's pretty cool. This can come in handy if there are characters you
don't want to act as delimiters in your number. Also, when you're putting in the value, make sure to use single quotes
around your ignore value so that parseInteger knows
that it's a single character. All right, we covered a ton. Let's do a recap here. So we talked about how serial data, when it arrives at the serial port, it goes to the serial receive buffer. We said that, hey, serial.read is great, but it only reads in one byte at a time. We talked about how
parseInteger can be used to convert characters in the serial receive
buffer into integers. We talked about three lookahead modes, skip_all, skip_none, and skip_whitespace. We know that the default
lookahead mode is skip_all. We also talked about how you
can ignore a specific character in the serial receive
buffer with parseInteger. Thanks a ton for watching, and I hope you learned something useful. Make sure to check back soon
for other great lessons. Hey, take it easy. And I look forward to
seeing you next time. Bye. (gentle music)