Saturday 5 September 2020

Serial Communications with Arduino Part 2 - Software Serial Ports

 Last recently, I put up a short post on how we can use Arduino to read data from a device. Cunningly, I made the process so simple (mainly for myself) that I neglected to actually use an Arduino.

So, in this post I will remedy that by providing an example on how to read data from a device using serial communication at the start, then move on to writing to the serial port.

In the last post, I gave an example of how you can connect a USB to TTL adapter to a device and read its data. This time round, we are going to use the UNO R3 to act as our USB to serial adapter. To do this, we are going to be using the following

  • 1x    breadboard
  • 1x    Arduino UNO R3 
  • 1x Neo-6M/GY-GPS6MV2 GPS Module
  • 1x CH340 USB to TTL adapter
  • Jumper wires

The proposition is quite simple; we want to send the output of the GPS module to the board over a serial port. Unfortunately, I have not found a way to simply connect it to the TX/RX pins on the board itself and have it output data. So, to accomplish this we need to create a second serial port to handle the incoming stream of information from the GPS module itself and we need to create that port in software.

To do this, we are going to have to use the Software Serial Library.:

1:  #include "SoftwareSerial.h"  
2:  SoftwareSerial ss(8, 9);  
The first line references the library we need to use in this program. If you get an error when compiling this code, you might want to check that you have this library installed from within the Library Manager.

The second line is simply us creating a new software serial port called "ss", the numbers following represent the RX and TX pins on the board.

Next, we have to set up our ports, this should be familiar to anyone who has been using the Serial Monitor from within the Arduino IDE: 
1:  void setup() {  
2:   // put your setup code here, to run once:  
3:   Serial.begin(9600);  
4:   ss.begin(9600);  
5:  }  

Here we can see that on line 3 the hardware serial port is started with a baud rate of 9600 - this is the speed at which the port is reading/writing at. Line 4 is almost exactly the same, however this is the software serial port that is being started this time, note that we are also starting it at the same baud rate.

From reading up on using this library, it seemed that 9600 was the highest baud rate to go for and still have a stable connection. The GPS module can work up to 115200 baud, however when I configured the serial ports to use this speed, nothing happened.

Next up, we have the main executing of the code itself. We read the data leaving the GPS module on its TX port on to the boards hardware RX port and vice versa: 
1:  void loop() {  
2:   // put your main code here, to run repeatedly:  
3:   if (ss.available())  
4:    Serial.write(ss.read());  
5:   if (Serial.available())  
6:    ss.write(Serial.read());  
7:  }  

Line 3 checks to see if the software serial port is available, if it is then the hardware serial port then writes whatever the software serial port is reading on line 4.

Line 5 does the opposite, if the hardware serial port is available the software serial port writes whatever the hardware serial port is reading - which happens to always be whatever the software serial port is reading due to the structure that we have created.

Think of the above as an exchange - the hardware serial port is empty until it reads the incoming message from the software serial port. Once it has that, then both ports will have the same message.

Make sure you have your serial monitor running when you upload the code, you should see something like this:


The full listing for the code will be at the bottom of this post.

At the start of this article I mentioned that I used a CH340 USB to TTL adapter for debugging. This is because I had a fairly hard time getting the software serial port actually doing what I wanted it to do, quite a few of the articles I had read on the subject provided examples that simply did not work so I began to think my GPS module had become damaged.

So, to verify that the GPS module was working whilst the board was running the code, I connected it in series with the wires going from the GPS module to the board.

This let me run putty to make sure that I was getting something from the GPS module itself and make sure there was an incoming message for the board to do something with. It was actually quite helpful to do this while figuring out my problem. 

The setup, minus the USB to TTL adapter, looks like this:


If you are trying this out for yourself, then hopefully you are seeing a nice barrage of NMEA sentences scrolling across your serial monitor.

However, if you are seeing nothing, then try swapping your RX/TX pins on the board itself. You might have gotten them mixed up - I certainly did a couple of times.

SoftwareSerial is not the only library available that can do the same thing. Another, very popular library you can install is AltSoftSerial. Syntactically, it is almost identical to SoftwareSerial and supports a wide arrange of MCU's and development boards. You can also use a mixture of different libraries to give yourself multiple serial ports to work with, should you need to, for example if you had a number of devices that provided data in the same way as the GPS module you will need to have more than one serial port configured to a set of pins. That way you will have an uninterrupted flow of data from each device on its own serial port.

So what does all of this mean? Well essentially it is just a description of how you can easily set up a couple of serial ports to share data. But in this specific context, where could we take the build next? We are using a GPS module and we can see the NMEA sentences that it is receiving. We also know that each sentence begins with a $, so we could easily read the sentences into an array or object in order to process them further.

From looking at the output, we can see that there are six distinct types of sentence being received, or at least the module is trying to populate the contents of six sentences with data from the GPS constellation, with that knowledge we might be able to do something useful with that data...

The full code listing for used for this article is as follows: 

1:  #include "SoftwareSerial.h"  
2:    
3:  SoftwareSerial ss(8, 9);  
4:    
5:  void setup() {  
6:   // put your setup code here, to run once:  
7:   Serial.begin(9600);  
8:   ss.begin(9600);  
9:  }  
10:    
11:  void loop() {  
12:   // put your main code here, to run repeatedly:  
13:   if (ss.available())  
14:    Serial.write(ss.read());  
15:   if (Serial.available())  
16:    ss.write(Serial.read());  
17:  }