3

I am quite new to python and pyserial. My pc was installed with python 2.7.4 with pyserial and I want to print the serially received data on a seperate window on my pc. First the window has to be opened, then after the serial data should print on that window. Here the window has to be opened once and the serial data has to be continously print on the window until the device stops tramsmitting the data. I tried with this code, but its worthless. please someone help me with the code.

import serial
import Tkinter
from Tkinter import *
s = serial.Serial('COM10',9600)    # open serial port
master = Tk()
master.geometry("1360x750")        # a window pop up with width (1360) and height(750)     which exatly fits my monitor screen..

while 1:
if s.inWaiting():
text = s.readline(s.inWaiting())
frameLabel = Frame( master, padx=40, pady =40)
frameLabel.pack()
w = Text( frameLabel, wrap='word', font="TimesNewRoman 37")
w.insert(12.0,text )
w.pack()
w.configure( bg=master.cget('bg'), relief='flat', state='Normal' )

mainloop()
Steve
  • 73
  • 2
  • 2
  • 9
  • You might have a look at the first part of this answer http://stackoverflow.com/a/14040516 . It shows how to repeatedly call a function in tkinter loop. This is basically what you want to do instead of the `while True` loop. – FabienAndre Jun 05 '13 at 11:37
  • many thanks for your quick ansnswer. I will try with functions in tkinter loop. – Steve Jun 05 '13 at 12:36

1 Answers1

8

The problem here is that you have two loops that should be constantly running: The mainloop for the GUI and the loop for transmitting the serial data. What you can do to solve this is to start a new thread to receive the content of the serial port, put it in a Queue, and check periodically in the GUI thread the content of this queue:

import serial
import threading
import time
import Queue
import Tkinter as tk


class SerialThread(threading.Thread):
    def __init__(self, queue):
        threading.Thread.__init__(self)
        self.queue = queue
    def run(self):
        s = serial.Serial('/dev/ttyS0',9600)
        s.write(str.encode('*00T%'))
        time.sleep(0.2)
        while True:
            if s.inWaiting():
                text = s.readline(s.inWaiting())
                self.queue.put(text)

class App(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self.geometry("1360x750")
        frameLabel = tk.Frame(self, padx=40, pady =40)
        self.text = tk.Text(frameLabel, wrap='word', font='TimesNewRoman 37',
                            bg=self.cget('bg'), relief='flat')
        frameLabel.pack()
        self.text.pack()
        self.queue = Queue.Queue()
        thread = SerialThread(self.queue)
        thread.start()
        self.process_serial()

    def process_serial(self):
        value=True
        while self.queue.qsize():
            try:
                new=self.queue.get()
                if value:
                 self.text.delete(1.0, 'end')
                value=False
                 self.text.insert('end',new)
            except Queue.Empty:
                pass
        self.after(100, self.process_serial)

app = App()
app.mainloop()

This code is tested with my Pi3 ttyS0 serial port and serially connected PC and slave device: its 100% working with single device connected serially

ram
  • 43
  • 8
A. Rodas
  • 20,171
  • 8
  • 62
  • 72
  • Isn't the serial object providing a queue-like api, and thus sufficient to use as a queue ? In other words, would checking `inWaiting()` and reading directly from `process_serial` loop be enough ? – FabienAndre Jun 05 '13 at 12:10
  • @FabienAndre The problem is not reading from the serial port, but the fact that you are running two loops at the same time. The queue (in combination with the `after`method) is the safe way to communicate the two threading without freezing the GUI. – A. Rodas Jun 05 '13 at 12:32
  • I completely agree that the queue is the right way to handle two threads. My question was if in this case, is it needed (and why) to use a second thread instead of reading serial from the Tkinter `after loop`. As a try to be more explicit, why not just replace `queue.qsize` check by `serial.inWaiting` and `queue.get` by `serial.read` ? – FabienAndre Jun 05 '13 at 12:50
  • @FabienAndre You can do that as well, but then the information is retrieved periodically each 100 milliseconds (so then you don't have any loop apart from the Tkinter mainloop), while with the other approach the content is read just in the same moment that is sent. – A. Rodas Jun 05 '13 at 13:11
  • Now i am receiving the serial data which is printing on my pc screen. – Steve Jun 05 '13 at 13:42
  • @ A.Rodas. everything is perfect. if a device transmit two lines of ASCII data through serial port, then my pc will receive the data and print on the window. Next time when i receive the serial data from a device,i want only this data to be printed on my window, i dont want the previous received data on my window. – Steve Jun 05 '13 at 13:48
  • @Steve Glad it helped ;) Feel free to accept the answer if it solved your problem. – A. Rodas Jun 05 '13 at 13:52
  • i will explain in brief:my pc received serial data and printed on the window, this data should be on the window until i receive serial data again. but when i receive the second serial data, the first received data should disappear from the window and the second received data should print on my window.There is no time periods for the device which is transmitting the data.I have to print first sended serial data on my pc window, and should display until second serial data occurs.But first received data on the window should just vanish before the second received data print on the window. – Steve Jun 05 '13 at 14:05
  • @ A.Rodas, please try to give a solution for my comment. waiting for your reply. – Steve Jun 06 '13 at 11:22
  • @Steve I have edited my question including how to remove the previous content, which was also asked [here](http://stackoverflow.com/questions/16999041) (I suppose the only reason for this coincidence is because this is a kind of homework). – A. Rodas Jun 08 '13 at 12:44