This section describes how to send and receive data over a serial port on a raspberry PI. The development environment still uses PyCharm to write Python code and develop remotely, and then QtCreator to write QML’s GUI interface.

1. New projects

1.1. New construction project

Open PyCharm and create a new project serialTesting as follows:

1.2. Add the Python main program

The serialtesting.py main program is as follows:

import os
import sys
from pathlib import Path

import serial
import threading
from PySide2 import QtCore
from PySide2.QtCore import Qt, QObject, Slot
from PySide2.QtQml import QQmlApplicationEngine
from PySide2.QtWidgets import QApplication

mserial1 = serial.Serial('/dev/ttyAMA1'.115200)
mserial2 = serial.Serial('/dev/ttyAMA2'.115200)

def Serial1Reading() :
    while True:
        while mserial1.inWaiting() > 0:
            s = mserial1.read(mserial1.inWaiting())
            s = s.decode()

            ifs ! ="":
                print("serial1 recv:", s)
                controler.uart1sig.emit(s)

def Serial2Reading() :
    while True:
        while mserial2.inWaiting()>0:
            s = mserial2.read(mserial2.inWaiting())
            s = s.decode()

            ifs ! ="":
                print("serail2 recv:",s)
                controler.uart2sig.emit(s)


thread1 = threading.Thread(target=Serial1Reading)
thread2 = threading.Thread(target=Serial2Reading)

class Controler(QObject) :

    uart1sig = QtCore.Signal(str)
    uart2sig = QtCore.Signal(str)

    def __init__(self) :
        super().__init__()

    @Slot()
    def exit(self) :

        sys.exit()

    @Slot(str)
    def uart1send(self,s) :
        print("uart1 send:",s)
        if mserial1.isOpen():
            mserial1.write(str(s).encode())

    @Slot(str)
    def uart2send(self,s) :
        print("uart2 send:",s)
        if mserial2.isOpen():
            mserial2.write(str(s).encode())

if __name__=='__main__':

    os.environ["QT_IM_MODULE"] = "qtvirtualkeyboard"

    a = QApplication(sys.argv)

    a.setOverrideCursor(Qt.BlankCursor)

    engine = QQmlApplicationEngine()

    controler = Controler()
    context = engine.rootContext()
    context.setContextProperty("_Controler", controler)

    engine.load(os.fspath(Path(__file__).resolve().parent / "ui/main.qml"))
    if not engine.rootObjects():
        sys.exit(-1)

    root = engine.rootObjects()[0]
    controler.uart1sig.connect(root.uart1ReadyRead)
    controler.uart2sig.connect(root.uart2ReadyRead)

    thread1.daemon=True
    thread2.daemon=True
    thread1.start()
    thread2.start()

    sys.exit(a.exec_())

Copy the code
  • A Controler class is established to interact with the QML interface, so that the interface can send serial data and display the received data.
  • The Controler class has two signal and two slot functions for receiving and sending serial data.
  • Two threads are set up to read serial port data. When serial port data arrives, the data will be displayed to the interface through the signal slot.
1.3. Add interface files
  • Add the UI folder to your project and create a new main.qml file, then use QtCreator to write the interface:
import QtQuick 2.11
import QtQuick.Window 2.4
import QtQuick.Controls 2.4
import QtQuick.Controls.Styles 1.4
import QtQuick.Extras 1.4
import QtGraphicalEffects 1.0
import QtQuick.VirtualKeyboard 2.1
import QtQuick.VirtualKeyboard.Settings 2.1


ApplicationWindow{
    id:root
    width: 800
    height: 480
    visible: true
    visibility: Window.FullScreen

    function uart1ReadyRead(string){
//        console.log("uart1 recv:",string)
        uart1recv.append(string)
    }

    function uart2ReadyRead(string){
//        console.log("uart2 recv:",string) uart2recv.append(string) } background: Rectangle{ color: "black" anchors.fill: parent } Button{ id:btnexit background: Rectangle{ color: "#a01010" anchors.fill: parent radius:12 } width: 48 height: 48 anchors{ top: parent.top right: parent.right topMargin: 8 rightMargin: 8 } Text { text: qsTr("X") anchors.centerIn: parent font{ pointSize: 32 } color: "white" } onClicked: { _Controler.exit(); } } Text { id: title text: qsTr("Serial Testing") anchors{ top: parent.top horizontalCenter: parent.horizontalCenter topMargin: 20 } font{ pointSize: 24 } color: "#a0a0a0" } TextField { id: uart1send width: 200 font.pointSize: 12 placeholderText: qsTr("uart1 send text") anchors{ top: title.bottom left: parent.left topMargin: 20 leftMargin: 30 } color: "#DBD6D6" background: Rectangle{ anchors.fill: parent color: "# 303030" } } Button{ id:btnsend text: "Send" width: 100 height: uart1send.height anchors{ left: uart1send.right leftMargin: 40 top: uart1send.top } background: Rectangle{ anchors.fill: parent color: btnsend.pressed ? "#216CB8":"#a0a0a0" radius: 10 } font.pixelSize: 20 font.bold: true onClicked: { _Controler.uart1send(uart1send.text) } } TextArea{ id:uart1recv width: 360 height: 320 anchors{ top: uart1send.bottom topMargin: 10 left: parent.left leftMargin: 20 } font.pointSize: 12 color: "#20a0a0" background: Rectangle{ anchors.fill: parent color: "# 202020" } } TextField { id: uart2send width: 200 font.pointSize: 12 placeholderText: qsTr("uart2 send text") anchors{ top: title.bottom right: btn2send.left topMargin: 20 rightMargin: 20 } color: "#DBD6D6" background: Rectangle{ anchors.fill: parent color: "# 303030" } } Button{ id:btn2send text: "Send" width: 100 height: uart2send.height anchors{ right: parent.right rightMargin: 30 leftMargin: 40 top: uart1send.top } background: Rectangle{ anchors.fill: parent color: btn2send.pressed ? "#216CB8":"#a0a0a0" radius: 10 } font.pixelSize: 20 font.bold: true onClicked: { _Controler.uart2send(uart2send.text) } } TextArea{ id:uart2recv width: 360 height: 320 anchors{ top: btn2send.bottom topMargin: 10 right: parent.right rightMargin: 20 } font.pointSize: 12 color: "#a020b0" background: Rectangle{ anchors.fill: parent color: "# 202020" } } InputPanel { id: inputPanel z: 99 x: 50 y: parent.height width: parent.width-100 states: State { name: "visible" when: inputPanel.active PropertyChanges { target: inputPanel y: parent.height - inputPanel.height } } transitions: Transition { from: "" to: "visible" reversible: true ParallelAnimation { NumberAnimation { properties: "y" duration: 250 easing.type: Easing.InQuart } } } } } /*##^## Designer { D{i:0; FormeditorZoom: 0.75; height:480; width:800} } ##^##*/Copy the code

The interface is completed as follows:

  • The interface mainly established two sending and receiving Windows, and then you can test to send data to each other and data receiving display.

2. Execute the program

2.1. Upload the program to Raspberry PI

Right-click on the project and upload the project file to raspberry PI.

2.2. Execute the program

After uploading, run the following command in the raspberry PI folder to execute the program:

python3 serialTesting.py
Copy the code

The following output is displayed:

Then you can enter the data in the input box and click “Send” to test the data sending and receiving between serial ports 1 and 2:

  • Full code: GitHub
  • Video effect: