catalogue
3.2 serial port detection procedure
3.3. Set and open serial port program
3.4 program for sending data regularly
3.9, open blog, official account program
3.10 clear the sending and receiving data display program
3.11. Close the serial port program
The Python Qt GUI design series blog has finally reached the practical chapter. This blog will run through the previous basic knowledge points to realize a serial port debugging assistant.
Attention to the official account: the man plays programming, replies the key word: serial debugging assistant, gets the source code of the project.
1. UI design
The UI design is implemented by Qt Creator, and the component layout is as follows:
2. Convert UI file to Py file
Here, a Python script is used to convert the UI file into a Python file. The code is as follows:
import os import os.path dir ='./' #The path where the file is located #Find all under the path ui file def listUiFile(): list = [] files = os.listdir(dir) for filename in files: #print(filename) if os.path.splitext(filename)[1] == '.ui': list.append(filename) return list #The extension is not ui conversion to py file def transPyFile(filename): return os.path.splitext(filename)[0] + '.py' #By order Convert ui files to py file def runMain(): list = listUiFile() for uifile in list: pyfile = transPyFile(uifile) cmd = 'pyuic5 -o {pyfile} {uifile}'.format(pyfile=pyfile, uifile=uifile) os.system(cmd) if __name__ =="__main__": runMain()
3. Logic function realization
3.1 initialization procedure
Firstly, initialize the status of some components and flag bits, and set the relationship between signal and slot. The implementation code is as follows:
# Initialization program def __init__(self): super(Pyqt5_Serial, self).__init__() self.setupUi(self) self.init() self.ser = serial.Serial() self.port_check() # Set Logo and title self.setWindowIcon(QIcon('Com.png')) self.setWindowTitle("Serial debugging assistant [official account] beauty playing programming") # Sets the window size to prevent stretching self.setFixedSize(self.width(), self.height()) # Set the number of transmitted data and received data to zero self.data_num_sended = 0 self.Lineedit2.setText(str(self.data_num_sended)) self.data_num_received = 0 self.Lineedit3.setText(str(self.data_num_received)) # Serial port close button enable self.Pushbuttom3.setEnabled(False) # Clear sending box and text box self.Text1.setText("") self.Text2.setText("") # Establish the relationship between control signal and slot def init(self): # Serial port detection button self.Pushbuttom2.clicked.connect(self.port_check) # Serial port open button self.Pushbuttom1.clicked.connect(self.port_open) # Serial port close button self.Pushbuttom3.clicked.connect(self.port_close) # Send data regularly self.timer_send = QTimer() self.timer_send.timeout.connect(self.data_send) self.Checkbox7.stateChanged.connect(self.data_send_timer) # Send data button self.Pushbuttom6.clicked.connect(self.data_send) # Load log self.Pushbuttom4.clicked.connect(self.savefiles) # Load log self.Pushbuttom5.clicked.connect(self.openfiles) # Jump link self.commandLinkButton1.clicked.connect(self.link) # Clear send button self.Pushbuttom7.clicked.connect(self.send_data_clear) # Clear receive button self.Pushbuttom8.clicked.connect(self.receive_data_clear)
3.2 serial port detection procedure
Detect all serial ports on the computer, and the implementation code is as follows:
# Serial port detection def port_check(self): # Detect all existing serial ports and store the information in the dictionary self.Com_Dict = {} port_list = list(serial.tools.list_ports.comports()) self.Combobox1.clear() for port in port_list: self.Com_Dict["%s" % port[0]] = "%s" % port[1] self.Combobox1.addItem(port[0]) # No serial port judgment if len(self.Com_Dict) == 0: self.Combobox1.addItem("No serial port")
3.3. Set and open serial port program
After detecting the serial port, configure it, open the serial port, and start the timer to always receive user input. The implementation code is as follows:
# Open serial port def port_open(self): self.ser.port = self.Combobox1.currentText() # Serial port number self.ser.baudrate = int(self.Combobox2.currentText()) # Baud rate flag_data = int(self.Combobox3.currentText()) # Data bit if flag_data == 5: self.ser.bytesize = serial.FIVEBITS elif flag_data == 6: self.ser.bytesize = serial.SIXBITS elif flag_data == 7: self.ser.bytesize = serial.SEVENBITS else: self.ser.bytesize = serial.EIGHTBITS flag_data = self.Combobox4.currentText() # Check bit if flag_data == "None": self.ser.parity = serial.PARITY_NONE elif flag_data == "Odd": self.ser.parity = serial.PARITY_ODD else: self.ser.parity = serial.PARITY_EVEN flag_data = int(self.Combobox5.currentText()) # Stop bit if flag_data == 1: self.ser.stopbits = serial.STOPBITS_ONE else: self.ser.stopbits = serial.STOPBITS_TWO flag_data = self.Combobox6.currentText() # Flow control if flag_data == "No Ctrl Flow": self.ser.xonxoff = False #Software flow control self.ser.dsrdtr = False #Hardware flow control DTR self.ser.rtscts = False #Hardware flow control RTS elif flag_data == "SW Ctrl Flow": self.ser.xonxoff = True #Software flow control else: if self.Checkbox3.isChecked(): self.ser.dsrdtr = True #Hardware flow control DTR if self.Checkbox4.isChecked(): self.ser.rtscts = True #Hardware flow control RTS try: time.sleep(0.1) self.ser.open() except: QMessageBox.critical(self, "Serial port exception", "This serial port cannot be opened!") return None # After the serial port is opened, switch the enable state of the serial port button to prevent misoperation if self.ser.isOpen(): self.Pushbuttom1.setEnabled(False) self.Pushbuttom3.setEnabled(True) self.formGroupBox1.setTitle("Serial port status (on)") # Timer receiving data self.timer = QTimer() self.timer.timeout.connect(self.data_receive) # Open the serial port receiving timer with a cycle of 1ms self.timer.start(1)
3.4 program for sending data regularly
The timer can support data timing between 1ms and 30s, and the implementation code is as follows:
# Send data regularly def data_send_timer(self): try: if 1<= int(self.Lineedit1.text()) <= 30000: # Timing time within 1ms~30s if self.Checkbox7.isChecked(): self.timer_send.start(int(self.Lineedit1.text())) self.Lineedit1.setEnabled(False) else: self.timer_send.stop() self.Lineedit1.setEnabled(True) else: QMessageBox.critical(self, 'Abnormal timing sending data', 'The periodic data transmission can only be set within 30 seconds!') except: QMessageBox.critical(self, 'Abnormal timing sending data', 'Please set the correct value type!')
3.5 data sending procedure
ASCII character and hexadecimal type data can be sent, and the sending time can be displayed in front of the data. Line feed is carried out after the data, and a byte is sent. The TX flag will be automatically accumulated. The implementation code is as follows:
# send data def data_send(self): if self.ser.isOpen(): input_s = self.Text2.toPlainText() # Determine whether it is a non empty string if input_s != "": # Time display if self.Checkbox5.isChecked(): self.Text1.insertPlainText((time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())) + " ") # HEX send if self.Checkbox1.isChecked(): input_s = input_s.strip() send_list = [] while input_s != '': try: num = int(input_s[0:2], 16) except ValueError: QMessageBox.critical(self, 'Serial port exception', 'Please enter standard hexadecimal data, separated by spaces!') return None input_s = input_s[2:].strip() send_list.append(num) input_s = bytes(send_list) # ASCII send else: input_s = (input_s).encode('utf-8') # HEX receive display if self.Checkbox2.isChecked(): out_s = '' for i in range(0, len(input_s)): out_s = out_s + '{:02X}'.format(input_s[i]) + ' ' self.Text1.insertPlainText(out_s) # ASCII receive display else: self.Text1.insertPlainText(input_s.decode('utf-8')) # Receive newline if self.Checkbox6.isChecked(): self.Text1.insertPlainText('\r\n') # Get Text cursor textCursor = self.Text1.textCursor() # Scroll to bottom textCursor.movePosition(textCursor.End) # Set the cursor to Text self.Text1.setTextCursor(textCursor) # Count the number of characters sent num = self.ser.write(input_s) self.data_num_sended += num self.Lineedit2.setText(str(self.data_num_sended)) else: pass
3.6 data receiving procedure
ASCII character and hexadecimal data can be received, and the sending time can be displayed in front of the data. Line feed is carried out after the data, one byte is received, and the RX flag will be automatically accumulated. The implementation code is as follows:
# receive data def data_receive(self): try: num = self.ser.inWaiting() if num > 0: time.sleep(0.1) num = self.ser.inWaiting() #Delay and read the data again to ensure data integrity except: QMessageBox.critical(self, 'Serial port exception', 'Serial port receiving data is abnormal, please reconnect the device!') self.port_close() return None if num > 0: data = self.ser.read(num) num = len(data) # Time display if self.Checkbox5.isChecked(): self.Text1.insertPlainText((time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())) + " ") # HEX display data if self.Checkbox2.checkState(): out_s = '' for i in range(0, len(data)): out_s = out_s + '{:02X}'.format(data[i]) + ' ' self.Text1.insertPlainText(out_s) # ASCII display data else: self.Text1.insertPlainText(data.decode('utf-8')) # Receive newline if self.Checkbox6.isChecked(): self.Text1.insertPlainText('\r\n') # Get text cursor textCursor = self.Text1.textCursor() # Scroll to bottom textCursor.movePosition(textCursor.End) # Set the cursor to text self.Text1.setTextCursor(textCursor) # Count the number of characters received self.data_num_received += num self.Lineedit3.setText(str(self.data_num_received)) else: pass
3.7 log saving procedure
Save the data sent and received in the receiving box to TXT text, and the implementation code is as follows:
# Save log def savefiles(self): dlg = QFileDialog() filenames = dlg.getSaveFileName(None, "Save log file", None, "Txt files(*.txt)") try: with open(file = filenames[0], mode='w', encoding='utf-8') as file: file.write(self.Text1.toPlainText()) except: QMessageBox.critical(self, 'Log exception', 'Failed to save log file!')
3.8. Loading log program
Load the data information saved in TXT text into the send box, and the implementation code is as follows:
# Load log def openfiles(self): dlg = QFileDialog() filenames = dlg.getOpenFileName(None, "Load log file", None, "Txt files(*.txt)") try: with open(file = filenames[0], mode='r', encoding='utf-8') as file: self.Text2.setPlainText(file.read()) except: QMessageBox.critical(self, 'Log exception', 'Failed to load log file!')
3.9, open blog, official account program
Click the button to open my official account number two dimensional code and blog homepage.
# Open blog links and official account number two dimensional code. def link(self): dialog = QDialog() label_img = QLabel() label_img.setAlignment(Qt.AlignCenter) label_img.setPixmap(QPixmap("./img.jpg")) vbox = QVBoxLayout() vbox.addWidget(label_img) dialog.setLayout(vbox) dialog.setWindowTitle("Fast scan code, pay attention to the official account.~") dialog.setWindowModality(Qt.ApplicationModal) dialog.exec_() webbrowser.open('https://blog.csdn.net/m0_38106923')
3.10 clear the sending and receiving data display program
Clear the contents and count times of sending data frame and receiving data frame. The implementation code is as follows:
# Clear send data display def send_data_clear(self): self.Text2.setText("") self.data_num_sended = 0 self.Lineedit2.setText(str(self.data_num_sended)) # Clear received data display def receive_data_clear(self): self.Text1.setText("") self.data_num_received = 0 self.Lineedit3.setText(str(self.data_num_received))
3.11. Close the serial port program
Close the serial port, stop the timer, reset the component and flag status, and the implementation code is as follows:
# Close the serial port def port_close(self): try: self.timer.stop() self.timer_send.stop() self.ser.close() except: QMessageBox.critical(self, 'Serial port exception', 'Failed to close the serial port, please restart the program!') return None # Switch the serial port button enable status and timing transmission enable status self.Pushbuttom1.setEnabled(True) self.Pushbuttom3.setEnabled(False) self.Lineedit1.setEnabled(True) # Set the number of transmitted data and received data to zero self.data_num_sended = 0 self.Lineedit2.setText(str(self.data_num_sended)) self.data_num_received = 0 self.Lineedit3.setText(str(self.data_num_received)) self.formGroupBox1.setTitle("Serial port status (off)")