Python串口:如何使用read或readline函数一次读取多个字符

37

我在使用我的程序时遇到了问题,无法读取超过一个字符,我似乎无法弄清楚我的程序出了什么问题。

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()

这是我得到的结果

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

事实上,我本来就期待这个。

connected to: COM5
1:12431
2:12431

类似上述内容,能够同时读取多个字符而不是逐个读取。


请问有人可以指导我如何解决Python中读取单个命令后串口被占用的问题吗? - nishant
在我找到的所有文档中,没有人特别指出我应该编写“port ='COM5'”而不仅仅是dev/usb0或类似的内容。谢谢! - IcanCwhatUsay
4个回答

36

我看到了几个问题。

首先:

ser.read() 一次只返回1个字节。

如果您指定了一个计数

ser.read(5)

它将读取5个字节(如果在5个字节到达之前超时则读取更少)。

如果您知道输入始终以EOL字符正确终止,则更好的方法是使用

ser.readline()

这将继续读取字符,直到接收到EOL。

第二点:

即使你使用ser.read()或ser.readline()返回多个字节, 因为你正在遍历返回值,你仍然会一次处理一个字节。

摆脱这个

for line in ser.read():

并且只需说:

line = ser.readline()

嗨,当我使用line=ser.readline()时,它总是要求输入整数,导致出现TypeError: an integer is required的错误。 print(str(count) + str(': ') + chr(line) ) - user2294001
1
chr(line) 需要一个整数参数,而你却传递了一个字符串。 - jwygralak67

21

我使用这个小方法来用Python读取Arduino串口监视器

import serial
ser = serial.Serial("COM11", 9600)
while True:
     cc=str(ser.readline())
     print(cc[2:][:-5])

不错,我需要清理那个响应,做得好!我认为对于未来的读者来说,值得在你的答案中提到你的代码具体执行什么。 - brasofilo
6
我猜你使用 cc[2:][:-5] 来去掉 b'\r\n'。使用 .decode("utf-8") 来完成这个任务不是更好吗? - Wouter

12

串行传输每次发送8位数据,这相当于1字节,而1字节表示1个字符。

您需要实现自己的方法,可以将字符读入缓冲区,直到达到某个标记。 约定是发送像 12431\n 这样的消息,表示一行。

因此,您需要实现一个缓冲区,它将存储X个字符,一旦达到该\n,就对该行执行操作,并继续将下一行读入缓冲区。

注意:您需要处理缓冲区溢出情况,例如接收到的行比您的缓冲区长等等...

编辑:

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()

你好,你能给我一些关于缓冲的指导吗?我现在非常困惑。 - user2294001
我编辑了代码,请看一下。只要记住一件事,上面的代码将会一直读取line数组,直到它遇到一个\n字符,所以请确保你的串行设备发送了一个\n - 1337holiday
嗨,上面的代码似乎无法工作。它说char未定义。 - user2294001
现在试试,我本应该使用 'c' 而不是 char,只需确保您的串行程序确实在每行后发送 '\n' 字符即可。 - 1337holiday
4
“你需要实现自己的方法,可以将字符读入缓冲区,直到达到某个标志” - 这难道不正是 serial.readline 所做的吗? - paxdiablo

6

我从我的Arduino Uno接收一些数据(0-1023数字)。 使用1337holiday、jwygralak67的代码以及其他来源的一些提示:

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()

4
我认为你的评论应该是 #convert from ascii。 - Nato Saichek
这个 chr(c) 在几天的问题研究后帮我解决了难题。我有一个 ATTiny85 发送一个整数到一个 ATTiny45,然后通过串口通讯将数据发送给 Raspberry Pi 0。当我发送 0 时,它为什么显示为 48,我正在检查这个问题。ASCII 是在 1963 年发表的。永远回到源头。谢谢。 - user5128720

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接