Python Serial: How to use the read or readline function to read more than 1 character at a time
Asked Answered
P

5

38

I'm having trouble to read more than one character using my program, I can't seem to figure out what went wrong with my program.

import serial

ser = serial.Serial(
    port='COM5',\
    baudrate=9600,\
    parity=serial.PARITY_NONE,\
    stopbits=serial.STOPBITS_ONE,\
    bytesize=serial.EIGHTBITS,\
        timeout=0)

print("connected to: " + ser.portstr)
count=1

while True:
    for line in ser.read():

        print(str(count) + str(': ') + chr(line) )
        count = count+1

ser.close()

here are the results I get

connected to: COM5
1: 1
2: 2
3: 4
4: 3
5: 1

actually I was expecting this

connected to: COM5
1:12431
2:12431

something like the above mentioned which is able read multiple characters at the same time not one by one.

Priorate answered 18/4, 2013 at 8:22 Comment(2)
#59565215 Please can anyone guide me on thisZaid
Of all the documentation I found, nobody specified that I should be writing "port = 'COM5'" instead of just dev/usb0 or similar. Thank you!Choplogic
R
37

I see a couple of issues.

First:

ser.read() is only going to return 1 byte at a time.

If you specify a count

ser.read(5)

it will read 5 bytes (less if timeout occurrs before 5 bytes arrive.)

If you know that your input is always properly terminated with EOL characters, better way is to use

ser.readline()

That will continue to read characters until an EOL is received.

Second:

Even if you get ser.read() or ser.readline() to return multiple bytes, since you are iterating over the return value, you will still be handling it one byte at a time.

Get rid of the

for line in ser.read():

and just say:

line = ser.readline()
Rehnberg answered 18/4, 2013 at 18:34 Comment(2)
Hi, when I'm using line=ser.readline() , it always ask me for an integer print(str(count) + str(': ') + chr(line) ) TypeError: an integer is requiredPriorate
chr(line) is expecting an integer argument. You're giving it a string.Rehnberg
L
22

I use this small method to read Arduino serial monitor with Python

import serial
ser = serial.Serial("COM11", 9600)
while True:
     cc=str(ser.readline())
     print(cc[2:][:-5])
Laflam answered 9/9, 2018 at 1:57 Comment(2)
Nice, I needed to clean that response, good one! I think for future readers it's worth mentioning in your answer what exactly your code performs.Earleneearley
I assume you use cc[2:][:-5] to strip the b' and \r\n'. Wouldn't it be better to use .decode("utf-8") for this?Higgledypiggledy
E
12

Serial sends data 8 bits at a time, that translates to 1 byte and 1 byte means 1 character.

You need to implement your own method that can read characters into a buffer until some sentinel is reached. The convention is to send a message like 12431\n indicating one line.

So what you need to do is to implement a buffer that will store X number of characters and as soon as you reach that \n, perform your operation on the line and proceed to read the next line into the buffer.

Note you will have to take care of buffer overflow cases i.e. when a line is received that is longer than your buffer etc...

EDIT

import serial

ser = serial.Serial(
    port='COM5',\
    baudrate=9600,\
    parity=serial.PARITY_NONE,\
    stopbits=serial.STOPBITS_ONE,\
    bytesize=serial.EIGHTBITS,\
        timeout=0)

print("connected to: " + ser.portstr)

#this will store the line
line = []

while True:
    for c in ser.read():
        line.append(c)
        if c == '\n':
            print("Line: " + ''.join(line))
            line = []
            break

ser.close()
Eyesight answered 18/4, 2013 at 8:27 Comment(5)
Hi, could you give me some guide on the buffering? I'm really confused right now.Priorate
I edited the code, take a look. Just remember one thing, the code above will KEEP reading into the line array until it sees a \n character so make sure in your serial device sends a \n.Eyesight
Hi, the codes aboves doesn't seems to work. it says char is not defined.Priorate
Try now, i had char when i should have had 'c', just make sure ur serial program does indeed send '\n' characters after each lineEyesight
"You need to implement your own method that can read characters into a buffer until some sentinel is reached" - isn't this exactly what serial.readline does?Tetanus
M
6

I was reciving some date from my arduino uno (0-1023 numbers). Using code from 1337holiday, jwygralak67 and some tips from other sources:

import serial
import time

ser = serial.Serial(
    port='COM4',\
    baudrate=9600,\
    parity=serial.PARITY_NONE,\
    stopbits=serial.STOPBITS_ONE,\
    bytesize=serial.EIGHTBITS,\
        timeout=0)

print("connected to: " + ser.portstr)

#this will store the line
seq = []
count = 1

while True:
    for c in ser.read():
        seq.append(chr(c)) #convert from ANSII
        joined_seq = ''.join(str(v) for v in seq) #Make a string from array

        if chr(c) == '\n':
            print("Line " + str(count) + ': ' + joined_seq)
            seq = []
            count += 1
            break


ser.close()
Marjana answered 25/3, 2014 at 11:42 Comment(2)
I think your comment #convert from ansii should be #convert from asciiRegressive
This chr(c) made it for me after few days of turning around the problem. I have an ATTiny85 sending an int to an ATTiny45 sending this data to a Raspberry Pi 0. all using serial communication. I was just checking why it was displaying 48 when I was sending 0. ASCII was published in 1963. Always, back to the source. Thank you.Ainsley
S
0

A bit different:

import serial

ser = serial.Serial(
    port='COM5',
    baudrate=115200,
    parity=serial.PARITY_NONE,
    stopbits=serial.STOPBITS_ONE,
    bytesize=serial.EIGHTBITS,
    timeout=0
)

print("Connected to:", ser.portstr)

array_tmp = []

while True:
    byte_read = ser.read()  # Read bytes from serial port
    if byte_read:#if not empty
        byte_char = byte_read.decode()  # Decode bytes to string
        array_tmp.append(byte_char)
        if byte_char == '\n':
            print(''.join(array_tmp))  # Print the received line
            print(array_tmp)  # Print the received line
            array_tmp = []

ser.close()
Scoville answered 26/3 at 12:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.