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
-
Gnome 47.2 Now Available
Gnome 47.2 is now available for general use but don't expect much in the way of newness, as this is all about improvements and bug fixes.
-
Latest Cinnamon Desktop Releases with a Bold New Look
Just in time for the holidays, the developer of the Cinnamon desktop has shipped a new release to help spice up your eggnog with new features and a new look.
-
Armbian 24.11 Released with Expanded Hardware Support
If you've been waiting for Armbian to support OrangePi 5 Max and Radxa ROCK 5B+, the wait is over.
-
SUSE Renames Several Products for Better Name Recognition
SUSE has been a very powerful player in the European market, but it knows it must branch out to gain serious traction. Will a name change do the trick?
-
ESET Discovers New Linux Malware
WolfsBane is an all-in-one malware that has hit the Linux operating system and includes a dropper, a launcher, and a backdoor.
-
New Linux Kernel Patch Allows Forcing a CPU Mitigation
Even when CPU mitigations can consume precious CPU cycles, it might not be a bad idea to allow users to enable them, even if your machine isn't vulnerable.
-
Red Hat Enterprise Linux 9.5 Released
Notify your friends, loved ones, and colleagues that the latest version of RHEL is available with plenty of enhancements.
-
Linux Sees Massive Performance Increase from a Single Line of Code
With one line of code, Intel was able to increase the performance of the Linux kernel by 4,000 percent.
-
Fedora KDE Approved as an Official Spin
If you prefer the Plasma desktop environment and the Fedora distribution, you're in luck because there's now an official spin that is listed on the same level as the Fedora Workstation edition.
-
New Steam Client Ups the Ante for Linux
The latest release from Steam has some pretty cool tricks up its sleeve.