2012-10-22 13 views
14

Mam program Pythona, który odczytuje dane z portu szeregowego za pośrednictwem modułu PySerial. Dwa warunki, o których muszę pamiętać to: nie wiem, ile danych powstanie i nie wiem, kiedy oczekiwać danych.Za pomocą PySerial można czekać na dane?

podstawie tego, jakie wymyślił snipets kodowych obserwacji:

#Code from main loop, spawning thread and waiting for data 
s = serial.Serial(5, timeout=5) # Open COM5, 5 second timeout 
s.baudrate = 19200 

#Code from thread reading serial data 
while 1: 
    tdata = s.read(500) # Read 500 characters or 5 seconds 

    if(tdata.__len__() > 0):  #If we got data 
    if(self.flag_got_data is 0): #If it's the first data we recieved, store it 
     self.data = tdata   
    else:       #if it's not the first, append the data 
     self.data += tdata 
     self.flag_got_data = 1 

Więc ten kod będzie pętla zawsze uzyskanie danych od portu szeregowego. Dostaniemy do 500 znaków danych, a następnie powiadomimy główną pętlę, ustawiając flagę. Jeśli nie ma danych, po prostu wrócimy spać i czekać.

Kod działa, ale nie podoba mi się limit czasu 5s. Potrzebuję go, ponieważ nie wiem, ile danych można się spodziewać, ale nie podoba mi się, że budzi się co 5 sekund, nawet jeśli nie ma danych.

Czy istnieje sposób sprawdzenia, kiedy dane staną się dostępne przed wykonaniem read? Mam na myśli coś w rodzaju polecenia select w systemie Linux.

EDIT:
Tylko myślałem, że pamiętać, że znalazłem metodę inWaiting(), ale naprawdę wydaje się, że to po prostu zmienić „SLEEP” sondażu, więc to nie jest to, co chcę tutaj. Chcę tylko spać, dopóki nie pojawią się dane, i idź po niego.

Odpowiedz

15

Ok, faktycznie coś razem, że lubię tego. Za pomocą kombinacji read() bez limitu czasu i sposobu inWaiting():

#Modified code from main loop: 
s = serial.Serial(5) 

#Modified code from thread reading the serial port 
while 1: 
    tdata = s.read()   # Wait forever for anything 
    time.sleep(1)    # Sleep (or inWaiting() doesn't give the correct value) 
    data_left = s.inWaiting() # Get the number of characters ready to be read 
    tdata += s.read(data_left) # Do the read and combine it with the first character 

    ... #Rest of the code 

To wydaje się dawać wyniki chciałem, że to rodzaj funkcjonalności nie istnieje jako jednej metody w Pythonie

+1

'time.sleep (1)' wydaje się być dość brzydkim hackem, który dodaje kilka opóźnień do uzyskania danych. – TJD

+0

@TJD - Nie ma tam argumentu, wydaje się, że działa również bez snu, ale 'data_left' staje się bardzo niewiarygodny (łańcuch 19 znaków w pętlach jako 3, następnie 10, a następnie 6" banków "). Wciąż nie jestem z tego zadowolony, ale jest bliższy temu, o czym myślałem. Uśpij, aż dane, następnie odczytaj dane, a następnie wróć do trybu uśpienia. – Mike

+0

Nie widzę, jak to jest "niewiarygodne". Tak właśnie przybywają bajty, kiedy je czytasz.Możesz użyć 'interCharTimeout', która pozwala wykryć, kiedy odbiornik przestał widzieć nowe bajty. – TJD

10

Można ustawić timeout = None, a następnie wywołanie read zostanie zablokowane, dopóki nie pojawi się żądana liczba bajtów. Jeśli chcesz poczekać na nadejście danych, po prostu wykonaj read(1) z limitem czasu None. Jeśli chcesz sprawdzić dane bez blokowania, wykonaj read(1) z limitem czasu zero i sprawdź, czy zwraca jakiekolwiek dane.

(patrz dokumentacja http://pyserial.sourceforge.net/pyserial_api.html)

+1

Ale ja też myślę nie ma absolutnie nic złego w użyciu 5s limitu czasu i po to wzbudzenia i natychmiast wrócić do czytania. Jest to bardzo proste i nie będzie miało mierzalnego narzutów. – TJD

+0

Dzięki za informację, widziałem, że dokumentacja do odczytu nie mogła dowiedzieć się, jak zrobić to, co chciałem. Zgadzam się, że posiadanie pętli z limitem czasu nie jest strasznie kosztowne na komputerze stacjonarnym, ale (pochodzące z osadzonego tła) wydaje mi się tak błędne, że sondowanie – Mike

+0

Lepsze rozwiązanie w mojej opinii (przynajmniej dla moich potrzeb). Dziękuję za udostępnienie. – Marcel

0
def cmd(cmd,serial): 
    out='';prev='101001011' 
    serial.flushInput();serial.flushOutput() 
    serial.write(cmd+'\r'); 
    while True: 
     out+= str(serial.read(1)) 
     if prev == out: return out 
     prev=out 
    return out 

nazwać tak:

cmd('ATZ',serial.Serial('/dev/ttyUSB0', timeout=1, baudrate=115000)) 
Powiązane problemy