Reputation: 974
Can anyone please give me a small and simple example on how to use threading with pyserial communication. I am googling for over three days and I am still illeterate and I dont even have a working piece of code which integrate both of them
Basically I am aiming to use threading in this scenario:
Have a serial communication continuously go on in the back ground to attain certain value (say A) from an MCU.
Stop attaining value A - then attain value B...and start continuously attaining value A again.
You can find some basic code here.
import threading
import time
import sys
import serial
import os
import time
def Task1(ser):
while 1:
print "Inside Thread 1"
ser.write('\x5A\x03\x02\x02\x02\x09') # Byte ArrayTo Control a MicroProcessing Unit
b = ser.read(7)
print b.encode('hex')
print "Thread 1 still going on"
time.sleep(1)
def Task2(ser):
print "Inside Thread 2"
print "I stopped Task 1 to start and execute Thread 2"
ser.write('x5A\x03\x02\x08\x02\x0F')
c = ser.read(7)
print c.encode('hex')
print "Thread 2 complete"
def Main():
ser = serial.Serial(3, 11520)
t1 = threading.Thread(target = Task1, args=[ser])
t2 = threading.Thread(target = Task2, args=[ser])
print "Starting Thread 1"
t1.start()
print "Starting Thread 2"
t2.start()
print "=== exiting ==="
ser.close()
if __name__ == '__main__':
Main()
Upvotes: 1
Views: 22228
Reputation: 15349
There's no factual basis for the claim by Task2
:
print "I stopped Task 1 to start and execute Thread 2"
Your implementation starts one thread then immediately starts the other without stopping the first. This means that the ser.read
and ser.write
commands could interfere with each other.
The simplest thing you could do to address this is to introduce variables that allow communication:
import sys
import os
import time
import threading
thread_flag = None
def Report(s):
print s
sys.stdout.flush() # helps to ensure messages from different threads appear in the right order
def Stop():
global thread_flag
thread_flag = 'stop'
def Task1(ser):
Report("Inside Thread 1")
global thread_flag
thread_flag = 'go'
while True:
Report("Thread 1 waiting for permission to read")
while thread_flag != 'go': time.sleep( 0.001 )
while thread_flag == 'go':
Report("Thread 1 is reading")
#ser.write('\x5A\x03\x02\x02\x02\x09') # Byte ArrayTo Control a MicroProcessing Unit
#b = ser.read(7)
#Report(b.encode('hex'))
time.sleep(1)
if thread_flag == 'stop': break
else: thread_flag = 'paused' # signals that the inner loop is done
Report("Thread 1 complete")
def Task2(ser):
Report("Inside Thread 2")
global thread_flag
thread_flag = 'pause' # signals Task1 to pause
while thread_flag != 'paused': time.sleep(0.001) # waits for Task1 inner loop to exit
Report("I stopped Task 1 to start and execute Thread 2")
#ser.write('x5A\x03\x02\x08\x02\x0F')
#c = ser.read(7)
#Report(c.encode('hex'))
thread_flag = 'go' # signals Thread 1 to resume
Report("Thread 2 complete")
def Main():
ser = None # serial.Serial(3, 11520)
t1 = threading.Thread(target = Task1, args=[ser])
t2 = threading.Thread(target = Task2, args=[ser])
Report("Starting Thread 1")
t1.start()
time.sleep(3)
Report("Starting Thread 2")
t2.start()
if __name__ == '__main__':
Main()
That approach uses a global variable, which is often frowned upon. You could instead make Task1
and Task2
methods of an object self
that carries both self.ser
and self.thread_flag
as attributes.
For any inter-thread communication more complex than this, you need to investigate locks, mutexes and semaphores (e.g. threading.Lock
)
Upvotes: 0