pycharm + PyQt5 读取串口并显示数据和图像

     万恶的项目上有一点需求,需要我们收集底层采集到的数据,本地存储,再发送到云端,被迫搬砖写了个小型的UI,记录下。

     首先是环境,开发的工具是Pycharm,python的解释器使用 anaconda3,辅助包主要是PyQt5,会稍微用到一点QTDesigner(不用也可以),数据库使用的是SQlite,数据库的查看工具是DB Browser。流程如下

      一、环境配置

      安装pycharm很简单,就不说了,但是这里一定要安装专业版的,因为社区版的pycharm再使用数据库时非常不方便。安装好之后我们按照下图配置环境 File - settings - project - Project interpreter 

      点击加号,输入pyqt,把圈中的两个包都安装上,后边需要用到的包也是同样的安装方法。注意解释器呀,要用anaconda3的,可以少安装很多东西。

      二、UI界面

      环境配好就可以动手写东西了,首先分析需求,我们要采集数据,然后再界面上显示数据,并做出图像,所以,首先要有数据和UI界面,这里先做界面。

      正常来讲,UI界面应该单独的放在一个模块里,然后在主模块中调用,这里我写的不好,就直接写在一起了,界面的主要部分如下所示:

	operatorLayout = QHBoxLayout()
	temperatureLayout = QHBoxLayout()
	pressureLayout = QHBoxLayout()
	flowLayout = QHBoxLayout()
	addressLayout = QHBoxLayout()
	# 传感器显示布局
	self.temperature = QLabel('0')
	self.temperature.setFixedWidth(200)
	self.temperature_status = QLineEdit('NO')
	self.temperature_status.setFixedWidth(200)
	self.pressure = QLabel('0')
	self.pressure.setFixedWidth(200)
	self.pressure_status = QLineEdit('NO')
	self.pressure_status.setFixedWidth(200)
	self.flow = QLabel('0')
	self.flow.setFixedWidth(200)
	self.flow_status = QLineEdit('NO')
	self.flow_status.setFixedWidth(200)
	self.address = QLabel('0')
	self.address.setFixedWidth(200)
	self.address_status = QLineEdit('NO')
	self.address_status.setFixedWidth(200)
	# 所有的状态标签
	temperature_show1 = QLabel("温度传感器:")
	temperature_show2 = QLabel("温度传感器工作状态:")
	pressure_show1 = QLabel("压力传感器:")
	pressure_show2 = QLabel("压力传感器工作状态:")
	flow_show1 = QLabel("流量传感器:")
	flow_show2 = QLabel("流量传感器工作状态:")
	address_show1 = QLabel("地址信息  :")
	address_show2 = QLabel("角度传感器工作状态:")
	# 添加布局,使用的是水平布局,然后垂直摆放
	temperatureLayout.addWidget(temperature_show1)
	temperatureLayout.addWidget(self.temperature)
	temperatureLayout.addWidget(temperature_show2)
	temperatureLayout.addWidget(self.temperature_status)
	pressureLayout.addWidget(pressure_show1)
	pressureLayout.addWidget(self.pressure)
	pressureLayout.addWidget(pressure_show2)
	pressureLayout.addWidget(self.pressure_status)
	flowLayout.addWidget(flow_show1)
	flowLayout.addWidget(self.flow)
	flowLayout.addWidget(flow_show2)
	flowLayout.addWidget(self.flow_status)
	addressLayout.addWidget(address_show1)
	addressLayout.addWidget(self.address)
	addressLayout.addWidget(address_show2)
	addressLayout.addWidget(self.address_status)
	
	self.prevButton = QPushButton("前一页")
	self.nextButton = QPushButton("后一页")
	self.switchPageButton = QPushButton("Go")
	self.switchPageLineEdit = QLineEdit('0')
	self.switchPageLineEdit.setFixedWidth(40)
	
	switchPage = QLabel("转到第")
	page = QLabel("页")
	operatorLayout.addWidget(self.prevButton)
	operatorLayout.addWidget(self.nextButton)
	operatorLayout.addWidget(switchPage)
	operatorLayout.addWidget(self.switchPageLineEdit)
	operatorLayout.addWidget(page)
	operatorLayout.addWidget(self.switchPageButton)
	operatorLayout.addWidget(QSplitter())
	
	# 状态布局
	statusLayout = QHBoxLayout()
	self.totalPageLabel = QLabel()
	self.totalPageLabel.setFixedWidth(70)
	self.currentPageLabel = QLabel()
	self.currentPageLabel.setFixedWidth(70)
	
	self.totalRecordLabel = QLabel()
	self.totalRecordLabel.setFixedWidth(70)
	
	statusLayout.addWidget(self.totalPageLabel)
	statusLayout.addWidget(self.currentPageLabel)
	statusLayout.addWidget(QSplitter())
	statusLayout.addWidget(self.totalRecordLabel)
	
	# 设置表格属性
	self.tableView = QTableView()
	# 表格宽度的自适应调整
	self.tableView.horizontalHeader().setStretchLastSection(True)
	self.tableView.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
	
	# 创建图形
	self.graphicsView = pg.GraphicsLayoutWidget()
	
	# 创建界面
	mainLayout = QVBoxLayout(self)
	mainLayout.addLayout(operatorLayout)
	mainLayout.addWidget(self.tableView)        #加入表格
	mainLayout.addLayout(temperatureLayout)
	mainLayout.addLayout(pressureLayout)
	mainLayout.addLayout(flowLayout)
	mainLayout.addLayout(addressLayout)
	mainLayout.addWidget(self.graphicsView)     #加入曲线
	mainLayout.addLayout(statusLayout)
	self.setLayout(mainLayout)

      这段代码看不懂关系也不大,完全可以用QTDesigner来画。

      三、数据采集

      使用python做数据采集需要使用 serial 这个包,然后只需要行代码就可以读取。

import serial
serialport = serial.Serial(GL.comport, int(GL.baudrate) ,timeout=0.5,parity=serial.PARITY_NONE, rtscts=1)
class WorkThread(QThread):
    receive = pyqtSignal()
    def run(self):
        while True:
            if (GL.bytes == 51):
                data = serialport.readline()
            if data != '':
                data1 = data.decode()
                data1 = data1.strip().split()
                data1 = [str(i) for i in data1[:6]]
                GL.data2 = data1
                self.receive.emit()   #发送消息

      首先载入serial,定义串口为 serialport ,然后写一个QThread的子类,使用另外一个线程做数据的读取(因为主线程是UI的显示,如果直接使用主线程读取,会造成阻塞)。这里使用了 pyqt 的消息和槽的机制,发送一个 receive 消息,然后再UI的初始化中绑定这个消息和处理方法(也就是槽),最后编写处理该消息的槽。

      四、存入数据库并画图

      有了UI界面、又完成了数据采集,我们就可以将数据存入数据库,并使用它们来画图了

 def update_data(self):
        time = QDateTime.currentDateTime()
        timeDisplay = time.toString("yyyyMMdd hh:mm:ss dddd")
        if GL.data2 != []:
            self.temperature.setText(GL.data2[0])
            self.pressure.setText(GL.data2[1])
            self.flow.setText(GL.data2[2])
            self.address.setText(GL.data2[5])
            # 获取采集数据
            GL.list[0] = int(GL.list[0] + 1)
            GL.list[1] = timeDisplay[9:17]
            GL.list[2] = int(GL.data2[1])
            GL.list[3] = int(GL.data2[0])
            GL.list[4] = int(GL.data2[2])
            GL.list[5] = GL.data2[5]
 
            GL.x_plot.append(GL.list[0])
            GL.y_plot.append(GL.list[2])
            GL.blue_plot.append(GL.list[3])
        if len(GL.x_plot) == 100:
            GL.x_plot = [0]
            GL.y_plot = [0]
            GL.blue_plot = [0]                        # 用刚刚采集到的100个点,画图
 
        self.plt.clear()
        self.plt.plot( GL.x_plot,GL.y_plot, pen= pg.mkPen(color='r', width=3),name="Red curve")
        self.plt.plot( GL.x_plot,GL.blue_plot, pen= pg.mkPen(color='b', width=3),name="Blue curve")
        self.db.open()
        query = QSqlQuery()
        # 存入数据库
        sql_1 = """insert into device(id,time,name,sex,age,deparment) values(%d,"%s",%d,%d,%d,"%s")""" % (GL.list[0], GL.list[1], GL.list[2], GL.list[3], GL.list[4], GL.list[5])
        query.exec(sql_1)
        self.db.close()

      上边这段代码就是刚才的 receive 消息对应的槽函数,当接收到receive消息时,我们将串口读到的数据存入全局变量,然后将全局变量按照顺序丢到数据库中。当然,要想使用数据库,肯定要在开头创建一个,如下:

def createTableAndInit(self):
    # 添加数据库
    self.db = QSqlDatabase.addDatabase('QSQLITE')
    # 设置数据库名称
    self.db.setDatabaseName('./db/database2.db')
    # 判断是否打开
    if not self.db.open():
        return False
    # 声明数据库查询对象
    query = QSqlQuery()
    # 创建表
    query.exec("create table device(id int , time int  , name vchar, sex vchar, age int, deparment int )")
    # 添加记录
    sql = "insert into device(id,time,name,sex,age,deparment) values(%d,%d,%d,%d,%d,%d)"%(GL.list[0],GL.list[1],GL.list[2],GL.list[3],GL.list[4],GL.list[5])
    query.exec(sql)
    return True

     如此,我们就完成了数据的采集、存储和显示。

     当然,这个代码可以优化的地方有很多,望能指正。

  • 10
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值