Python Forum
[Tkinter] Serial Port data readout
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[Tkinter] Serial Port data readout
#1
Hello,

I have designed a python serial link reader using tkinter and having some problem. The system is constructed on an arduino + tkinter reader gui. Both files are below. Arduino file performes the transmission in a switch case block depending on received "command", "1" starts "2" stops.

For testing:
On arduino side, I used arduino software serial monitor to start stop and I observed no problem as below

Python reader side, I minimized the gui with only necessary pieces as below, hit run button several times. Received bytevise data is below.

So I setup the serialport.read for single byte but the received value includes several bytes depending on the printed result. So how can this be possible?

I would like to ask kindly how to test this very simple reader code? It is related to threading maybe?

Maybe I' m testing in wrong way, please let me know.

Any help is appreciated.

Arduino serial monitor output
Output:
14999277 0 0 100 0 123 250 0 0 14999277 0 0 0 150 14999277 0 0 100 0 123 250 0 0 14999277 0 0 0 150 14999277 0 0 100 0 123 250 0 0 14999277 0 0 0 150
Python GUI output
Output:
STARTED Data read thread is ok! b'1' b'4' b'9' b'9' b'9' b'8' b'7' b'9' b' ' b'0' b' ' b'0' . . . STOPPED STARTED b''Data read thread is ok!b'1' b'4'b'9' b'9'b'9' b'8'b'7' b'9'b' ' b'0'b' ' b'0'b' ' b'1'b'4' . . . STOPPED STARTED b''b''Data read thread is ok! b'4'b'9'b'1' b'9'b'9'b'8' b'7'b'9'b' ' b'0'b' 'b'0' b' 'b'1'b'4' b'9'b'9'b'7' b'6'b'3'b'4' . . .
bool running = false;
int i=0;

void setup(void) {
  Serial.begin(9600);
}

void loop() {

  if (Serial.available() > 0) {
    char commmand = Serial.read();
    switch (commmand) {
      case '1' :
        running = true;
        break;

      case '2' :
        running = false;
        break;
    }
  }
 
 if ( running == true ){
      i=i+1;
      
      Serial.write("14999277");   // 1
      Serial.write(" ");
 
      ...
       
      Serial.write("150");        // 14
      Serial.write(" ");

      Serial.write(" ");
      Serial.write(" ");
      
      Serial.write("\r");       
      Serial.write("\n");
      
      delay(1000);
  }
}
Tkinter GUI

import tkinter as tk
from tkinter import *
from tkinter import ttk
import tkinter.font as tkFont
from threading import Timer
from threading import Thread
import time
from time import  sleep
import serial
import serial.tools.list_ports

class QCM_GUI():    
    def __init__(self):        
        self.root = tk.Tk()
        self.create_widgets()
        self.id  = 0
        self.CounterStartID = False
        self.mySerialPort=serial.Serial("COM4", 9600)        
        self.DataReaderStarted = False 
       
    def DataReaderThread(self):
        i=0
        while True:
            i += 1
            f=self.mySerialPort.read(1)
            print(f)
    
    # Running methods in Threads
    def Create_DataReaderThread(self):
        self.DataReaderThread_run = Thread(target=self.DataReaderThread, name='DataReaderThread')
        self.DataReaderThread_run.setDaemon(True)
        self.DataReaderThread_run.start()
        print("Data read thread is ok!")
        
    def start(self):        
        if self.CounterStartID == False:            
            startt='1'.encode()
            self.mySerialPort.write(startt)            
            print("STARTED")            
            self.mySerialPort.reset_input_buffer()
            self.mySerialPort.reset_output_buffer()
            print("self.DataReaderStarted: ", self.DataReaderStarted)            
            if self.DataReaderStarted == False :
                self.Create_DataReaderThread()
                ## self.DataReaderStarted == True
            else:
                pass            
            self.CounterStartID = True            
        else :
            print("STOPPED")
            stopp='2'.encode()
            self.mySerialPort.write(stopp)
            self.id  = 0
            self.CounterStartID = False            
            
    def create_widgets(self):        
        self.CounterStartStop_Button = tk.Button(self.root, text='RUN', fg='black', font='none 12 bold', command=self.start)
        self.CounterStartStop_Button.place(x=100, y=100, anchor='c')
        
gui = QCM_GUI()
gui.root.geometry('200x200')
gui.root.mainloop()
Reply
#2
It would appear that the number of characters printed on a line is equal to the number of threads that are running. It is interesting that the print statement keeps getting interrupted between printing the character and the newline.
Reply
#3
(Jun-11-2020, 11:32 AM)deanhystad Wrote: It would appear that the number of characters printed on a line is equal to the number of threads that are running. It is interesting that the print statement keeps getting interrupted between printing the character and the newline.


After 3rd start, there are 3 bytes printed together like b'4'b'9'b'1' And this continues like that.
Maybe the method I' m using is not correct. Suggestions for reading the serial port is also very welcome, If you think like that!
Reply
#4
You are getting multiple characters because you have multiple readers. After your first start you have one thread that is reading from the serial port. After your second start you have two threads that are reading the serial port. After your third start your have three threads reading from the port. Each thread reads one character and prints it out, but you end up reading and printing three characters at a time because all three threads are running at the same time. I am not sure why the printing works out as it does (all characters printed first followed by all the newlines), but since there is nothing controlling which thread is using stdout at any given time the results are not predictable.

What you probably want to do is only have one thread that reads the serial port. You can accomplish this by only starting one thread and leaving it running, or actually stopping the thread when your code says it is stopping. Your choice. So either:
    def start(self):        
        if self.CounterStartID == False:            
            startt='1'.encode()
            self.mySerialPort.write(startt)            
            print("STARTED")            
            self.mySerialPort.reset_input_buffer()
            self.mySerialPort.reset_output_buffer()
            print("self.DataReaderStarted: ", self.DataReaderStarted)            
            if self.DataReaderStarted == False :
                self.Create_DataReaderThread()
                self.DataReaderStarted == True
            else:
                pass            
            self.CounterStartID = True            
        else :
            print("STOPPED")
            stopp='2'.encode()
            self.mySerialPort.write(stopp)
            self.id  = 0
            self.CounterStartID = False
or
    def DataReaderThread(self):
        i=0
        while self.CounterStartID:
            i += 1
            f=self.mySerialPort.read(1)
            print(f)
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Serial port Auto detection GUI Tour PA3040 0 3,981 Aug-31-2020, 07:22 AM
Last Post: PA3040
  Read Data from Serial port PA3040 2 2,981 Feb-25-2020, 04:13 PM
Last Post: Denni
  [PyQt] Sending 4 bytes Hex data over serial in PyQt gratna 4 8,567 Nov-07-2019, 04:04 PM
Last Post: gratna

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020