In this blog post, we will continue to learn C++ using Arduino and Arduino IDE. We will learn how to write a C++ class to send and receive data via UART or serial port. Although Arduino provides two classes to interact with serial interface, Serial and SoftwareSerial, we won’t be using these classes. We will write our own class from scratch.
How does UART work
This section describes briefly about UART (Universal Asynchronous Receiver Transmitter). In UART, one device talks with another device using two wires. In our project, one device is a Arduino Mega 2560 board, the other device is a computer which can be a Mac or a PC. For two devices to talk using UART protocol, they use two wires to transfer signals. On one side, the Rx pin of Arduino is connecting to a Tx pin of the computer, the Tx pin of the Arduino is connected to the Rx pin of the computer. The Arduino sends data to the computer via its Tx pin. The computer sends commands to Arduino via its Tx pin and Arduino receives commands through its Rx pin. You might wonder where are those Tx and Rx pins? You only see the Arduino board connects to the computer via a USB cable. On the Arduino, there is a chip, Atmega 16U2, that converts UART signals to USB signals and actually the computer is physically connecting to the Atmega 16U2 chip. The actual communication between a serial terminal program and the Arduino happens in a few steps. The serial terminal program sends data to the USB port, the data is transferred to the Atmega 16U2, then the Atmega 16U2 converts data to UART packets and delivers them to the Arduino. We can ignore the middle parts which convert UART to USB and USB to UART and think that the Arduino and a serial terminal program (Serial Monitor) is talking directly via UART.
For Arduino and Serial Monitor to understand each other via UART, they must first agree on a common communication speed. One device will send out data at a certain speed and the other device will interpret data at the same speed. Unit of speed is number of bits per second or baud. In our project, we will implement baud rate of 9600 which means there will be 9600 bits transferred in each second. That means the duration of each bit (0 or 1) is 1/9600 ~ 104 microsecond. Remember this number as we will later use it in our code. Another thing to note is if a device needs to initiate the communication, it will signify the other device by sending a start bit. When there is no data to transfer, pin Tx of Arduino is held High. If Arduino wants to send data, it first needs to send start bit by pulling its Tx pin Low for 104 microsecond. Then, it sends out data, bit by bit. In our project, we will set the number of bits in each data packet is 8, and Arduino will send the least significant bit first. After all 8 bit has been sent, Arduino needs to send the stop bit by pulling its Tx pin High for 104 microsecond. To receive data from the computer, Arduino will need to read its Rx pin status until it detects a change from high to low. That’s when it knows the computer is going to send some data over. It will then need to sample 8 bit data, knowing in advanced that each bit is 104 microsecond long, followed by a stop bit. Combining all the bits it receives, remember that the least significant bit is received first, Arduino can recover what the message is. There are more about UART, such as parity check bit, however, once we understand the basic, it is trivial to learn the rest.
Declare MyUART class
We now start writing a C++ class named MyUART to allow Arduino to communicate with the computer via UART. Open Arduino IDE, type in the class definition which looks like this:
There are a few things to note here. Firstly, since Arduino IDE is built based on C++ and behind the scene, it is using a C++ compiler, C++ code is interpreted without any problem. Arduino has done a great job of hiding all complex concepts and make Arduino beginner friendly. It is also a perfect tool to learn more advanced C++ concepts. Secondly, there are some C++ concepts in the above code snippet. We have declared two variables tx_pin and rx_pin of type int. These are data members of MyUART class. These variable are used to specify the Tx pin and Rx pin or UART interface, Tx pin is for sending data and Rx pin is for receiving data. In principle, we can specify any pin for UART transmission as we are controlling I/O pin directly. For our project, we will use pin 1 for Tx and pin 0 for Rx as those are physical pins that connect to Atmega 16U2 which in turn connect to computer via USB cable.
We also declare three function members. The first function MyUART(int t_pin, int r_pin) takes two int parameters and does not have a return type. This function is called constructor and is called once when an instance of a class is created. In the constructor, we initialise the data members tx_pin and rx_pin. To create an instance of class MyUART, we write
This code will create an instance of class MyUART and call constructor function and assign pin 1 as the Tx pin, pin 0 as the Rx pin.
The other two functions are normal member functions which are used to send a character and receive a character. The data members are declared as private and function members are declared as public. Private means the data member can only be accessible from function members and can not be accessed from outside. That means we can not write mySerial.tx_pin = 1 or mySerial.rx_pin = 1. Public means the member is accessible outside of class definition, for example, it is fine to call mySerial.send_char(‘1’) to send character ‘1’ over the UART because send_char() is a public function. Usually data members are defined private to prevent accidental modifying their values outside of class definition.
Implement MyUART functions
The constructor implementation looks like
In the constructor, we assign the Tx and Rx pin numbers, then configure Tx pin as output pin and Rx pin as input pin. Tx pin is configured as output as Arduino is driving the pin high and low to send data. Rx pin is configured as input with internal pull up resistor as Arduino will read data transferred from computer through it. We also initialise Tx pin high as normal the Tx is held high when no data is transferred.
Sending a character over UART
Sending a character (8 bit) is implemented by function send_char which looks like this
Note that we have defined the data rate in advanced (9600 bits per second or 9600 baud which is equivalent to 104 microsecond per bit as discussed above). The sequence is straight forward: send start bit, then send 8 data bit via a for loop, then send the stop bit.
Receiving a character from UART
The function to receive a character (8 bit) looks like this
Once again, we have agreed in advance about the communication speed of 9600 baud, the number of bits per packet is 8 (one character). This function reads the Rx pin repeated until is is pulled low by the computer which signify beginning of data transfer. It waits 104 microsecond for the start bit to pass, then it starts sampling data at interval of 104 microsecond. After receiving the stop bit, it combines all data and return the character value. If the computer transfers data at a different rate, this will not work as the time at which Arduino sample data would be wrong.
Controlling LED from computer via UART
With the above functions, we can write a simple application to turn on or off a LED on the Arduino by using Serial Monitor from the computer. The main program looks like this
The code is self explanatory. Declare an instance mySerial of class MyUART and assign pin 1 as Tx pin, pin 0 as Rx pin. In setup() function, initialise the built in LED on the Mega 2560. In the main loop function, call receive_char() function member of mySerial to receive a character from computer. If a character is received, send it back to the computer whatever it gets. If it gets ‘1’, turn on led and ‘2’, turn off led.
You can compile the program, upload it to the Arduino. Then open Serial Monitor, set the speed to 9600 baud, No line ending. Type 1 in the text field and hit Enter. You will see number 1 is shown in the Serial Monitor and the Led on the Mega 2560 is on. If you type 2, 2 will appear in the Serial Monitor and the Led on the Mega 2560 is off. In this project, I am using Mega 2560, you can use any Arduino and it would still work the same.
That’s all for today’s post. We’ll be learning more about C++ in coming post. If you have any comments, leave it in the field below.