鱼C论坛

 找回密码
 立即注册
查看: 5023|回复: 6

[已解决]用Python写了个串口工具,但是程序老是容易崩溃,求帮忙找下原因

[复制链接]
发表于 2018-3-14 23:08:59 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
自学python,写了个串口工具,但是一旦连续接收数据多了之后,程序就会崩溃。
不知道是何原因,请小伙伴们帮忙找下原因。

另外代码写的不合理的地方,也希望帮忙指出,谢谢。

出错截图如下图。右边是网上找的串口工具,连续不断的给右边(自己写的)程序发数据,两条消息间隔30ms。
没传多久就会出现如图的停止工作的情况。

出错截图

出错截图


Pthon3 + PyQT

helloU.py
# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'helloU.ui'
#
# Created by: PyQt5 UI code generator 5.9.2
#
# WARNING! All changes made in this file will be lost!

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(562, 437)
        MainWindow.setMinimumSize(QtCore.QSize(562, 437))
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setEnabled(True)
        self.centralwidget.setObjectName("centralwidget")
        self.gridLayout_2 = QtWidgets.QGridLayout(self.centralwidget)
        self.gridLayout_2.setObjectName("gridLayout_2")
        self.gridLayout = QtWidgets.QGridLayout()
        self.gridLayout.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint)
        self.gridLayout.setObjectName("gridLayout")
        self.sendLineEdit = QtWidgets.QLineEdit(self.centralwidget)
        self.sendLineEdit.setObjectName("sendLineEdit")
        self.gridLayout.addWidget(self.sendLineEdit, 2, 0, 1, 7)
        self.dataBits = QtWidgets.QComboBox(self.centralwidget)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.dataBits.sizePolicy().hasHeightForWidth())
        self.dataBits.setSizePolicy(sizePolicy)
        self.dataBits.setMinimumSize(QtCore.QSize(50, 20))
        self.dataBits.setMaximumSize(QtCore.QSize(50, 20))
        self.dataBits.setObjectName("dataBits")
        self.gridLayout.addWidget(self.dataBits, 0, 4, 1, 1)
        self.sendBtn = QtWidgets.QPushButton(self.centralwidget)
        self.sendBtn.setObjectName("sendBtn")
        self.gridLayout.addWidget(self.sendBtn, 3, 0, 1, 1)
        self.rcvBrowser = QtWidgets.QTextBrowser(self.centralwidget)
        self.rcvBrowser.setObjectName("rcvBrowser")
        self.gridLayout.addWidget(self.rcvBrowser, 1, 0, 1, 7)
        self.parityMode = QtWidgets.QComboBox(self.centralwidget)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.parityMode.sizePolicy().hasHeightForWidth())
        self.parityMode.setSizePolicy(sizePolicy)
        self.parityMode.setMinimumSize(QtCore.QSize(60, 20))
        self.parityMode.setMaximumSize(QtCore.QSize(60, 20))
        self.parityMode.setObjectName("parityMode")
        self.gridLayout.addWidget(self.parityMode, 0, 3, 1, 1)
        self.stopBits = QtWidgets.QComboBox(self.centralwidget)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.stopBits.sizePolicy().hasHeightForWidth())
        self.stopBits.setSizePolicy(sizePolicy)
        self.stopBits.setMinimumSize(QtCore.QSize(50, 20))
        self.stopBits.setMaximumSize(QtCore.QSize(50, 20))
        self.stopBits.setObjectName("stopBits")
        self.gridLayout.addWidget(self.stopBits, 0, 5, 1, 1)
        self.baudLineEdit = QtWidgets.QLineEdit(self.centralwidget)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.baudLineEdit.sizePolicy().hasHeightForWidth())
        self.baudLineEdit.setSizePolicy(sizePolicy)
        self.baudLineEdit.setMinimumSize(QtCore.QSize(80, 20))
        self.baudLineEdit.setMaximumSize(QtCore.QSize(80, 20))
        self.baudLineEdit.setText("")
        self.baudLineEdit.setObjectName("baudLineEdit")
        self.gridLayout.addWidget(self.baudLineEdit, 0, 2, 1, 1)
        spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.gridLayout.addItem(spacerItem, 0, 6, 1, 1)
        self.openButton = QtWidgets.QPushButton(self.centralwidget)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.openButton.sizePolicy().hasHeightForWidth())
        self.openButton.setSizePolicy(sizePolicy)
        self.openButton.setMinimumSize(QtCore.QSize(80, 20))
        self.openButton.setMaximumSize(QtCore.QSize(80, 20))
        self.openButton.setObjectName("openButton")
        self.gridLayout.addWidget(self.openButton, 0, 0, 1, 1)
        self.portNum = QtWidgets.QComboBox(self.centralwidget)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.portNum.sizePolicy().hasHeightForWidth())
        self.portNum.setSizePolicy(sizePolicy)
        self.portNum.setMinimumSize(QtCore.QSize(80, 20))
        self.portNum.setMaximumSize(QtCore.QSize(80, 20))
        self.portNum.setObjectName("portNum")
        self.gridLayout.addWidget(self.portNum, 0, 1, 1, 1)
        spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.gridLayout.addItem(spacerItem1, 3, 3, 1, 4)
        self.HexCheckBox = QtWidgets.QCheckBox(self.centralwidget)
        self.HexCheckBox.setObjectName("HexCheckBox")
        self.gridLayout.addWidget(self.HexCheckBox, 3, 1, 1, 1)
        self.NewLineCheckBox = QtWidgets.QCheckBox(self.centralwidget)
        self.NewLineCheckBox.setObjectName("NewLineCheckBox")
        self.gridLayout.addWidget(self.NewLineCheckBox, 3, 2, 1, 1)
        self.gridLayout_2.addLayout(self.gridLayout, 0, 0, 1, 1)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 562, 23))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.sendBtn.setText(_translate("MainWindow", "Send"))
        self.openButton.setText(_translate("MainWindow", "OPEN"))
        self.HexCheckBox.setText(_translate("MainWindow", "HEX"))
        self.NewLineCheckBox.setText(_translate("MainWindow", "NewLine"))


SerialHandle.py
#!/usr/bin/env python
# _*_ coding:utf-8 _*_

import sys
import threading
import time
import serial
import binascii
import logging

logging.basicConfig(level=logging.INFO)

class SerialHandle(object):
    def __init__(self, Port="COM3", BaudRate="9600", ByteSize="8", Parity="N", Stopbits="1"):
        '''
        初始化一些参数
        :param Port:
        :param BaudRate:
        :param ByteSize:
        :param Parity:
        :param Stopbits:
        :return:
        '''
        self.l_serial = None
        self.alive = False
        self.portNum = Port
        self.baudrate = BaudRate
        self.bytesize = ByteSize
        self.parity = Parity
        self.stopbits = Stopbits
        self.receiveData = ""


    def start(self):
        '''
        打开串口
        :return:
        '''
        self.l_serial = serial.Serial()
        self.l_serial.port = self.portNum
        self.l_serial.baudrate = self.baudrate
        self.l_serial.bytesize = int(self.bytesize)
        self.l_serial.parity = self.parity
        self.l_serial.stopbits = int(self.stopbits)
        self.l_serial.timeout = 2

        try:
            self.l_serial.open()
            if self.l_serial.isOpen():
                self.alive = True
        except Exception as e:
            self.alive = False
            logging.error(e)

    def stop(self):
        '''
        关闭串口
        :return:
        '''
        self.alive = False
        if self.l_serial.isOpen():
            self.l_serial.close()

        # 获取COM号列表

    def port_list(self):
        comlist = []
        port_list = list(serial.tools.list_ports.comports())
        for port in port_list:
            comlist.append(port[0])
        return comlist

    def read(self):
        '''
        循环读取串口的数据
        :return:
        '''
        isRcved = False
        timeRcved = 0
        while self.alive:
            try:
                number = self.l_serial.inWaiting()
                if number:
                    isRcved = True
                    timeRcved = int(round(time.time() * 1000))
                    self.receiveData += self.l_serial.read(number).decode()#.replace(binascii.unhexlify("00"), "")
                    #print(self.receiveData)
                    #print("rcv data: %s" % self.l_serial.read(number).decode())
            except Exception as e:
                logging.error(e)

            if isRcved == True :
                if (int(round(time.time() * 1000)) - timeRcved)>10:
                    print(self.receiveData)
                    isRcved = False
                    self.receiveData = ""


    def dataReceiveAndProcess(self, func):
        try:
            thread_read = threading.Thread(target=self._dataRecevie, args=(func, ))
            thread_read.setDaemon(True)
            thread_read.start()
        except BaseException as e:
            print("error:",e)


    def _dataRecevie(self, func):
        '''
        循环读取串口的数据
        :return:
        '''
        isRcved = False
        timeRcved = 0
        while self.alive:
            number = self.l_serial.inWaiting()
            if number:
                logging.info('receive data\n')
                isRcved = True
                timeRcved = int(round(time.time() * 1000))
                self.receiveData += self.l_serial.read(number).decode()#.replace(binascii.unhexlify("00"), "")
                #print(self.receiveData)
                #print("rcv data: %s" % self.l_serial.read(number).decode())

            if isRcved == True :
                if (int(round(time.time() * 1000)) - timeRcved)>10:
                    logging.info('process data\n')
                    #print(self.receiveData)
                    func(self.receiveData)
                    isRcved = False
                    self.receiveData = ""



    def sendData(self, data, isHex=False, isNewLine=False):
        '''
        发送数据
        :param data: self.sendLineEdit.text()
        :param isHex: self.HexCheckBox.checkState()
        :param isNewLine: self.NewLineCheckBox.checkState()
        :return:
        '''
        if data != "":
            if (isHex == False):
                # 字符串发送
                if isNewLine:
                    data = data + "\r\n"
                inputData = data.encode('utf-8')
            else:
                # 十六进制发送
                data = data.strip()  # 删除前后的空格
                sendList = []
                while data != "":
                    try:
                        # int() 函数用于将一个字符串或数字转换为整型。
                        num = int(data[0:2], 16)
                    except ValueError:
                        print("input hex data!")
                        #QMessageBox.critical(self, 'pycom', '请输入十六进制数据,以空格分开!')
                        return None
                    data = data[2:]
                    data = data.strip()

                    # 添加到发送列表中
                    sendList.append(num)

                if isNewLine:
                    sendList.append(0x0d)
                    sendList.append(0x0a)

                inputData = bytes(sendList)

        # d = "12abc"
        # d = d.encode("ascii")
        self.l_serial.write(inputData)

if __name__ == '__main__':
    import threading
    ser = SerialHandle()
    ser.start()

    ser.sendData("12 23 34", True)
    thread_read = threading.Thread(target=ser.read)
    thread_read.setDaemon(True)
    thread_read.start()
    import time
    time.sleep(25)
    ser.stop()

main.py
#!/usr/bin/env python
# _*_ coding:utf-8 _*_

import sys
import threading
import time
import datetime
import helloU
import SerialHandle
import serial
import serial.tools.list_ports
from PyQt5.QtGui import *
from PyQt5.QtWidgets import QApplication, QMainWindow, QMessageBox




class SerialDlg(helloU.Ui_MainWindow):
    def defaultInit(self):
        self.ser = SerialHandle.SerialHandle()
        self.serial_receive_count = 0

        self.portNum.addItems(self.ser.port_list())
        self.baudLineEdit.setText("9600")
        self.parityMode.addItems(['None', 'Even', 'Odd', 'Mark', 'Space'])
        self.dataBits.addItems(['5', '6', '7', '8'])
        self.stopBits.addItems(['1', '1.5', '2'])

        self.dataBits.setCurrentText("8")

        self.openButton.setText("OPEN")
        self.openButton.setStyleSheet("background-color:#4abdac")
        self.openButton.setFont(QFont('SansSerif', 15, QFont.Bold))
        self.openButton.setAutoFillBackground(True)
        self.openButton.clicked.connect(self.OpenSerial)
        self.sendBtn.clicked.connect(self.SendData)

        self.sendBtn.setDisabled(True)


    # 打开串口
    def OpenSerial(self):

        if self.openButton.text() == "OPEN":
            self.portNum.setDisabled(True)
            self.baudLineEdit.setDisabled(True)
            self.parityMode.setDisabled(True)
            self.dataBits.setDisabled(True)
            self.stopBits.setDisabled(True)
            self.sendBtn.setDisabled(False)

            self.port = self.portNum.currentText()
            self.baudrate = self.baudLineEdit.text()

            ParityValue = self.parityMode.currentText()
            self.parity = ParityValue[0]

            self.bytesize = int(self.dataBits.currentText())
            self.stopbits = int(self.stopBits.currentText())

            self.openButton.setText("CLOSE")
            self.openButton.setStyleSheet("background-color:#fc4a1a")
            # self.openButton.setAutoFillBackground(True)

            self.ser.portNum = self.port
            self.ser.baudrate = self.baudrate
            self.ser.bytesize = self.bytesize
            self.ser.parity = self.parity
            self.ser.stopbits = self.stopbits

            self.ser.start()

            self.ser.dataReceiveAndProcess(self.showDataOnQTextBrowser)
            #thread_read = threading.Thread(target=self.ser.read)
            #thread_read.setDaemon(True)
            #thread_read.start()

        elif self.openButton.text() == "CLOSE":
            self.ser.stop()
            self.openButton.setText("OPEN")
            self.openButton.setStyleSheet("background-color:#4abdac")
            # self.openButton.setAutoFillBackground(True)

            self.portNum.setDisabled(False)
            self.baudLineEdit.setDisabled(False)
            self.parityMode.setDisabled(False)
            self.dataBits.setDisabled(False)
            self.stopBits.setDisabled(False)
            self.sendBtn.setDisabled(True)

    # 发送数据
    def SendData(self):
        self.ser.sendData(self.sendLineEdit.text(), self.HexCheckBox.checkState(), self.NewLineCheckBox.checkState())

    # 数据显示
    def showDataOnQTextBrowser(self, data):
        self.serial_receive_count += 1
        self.rcvBrowser.append("[" + str(datetime.datetime.now()) + " - "+ str(self.serial_receive_count) + "]:\n")
        self.rcvBrowser.append(data)
        #QTextCursor cursor = self.rcvBrowser.textCursor()
        self.rcvBrowser.setTextCursor(self.rcvBrowser.textCursor())



if __name__ == '__main__':
    app = QApplication(sys.argv)
    MainWindow = QMainWindow()
    ui = SerialDlg() #helloU.Ui_MainWindow()
    ui.setupUi(MainWindow)
    ui.defaultInit()
    MainWindow.show()
    sys.exit(app.exec_())
最佳答案
2018-3-15 17:32:10
justloong 发表于 2018-3-15 09:58
系统问题?你指我PC的操作系统的问题吗?
WIN10系统

,我的archlinux+gnome就没有事,你再等等吧,python更新后应该会好,还有,别装测试版,bug多
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-3-15 07:34:30 | 显示全部楼层
这闪退有很多种可能,我估计是系统的问题
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-3-15 09:58:41 | 显示全部楼层
AndyZhou 发表于 2018-3-15 07:34
这闪退有很多种可能,我估计是系统的问题

系统问题?你指我PC的操作系统的问题吗?
WIN10系统
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-3-15 17:32:10 | 显示全部楼层    本楼为最佳答案   
justloong 发表于 2018-3-15 09:58
系统问题?你指我PC的操作系统的问题吗?
WIN10系统

,我的archlinux+gnome就没有事,你再等等吧,python更新后应该会好,还有,别装测试版,bug多
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-3-15 18:31:33 | 显示全部楼层
AndyZhou 发表于 2018-3-15 17:32
对,我的archlinux+gnome就没有事,你再等等吧,python更新后应该会好,还有,别装测试版 ...

多谢。这种问题对于我这种新手来讲,要不是别人指点,简直就是无解啊
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-3-15 18:45:37 | 显示全部楼层
justloong 发表于 2018-3-15 18:31
多谢。这种问题对于我这种新手来讲,要不是别人指点,简直就是无解啊

哦对了,你试试先更新python,再pip install pip-review ,然后 pip-review --auto,这样可以更新pip包
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-6-28 17:08:34 | 显示全部楼层
请问你实现了没有,我遇到跟你一样的问题,我的QQ号171365505希望跟我联系
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-4-4 03:11

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表