做一个简单的小程序,发送报文并在屏幕上显示。目前遇到的问题就是发送的报文无法在屏幕上显示出来,代码如下:
from __future__ import print_function
import can
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import time
import sys
import random
class MainWidget(QWidget):
sinOut1=pyqtSignal(str) #信号之文件路径
def __init__(self,parent=None):
super(MainWidget,self).__init__(parent)
self.setWindowTitle("报文发送")
self.resize(1400,600) #调整窗口大小
self.thread_tx = WORKER_tx() #定义发送报文线程
self.mesbox=QTextEdit() #报文显示栏
self.textline=QLineEdit() #文件地址显示栏
self.btnOpen = QPushButton("打开文件")
self.btnflash = QPushButton("发送文件")
self.btnRecv = QPushButton("接收文件")
layout= QGridLayout(self)
layout.addWidget(self.mesbox,0,0,5,2)
layout.addWidget(self.textline,5,0)
layout.addWidget(self.btnOpen,5,1)
layout.addWidget(self.btnflash,6,0,1,2)
layout.addWidget(self.btnRecv, 7, 0, 1, 2)
self.btnOpen.clicked.connect(self.getfile)
self.sinOut1.connect(self.show_filename)
self.btnflash.clicked.connect(self.slot_start_tx)
self.thread_tx.sinOut2.connect(self.data_flash) #定义信号与槽连接
def getfile(self): #打开文件,获得文件路径
fname,_=QFileDialog.getOpenFileName(self,'Open File','.',"Hex File(*.hex *.Hex)")
self.sinOut1.emit(str(fname))
def show_filename(self,file_name): #显示文件路径
self.textline.setText(file_name)
def slot_start_tx(self): # 发送报文线程
self.btnflash.setEnabled(False)
self.thread_tx.start()
def data_flash(self,mes):
self.mesbox.append(mes)
class WORKER_tx(QThread): # 定义线程发送数据
sinOut2 = pyqtSignal(str)
def __init__(self, parent=None):
super(WORKER_tx, self).__init__(parent)
self.working = True
'''定义发送报文通道'''
self.bus_tx = can.interface.Bus(bustype='bmcan', channel=0, bitrate=500000, data_bitrate=2000000, tres=True)
'''定义接收报文通道'''
self.bus_rx = can.interface.Bus(bustype='bmcan', channel=1, bitrate=500000, data_bitrate=2000000, tres=True)
def run(self):
while self.working == True:
data = [random.randint(0, 15) for i in range(0, 8)]
msg = can.Message(arbitration_id=0xc0ffee,data=data,is_extended_id=True)
self.bus_tx.send(msg)
time.sleep(1)
self.sinOut2.emit(str(self.bus_rx.recv())) #发送报文信号
# self.sinOut2.emit(str(msg))
self.working = False
if __name__ == '__main__':
app = QApplication(sys.argv)
demo= MainWidget()
demo.show()
sys.exit(app.exec_())
用到了Python-can, can-tools, pyqt5等模块。
我这里有一个CAN卡,两通道一个用发送报文,另一个用来接收报文。之前想过再起一个线程,用来接收报文,并把报文发送到QTextEdit当中,这种方法也实现不了。想用异步发送,然后在总线中进行轮询,还没有实施,我感觉也够呛。
编译器用的Pycharm,CAN卡是busmaster,我试过简单的发送和接受报文,这个可以实现,利用can.listenner监听报文,也可以实现,但到了Pyqt5 里面用QThread实现起来有点困难,主线程定义了操作面板,子线程用来发送,总感觉还少了点什么,没办法,刚开始学!
我试了一下,报错如下:
我也查了一下bus.py源文档,没有subscribe函数,因此,如果要想启用监听listener,我尝试了can.Notifier,但还是监听不到报文:
首先,要确保CAN报文在Python-can中能够正常发送和接收。如果你能够成功地发送和接收报文,那么至少证明你的CAN卡与电脑连接正确。然后,我们需要将接收到的CAN报文显示在PyQt5的QTextEdit控件中。
我们可以通过继承QThread类来创建一个新线程,用于接收CAN报文。在新线程中,需要使用Python-can中的listener类来监听总线上的报文。一旦监听到报文,我们可以使用PyQt5的信号槽系统将报文发送回主线程,以便在QTextEdit中显示。
以下代码是一个简单的示例:
from PyQt5.QtCore import QThread, pyqtSignal
import can
class ReceiverThread(QThread):
message_received = pyqtSignal(str)
def __init__(self, bus):
super(ReceiverThread, self).__init__()
self.bus = bus
def run(self):
listener = can.BufferedReader()
self.bus.subscribe(listener)
while True:
msg = listener.get_message()
data = msg.data.hex()
self.message_received.emit(data)
在这个示例中,我们使用了BufferedReader类来监听CAN报文。在run方法中,我们使用了一个无限循环来不断监听来自总线的报文。当有报文时,我们将报文的十六进制数据转换为字符串,并使用message_received信号将报文发送回主线程。
接下来,我们需要在主线程中创建一个QTextEdit控件,并将message_received信号连接到一个槽函数,以便在QTextEdit中显示报文。以下是一个简单的代码片段:
from PyQt5.QtWidgets import QTextEdit, QApplication
from PyQt5.QtCore import pyqtSlot
class Window(QMainWindow):
def __init__(self, bus):
super(Window, self).__init__()
self.setWindowTitle("CAN Bus Monitor")
self.text_edit = QTextEdit()
self.setCentralWidget(self.text_edit)
self.receiver_thread = ReceiverThread(bus)
self.receiver_thread.message_received.connect(self.update_text_edit)
self.receiver_thread.start()
@pyqtSlot(str)
def update_text_edit(self, message):
self.text_edit.append(message)
在这个示例中,我们在主线程中创建了一个QTextEdit控件,并将其设置为MainWindow的中央小部件。我们还创建了一个ReceiverThread对象,并将message_received信号连接到一个名为update_text_edit的槽函数。当收到新报文时,槽函数会将报文附加到QTextEdit中。
最后,我们需要使用Python-can模块中的can.Message类来发送CAN报文。以下是一个简短的示例代码:
bus = can.interface.Bus(bustype='pcan', channel='PCAN_USBBUS1', bitrate=250000)
msg = can.Message(arbitration_id=0x123, data=[0x01, 0x02, 0x03])
bus.send(msg)
在这个示例中,我们首先创建了一个CAN总线对象,指定了总线类型和通道。然后,我们使用can.Message类创建了一个带有特定ID和数据的CAN报文。最后,我们使用总线对象的send方法发送报文。
综上所述,针对该问题,我们需要解决以下几个方面:
如果以上步骤都正确地完成了,那么你的小程序应该可以正常地发送和接收CAN报文,并在QTextEdit控件中显示报文。