Low-Level RS232 Protocol
Asynchronous protocol
RX/TX signals
Default frame
Baudrate
Serial Terminal
First communication / Nucleo
Before venturing into the development of a complete graphical interface able to display data graphics and to send orders to the acquisition board, we will learn how to set up a serial link and transfer data in the two directions.
Setting up a Serial communication
To implement a Serial communication port on a Nucleo board, via MBED-OS, a BufferedSerial object is required, from the mbed.h library.
1#include "mbed.h"
2
3BufferedSerial usb_pc(USBTX, USBRX);
In this example, the serial link is named usb_pc and is based on a virtual RS232 link through the USB cable (the same as for downloading the binary file to the board).
To create a link with other devices (as BlueTooth HC05 module for example), you can use two others serial ports on the L476RG board : - Serial 1 : A4 (TX) / A5 (RX) - Serial 4 : A0 (TX) / A1 (RX)
Differents parameters can be updated on a Serial link. You can set a different data transfer rate, called baudrate, or modify the transmission low-level format of the data.
1usb_pc.set_baud(115200);
2
3usb_pc.format(8, SerialBase::None, 1);
The first function, set_baud, permits to change the data transfer rate in bauds.
The second function, set_format, permits to change the data format. The firts argument is the number of data bits (1 byte is 8 bits). The second argument is to set a parity value (default is None). The third argument is to set a stop bit (default value is 1).
Sendind data from external device to computer
To send data to the computer, write function from the BufferedSerial class can be used. Two arguments are required : a pointer to a memory space where data are stored as bytes and the amount of data (in bytes) to send.
1char data = 'a';
2usb_pc.write(&data, 1);
This first example permits to send one byte at a time (here is the ‘a’ character) through the RS232 serial port.
1char data[5] = {'a','0','b','5','!'};
2usb_pc.write(data, 5);
This second example permits to send 5 bytes at a time through the RS232 serial port.
Testing the transmission
To test the communication between the Nucleo board and the computer, a simple program that send periodically a character or a string of characters can be used.
1#include "mbed.h"
2BufferedSerial usb_pc(USBTX, USBRX);
3char data;
4char data2[5] = {'a','0','b','5','!'};
5
6/* MAIN PROGRAM */
7int main()
8{
9 // Initialization of Serial communication port
10 usb_pc.set_baud(115200);
11 usb_pc.set_format(8, SerialBase::None, 1);
12
13 while (true)
14 {
15 data = 'a';
16 usb_pc.write(&data, 1);
17 thread_sleep_for(1000);
18 usb_pc.write(data2, 5);
19 thread_sleep_for(1000);
20 }
21}
In this example, the ‘a’ character followed by the {a0b5!} string 1 second later are sent from the Nucleo board at a baudrate of 115200 bauds, in the default format (data are on 8 bits with no parity bit and 1 stop bit).
But computers are not natively able to read serial communication port. An application that read the hardware buffer of the communication port is required, as for example Tera Term
By setting up a serial terminal correctly (same baudrate…), the result is given in the next figure.
The computer receives each second, alternatively, ‘a’ character and {a0b5!} string.
Python and Serial communication
Serial terminals are not user-friendly for developing a complete system able to collect data and display them in a professionnal graphics.
Pyserial library
Listing communication ports
Accessing a specific port
First console application to collect data
1from serial import Serial
2import serial.tools.list_ports
3
4if __name__ == "__main__":
5 ports = serial.tools.list_ports.comports()
6 # To obtain the list of the communication ports
7 for port, desc, hwid in sorted(ports):
8 print("{}: {}".format(port, desc))
9 # To select the port to use
10 selectPort = input("Select a COM port : ")
11 print(f"Port Selected : COM{selectPort}")
12 # To open the serial communication at a specific baudrate
13 serNuc = Serial('COM'+str(selectPort), 115200) # Under Windows only
14
15 # number of bytes to collecting
16 nb_bytes = int(input("Enter the number of bytes to collect : "))
17
18 # collecting data byte after byte
19 nb_bytes_collected = 0
20 while(nb_bytes_collected < nb_bytes):
21 # Waiting new data
22 while serNuc.inWaiting() == 0:
23 pass
24 data_rec = serNuc.read(1) # bytes
25 print(f'D{nb_bytes_collected} = {data_rec}')
26 nb_bytes_collected += 1
27
28 # Close the serial port
29 serNuc.close()
Complete communication / Nucleo
In the previous part, communication was tested only in one direction : from the Nucleo board (or acquisition device) to the computer.
In a complete application it’s necessary to also send commands from the computer to the acquisition board.
Reading data / Polling method
The RS232 protocol is asynchronous, meaning that there is no clock transmitted between the two nodes of the network. But there is also no periodicity in the frame transmission.
When an RS232 signal is received by a node (detected by a start bit sequence on the communication RX port), the data is stored in an hardware buffer.
To know if a byte is received (i.e. stored in the hardware buffer), readable function from the BufferedSerial class can be used. This function returns true if a byte can be read, false otherwise.
1while(true){
2 if(usb_pc.readable()){
3 // almost one byte is readable
4 }
5}
In the previous example
To receive data from the computer, read function from the BufferedSerial class can be used. Two arguments are required : a pointer to a memory space where data will be stored as bytes and the amount of data (in bytes) to send.
Echo application
1while(true){
2 if(usb_pc.readable()){
3 usb_pc.read(&data, 1);
4 usb_pc.write(&data, 1);
5 }
6}
Read data / Interrupt method
Switch On/Off the acquisition device
Final program
1#include "mbed.h"
2
3BufferedSerial usb_pc(USBTX, USBRX);
4
5void usb_pc_ISR(void){
6 char rec_data_pc;
7 int rec_length = 0;
8 if(usb_pc.readable()){
9 rec_length = usb_pc.read(&rec_data_pc, 1);
10 usb_pc.write(&rec_data_pc, 1);
11 rec_data_pc = 'c';
12 usb_pc.write(&rec_data_pc, 1);
13 }
14}
15
16int main()
17{
18 usb_pc.set_baud(115200);
19 usb_pc.sigio(callback(usb_pc_ISR));
20 while (true){}
21}