Overview of the Serial Communication Protocol
Setting Up the Arduino
Notice that the Arduino code (Listing 1) does not have much logic. The only thing it does is respond to incoming messages. In this case, whatever program is controlling the device makes all the decisions, so the logic lives elsewhere. The Arduino just follows the instructions it receives over the serial port and reports changes to the attached inputs.
Listing 1
Arduino Code
01 #include <Servo.h> 02 03 Servo servo; 04 int oldSwitch = 0; 05 int oldButton = 0; 06 07 void setup() 08 { 09 pinMode(2, INPUT_PULLUP ); 10 pinMode(3, INPUT_PULLUP ); 11 pinMode(13, OUTPUT); 12 Serial.begin ( 9600 ); 13 Serial.setTimeout ( 5000 ); 14 15 servo.attach ( 11 ); 16 } 17 18 void loop() 19 { 20 char incoming=0; 21 int readState=0; 22 23 if ( Serial.available() ) 24 { 25 incoming = Serial.read(); 26 if ( incoming == 'L' ) digitalWrite ( 13 , HIGH ); 27 else if ( incoming == 'l' ) digitalWrite ( 13 , LOW ); 28 else 29 { 30 int i=0; 31 String fullNumber = String ( incoming ); 32 String number; 33 34 number = Serial.readStringUntil ( '.' ); 35 fullNumber.concat ( number ); 36 i = fullNumber.toInt(); 37 38 if ( i >= 0 && i <= 180 ) servo.write ( i ); 39 } 40 } 41 42 readState = digitalRead ( 2 ); 43 if ( readState != oldButton ) 44 { 45 oldButton = readState; 46 Serial.print ( "Button:" ); 47 Serial.println ( readState ); 48 } 49 50 readState = digitalRead ( 3 ); 51 if ( readState != oldSwitch ) 52 { 53 oldSwitch = readState; 54 Serial.print ( "Switch:" ); 55 Serial.println ( readState ); 56 } 57 }
Lines 1-5 bring in the appropriate library and initialize global variables: servo
from the Servo.h
library represents a servo motor, and the integers oldSwitch
and oldButton
store previous states of the button and switch.
The Arduino calls the setup
function (lines 7-16) once when the program is first run. As the name implies, it sets up any Arduino features that will be used and initializes any hardware that needs to be set up before the main loop runs. In this case, it sets up input and output pins and the serial port.
Lines 9-11 tell the Arduino whether the specified pin is used as an input or an output. The first argument is the pin number, and the second argument is the mode. The INPUT_PULLUP
mode not only sets the pin to an input but also enables the Arduino's pull-up resistor.
Buttons and switches are passive components (not electrically active on their own) so the pull-up resistor provides the electrical equivalent of a default value. The pull-up resistor is relatively weak, so when the button or switch is connected to ground, the pin will see that instead, which guarantees a clean 0 or 1 each time the button or switch changes.
The Arduino Uno has one serial port located on pins 0 and 1. You'll notice, though, that nothing is connected to those pins. It also has a USB-to-serial converter as part of its onboard hardware, but everything happens behind the scenes, so you don't have to worry about it. I'll be using serial from the attached computer over the USB port.
The Serial.begin
function tells the Arduino to turn on the serial port (as opposed to being a general-purpose I/O), and 9600
is the baud rate. Serial.timeout
tells the Arduino that any code waiting for input from the serial port should stop waiting after 5,000msec, which prevents the program from stalling if a proper signal isn't received. Eventually, it will time out and move on with the program.
Servo Setup
The servo
variable created in line 3 hasn't been connected to anything yet, so the servo.attach
line tells the Arduino which pin the servo is on (11 in this case).
The special Arduino loop()
function starts in line 18 and does exactly what its name implies: It runs continuously until power is removed from the Arduino.
After initializing two local variables, incoming
and readState
, a checking routine looks for any characters that are available from the serial port. Serial.available
returns the number of characters waiting in the buffer. If it is not zero, the processing inside the if
statement proceeds.
The Serial.read
gets the first character from the serial port and saves it in the incoming
variable. If the incoming character is an uppercase L, a call to digitalWrite
turns the LED on; otherwise, the program checks for a lowercase l, which turns off the LED.
By line 28, if nothing has happened, the Arduino has probably received a number, which is processed in lines 29-39. After initializing the local variable i
to 0, lines 31 and 32 set up strings for the incoming data from the serial port. The fullNumber
variable is given an initial value of the string version of incoming
– the first character received (i.e., the first digit).
The variable number
is initialized to a blank string. Line 34 requests characters from the serial port until it receives a period. The received characters go into number
, which is concatenated to fullNumber
in the next line. Now fullNumber
really does have the full number received from the port. Line 36 uses toInt
to turn the string into an integer and stores it in i
.
Finally, if i
is greater than 0 and less than 180 (the valid range for a servo), servo.write
asks the servo to move to the angle specified in i
.
Buttons and Switches
Variable readState
stores the state of Arduino pin 2, which determines whether the button is pressed or not. Note that a value of 0 is pressed and 1 is not pressed, which might seem backward.
If readState
is different from oldButton
, the button has changed state. In that case, line 45 updates oldButton
, line 46 sends the string Button:
out the serial port, and line 47 sends the new state of the button; Serial.println
then tells the Arduino to add a newline after printing the readState
variable.
Checking the switch works exactly the same as checking the button, except on pin 3 (line 50) and by checking and updating oldSwitch
(lines 51 and 53) instead of oldButton
and printing Switch:
instead of Button:
(line 54).
Buy Linux Magazine
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Subscribe to our ADMIN Newsletters
Support Our Work
Linux Magazine content is made possible with support from readers like you. Please consider contributing when you’ve found an article to be beneficial.
News
-
TUXEDO Computers Unveils Linux Laptop Featuring AMD Ryzen CPU
This latest release is the first laptop to include the new CPU from Ryzen and Linux preinstalled.
-
XZ Gets the All-Clear
The back door xz vulnerability has been officially reverted for Fedora 40 and versions 38 and 39 were never affected.
-
Canonical Collaborates with Qualcomm on New Venture
This new joint effort is geared toward bringing Ubuntu and Ubuntu Core to Qualcomm-powered devices.
-
Kodi 21.0 Open-Source Entertainment Hub Released
After a year of development, the award-winning Kodi cross-platform, media center software is now available with many new additions and improvements.
-
Linux Usage Increases in Two Key Areas
If market share is your thing, you'll be happy to know that Linux is on the rise in two areas that, if they keep climbing, could have serious meaning for Linux's future.
-
Vulnerability Discovered in xz Libraries
An urgent alert for Fedora 40 has been posted and users should pay attention.
-
Canonical Bumps LTS Support to 12 years
If you're worried that your Ubuntu LTS release won't be supported long enough to last, Canonical has a surprise for you in the form of 12 years of security coverage.
-
Fedora 40 Beta Released Soon
With the official release of Fedora 40 coming in April, it's almost time to download the beta and see what's new.
-
New Pentesting Distribution to Compete with Kali Linux
SnoopGod is now available for your testing needs
-
Juno Computers Launches Another Linux Laptop
If you're looking for a powerhouse laptop that runs Ubuntu, the Juno Computers Neptune 17 v6 should be on your radar.