You'll need Arduino serial read to get data into your Arduino but first you will need to initialise the serial port with Serial.begin() followed by Serial.available() to check if any new data is ready from the serial port.
Given that the internal serial port hardware can only accept one byte at a time from the serial link, and you want to accept lots of character data from the port continuously.
The question is how can you ensure that no data is lost if your program is busy doing something else?
The answer is you don't have to think about this! But you should.
Code underlying Arduino Serial read implements interrupt driven input and circular buffering for both receive and transmit directions.
Code written in HardwareSerial.h and HardwareSerial.cpp defines circular queues that are 64 bytes long unless your Arduino SRAM space is less than 1024 bytes in which case the buffers are 16 bytes long.
There are also head and tail pointers:
volatile rx_buffer_index_t _rx_buffer_head;
volatile rx_buffer_index_t _rx_buffer_tail;
volatile tx_buffer_index_t _tx_buffer_head;
volatile tx_buffer_index_t _tx_buffer_tail;
You can also see that there are two pointers for each buffer, so for
an Arduino Uno or Nano 128Bytes are reserved for serial buffering. Just
in case you were wondering where your SRAM disappeared!
The code also defines two interrupt vectors:
inline void _rx_complete_irq(void);
id _tx_udr_empty_irq(void);
These are attached to the RX buffer and TX buffer interrupts respectively.
When the RX interrupt triggers, a byte of data is placed into the circular buffer at _rx_buffer_tail and _rx_buffer_tail is incremented. When you use Serial.read() to get the data out bytes are read out from _rx_buffer_head until _rx_buffer_head equals _rx_buffer_tail - when the queue is empty.
Because it is a circular buffer code ensures that _rx_buffer_tail and _rx_buffer_tail wrap correctly.
A similar operation is done for the transmit buffer.
So what do circular buffers do for you?
Essentially interrupt driven circular buffers allow the processor to
do other tasks without continually having the poll the serial hardware.
So your program can be off doing some other important task and does not
have to read the serial hardware, as that is done in the background.
The reason it works is that reading bytes from the SRAM is very fast -
and your code does not have to wait for the serial port to update as
data is transferred directly from the serial port hardware to the
circular buffers automatically when a serial interrupt is generated.
Lets assume that the serial port is initialised to 9600Baud and since
the Arduino buffer is 64 bytes long it could receive 64 bytes.
The time that could be spent in this is (1.0/9600)*64 = 6.6ms. i.e. this
is the maximum time you could wait not getting data from the port. So
for an
Arduino running at 16MHz that is 6.6e-3/(1.0/16e6) = 105600
instructions.
That is a lot of instructions and means in practice the Arduino has
plenty of time to do other stuff and can occasionally read the serial
port with:
Serial.read();
If you did not have a circular buffer you would need to read the
internal serial port hardware buffer every (1.0/9600)s or every
104us. That would allow 104e-6/(1.0/16e6) = 1664 instructions - far less
than before so your program would be forced to read the data more
often.How to avoid the trap, that you could easily fall into, of missing data.
The example is very simple and outputs whatever character is
received from the serial port (one character output per line).
Serial.available() is used to find out if there is any data at the port,
and because of the circular buffers used in the Arduino code there
could
be more than 1 character available, which is why the comparison
"greater
than" is used.
If there is a character available then it is printed to the serial
output port using Serial.println() - the data appears in the Serial
monitor in the Arduino IDE.
// Example showing Arduino Serial read operation
void setup() {
Serial.begin(9600);
}
void loop() {
char ch;
if (Serial.available() > 0) {
ch = Serial.read();
Serial.println(ch);
}
}
This is the output you will see in the serial monitor
You have to type in a string of data in the serial monitor and then
press enter to transmit the string to the Arduino where the following
transparent text is shown "Message (Enter to send message to 'Arduino
Uno' on 'COM4')"
Here the text "hello<Enter>" was typed.
When developing some programs I often use a serial terminal program
as I don't want to have to hit Enter all the time - the data is sent
immediately so that a program action can happen immediately.
You can use a character delimiter (detected in the program) to
separate commands if you want to, or initially just react to the alphabet to
do stuff immediately (or a mixture of both) - the serial decode can get
quite complicated e.g. if you want to send floating point data etc.
The Arduino Serial read function is easy to use and provides built in
buffers that allow serial port data to be captured with ease.
All you do is occasionally use the Serial.read() function in the main
loop of your program, to receive serial data from the internal serial
port hardware.
Ensure you read the buffer fast enough compared to the Baud rate - to avoid the trap of missing data. Note that if you increase the Baud rate the buffer will fill up faster so read it more often. As discussed above this also depends on the speed of output of the serial generating device.
You can see an example of serial asynchronicity using just your Arduino here.
The two other functions that for a basic part of Serial code are:
Serial.available()
Serial.begin()
Comments
Have your say about what you just read! Leave me a comment in the box below.
Don’t see the comments box? Log in to your Facebook account, give Facebook consent, then return to this page and refresh it.