美文网首页物联网驿站
PyQt5快速上手应用篇2-打通串口工具数据交互

PyQt5快速上手应用篇2-打通串口工具数据交互

作者: 一叶孤沙 | 来源:发表于2020-04-03 19:14 被阅读0次

    前言

    本节我们继续使用Pyqt5开发串口工具,目标是打通串口工具数据交互功能,实现串口工具核心功能,细节部分将在之后章节会继续优化。

    一、实例

    1. QT Designer修改UI

    打开应用篇1中uart_tool.ui,首先修改串口QCombox配置信息,然后修改textBrowser为Text Edit,这是由于textBrowser只能显示数据,不能获取输入,所以本节修改为Text Edit,以便获取输入信息,并发送给串口设备。

    image

    UI界面修改完成后,接下里需要搞清楚界面中各个组件的名字和代码如何对应,我们以串口为例。

    image

    同理,工具栏中对应关系如下:

    image

    2 将*.ui转换为ui_uart_tool.py

    进入run.py目录,输入如下命令:

    pyuic5-oui_uart_tool.pyuart_tool.ui
    

    3 编写python程序

    正式编写程序之前,我们需要明确下本节具体需求,打开软件时候,首先从配置文件config.ini中获取串口配置信息,然后渲染到软件显示;接着点击工具栏中开始图标,调用pyserial包连接串口设备,然后再输入text Edit中输入信息,点击发送按钮,textBrowser中显示收到的串口信息。

    3.1 配置信息处理

    配置信息处理需要参考”Pyqt5快速上手基础篇10-QSettings用法“,config.ini文件中设置了默认的串口信息(波特率9600,数据位8位,停止位一位,无奇偶校验,无流控),内容如下所示:

    [SETUP]
    BAUD_VALUE=9600
    DATABIT_VALUE=8
    POLARITY_VALUE=none
    STOPBIT_VALUE=1
    FLOW_VALUE=none
    

    核心代码如下:

            self.settings = qc.QSettings("config.ini", qc.QSettings.IniFormat)
            # self.com = self.settings.value("SETUP/COM_VALUE")
            self.baud = self.settings.value("SETUP/BAUD_VALUE", 0, type=int)
            self.databit = self.settings.value("SETUP/DATABIT_VALUE")
            self.polarity = self.settings.value("SETUP/POLARITY_VALUE")
            # odd even  none
            if (self.polarity == "odd"):
                self.polarity = "奇校验"
            elif(self.polarity == "even"):
                self.polarity = "偶校验"
            elif(self.polarity == "none"):
                self.polarity = "无"
            self.stopbit = self.settings.value("SETUP/STOPBIT_VALUE")
            self.flow =  self.settings.value("SETUP/FLOW_VALUE")
            if (self.flow == "cts"):
                self.flow =  "RTS/CTS"
                print("odd check taest")
            elif(self.flow == "xon"):
                self.flow =  "XON/XOFF"
            elif(self.flow == "none"):
                self.flow =  "无"      
    

    3.2 串口工具通信架构

    本工具逻辑上分为三层,分别是最上层的UI层、最底层串口通信层、中间层的逻辑处理层,其中UI层负责获取用户输入,同时更新UI信息;串口通信层负责和串口设备通信,包括建立连接、收发数据、关闭连接等;逻辑处理层起到承上启下的作用,负责连接UI层和串口通信层,同时该层完成业务核心逻辑的处理。

    (1)下行数据处理

    下行数据是指串口工具发送数据给串口设备的过程,逻辑比较简单,最上层class myForm对象实例化的时候,会同时实例化中间层Tool对象,

    self.tool = tool.Tool(self, logger.info)#串口工具逻辑处理对象
    

    中间层Tool实例化后,上层打开串口时候,也会实例化底层Uart对象,

    self.uart = uart.Uart(port,self.parent.baud,self.log)
    

    因此最上层需要发送数据时候,直接调用如下函数即可:

    self.tool.send_data_fun(send_text.encode())
    

    (2) 上行数据处理

    上行数据是指串口设备发送数据给串口工具并显示在textBrowser的过程,class Uart(object)类定义了最底层串口通信层的方法,实例化时候,其构造函数会同时创建recv_data_thread()和send_data_thread()两个线程,其中recv_data_thread()线程负责接收串口设备发来的数据,核心处理代码如下:

      def recv_data_thread():
                while True:
                    try:
                        if (1 == self.run_status):
                            nums = self.uart.inWaiting()
                            if (nums > 0):
                                recv_msg = self.uart.read(nums)
                            else:
                                continue
                            if self.recv_queue.full():
                                self.recv_queue.get()
                            self.recv_queue.put(recv_msg.decode())
                            data = "[module->pc] " +str(recv_msg)
                            print(data)
                            # self.log(data)
                        sleep(0.05)
                    except Exception as e:
                        self.log("Error")
                        self.log(e)
    

    从上述代码中,可以看到,串口通信层收到数据后会放入recv_queue队列中,现在有个问题是如何将队列中的数据实时的发给UI界面显示呢?

    本文处理方法是利用中间层class Tool(object)对象来传递消息,Tool对象初始化时候,其构造函数中会自动开启一个tool_logic_thread线程,当线程检测到UI层工具栏开启图标被点击后,会实例化Uart对象,同时开启一个数据接收线程recv_data_thread(),该线程负责将收到的队列中的数据读取出来,同时发送给UI的TextBrowser显示。

        def tool_logic_thread(self):
            self.log("start tool logic thread")
            while (True):
                if (1 == self.parent.uart_start_status and 0 == self.run_status):
                    port = self.parent.comboBox_uart.currentText()
                    self.uart = uart.Uart(port, self.parent.baud, self.log)
                    self.run_status = 1
                    # start recv data thread
                    threading.Thread(target=self.recv_data_thread, daemon=True).start()
                elif(2 == self.parent.uart_start_status):
                    pass
                elif(0 == self.parent.uart_start_status):
                    self.close_uart()
                sleep(0.1)
    
        def recv_data_thread(self):
            self.log("start recv_data_thread")
            while (True):
                if (False == self.uart.recv_queue.empty()):
                    data = self.uart.recv_queue.get()
                    self.parent.signal_recv_data.emit(data)
                sleep(0.1)
    

    注意收到的数据发送给UI的textBrowser用到了自定义信号量signal_recv_data,当中间层Tool触发信号后,UI层对应槽函数会响应。

         self.signal_recv_data.connect(self.update_textbrowser_recv_cb)#连接信号和槽函数
        #槽函数
        def update_textbrowser_recv_cb(self, data):
            self.textBrowser_recv.insertPlainText(data)
            cursor = self.textBrowser_recv.textCursor()
            self.textBrowser_recv.moveCursor(cursor.End)
    

    二、运行

    1.硬件连接:

    image

    2.运行:

    进入文件目录,输入python3 run.py,即可弹出上述用QT Designer设计出来的MainWindow页面。

    image

    然后选择端口,点击工具栏中开始按钮:

    image

    接着在Text Edit框中输入hello world并点击发送按钮。


    image

    可以看到textBrowser显示了从串口设备接收的数据,至此我们打通了数据通信的道路。

    三、结语

    (1)自定义信号

    本节用到了自定义信号,之后再基础篇会更新。

    一叶孤沙出品:一沙一世界,一叶一菩提

    相关文章

      网友评论

        本文标题:PyQt5快速上手应用篇2-打通串口工具数据交互

        本文链接:https://www.haomeiwen.com/subject/lvbkphtx.html