【串口通信】python serial库时read、readline、read_all等方法的区别

  • 💖 作者简介:大家好,我是Zeeland,全栈领域优质创作者。
  • 📝 CSDN主页: Zeeland 🔥
  • 📣 我的博客: Zeeland
  • 📚 Github主页: Undertone0809 (Zeeland) (github.com)
  • 🎉 支持我:点赞👍+收藏⭐️+留言📝
  • 💬介绍:The mixture of software dev+Iot+ml+anything🔥

1. 概况

Python中Serial在读取数据的时候具有几种方法,本文将简单介绍一下如何使用serial库解析串口的数据。

2. 介绍

本文需要用到的几种方法和属性,大概看看就好,主要看下面的教程如何使用。

方法 功能
serial.read(size) 读取size字节的数据
serial.readline() 读取一行的数据
serial.readlines() 读取多行的数据,将数据保存到数组里
serial.read_all() 读取一个timeout周期内的全部数据(常用方法)
serial.read_all 读取串口所有的参数信息
serial_timeout(参数) 超时属性,下面具体介绍

3. 快速上手

  • 下面的场景我们需要用用COM4串口发送一串字符串 "hello world" ,波特率9600,如何使用python的 serial 库进行解析串口发送来的数据?

  • 直接上代码

import serial

ser = serial.Serial("COM2", 9600, timeout=0.01)

while True:
    data = ser.read_all()
    if data:
        rec_str = data.decode('utf-8')
        print(rec_str)
        
  • 这里我创建了两个虚拟的串口进行模拟,COM2向COM1发送了两次 hello world ,而Python端实现了COM1,监听来自COM2的消息,用 read_all() 方法读取接收到的数据,接收到的数据类型是 bytes 类型的,因此我们需要将 bytes 数组转成字符串print出来,如下图所示。

在这里插入图片描述

  • 而初始化的时候这里的 timeout 是指在设定的 timeout 时间范围内,如果读取的字节数据是有效的(就是非空)那就直接返回,否则一直会等到这个设定的timeout时间并返回这段时间所读的全部字节数据。

  • 简单来说你可以理解为每 timeout 秒读一次数据,而如果 timeout 太小,数据量太大,可能一次发送不完,会数据未读完的状态。

  • 也就是说,如果我的timeout设置为0.01,现在我有一个串口通信的传感器,传感器通过串口使用COM2发送一次数据,传感器如果在0.01秒内将所有数据都传输过来,就保存到缓存 buffer 中,到了0.01秒后会调用一次 read_all() 就可以读取到传感器发送到 buffer 中的数据了;如果传感器在0.01秒内没有将数据发送全的话, buffer 中的数据就是不完全的,就会返回不完全的数据;如果传感器在0.01秒内发送了数据的话, buffer 也会返回两组合在一起的数据。

注意:timeout的设置至关重要,如果不是特别高频的数据的话,timeout=0.01的100Hz完全够了,当然timeout最小支持多少要看你的波特率。如果我0.3秒发送了一次数据,timeout设置0.01,就可以返回一次完整的数据;如果我0.01秒发送一次数据,timeout设置0.3,那么一次就会返回30次数据,所以这就是timeout的作用。

  • 前面引入了 buffer 的概念,这里你应该可以知道,你可以直接把 buffer 理解为一个文件夹,读数据的方式是和 file 是一样的,只是引入的 timeout 的概念,使得 buffer 内的数据会以 1/timeout 的频率进行刷新。
  • 如果你把 buffer 当做 file 理解,那么 readline() 就是读取buffer中的一行,如果你的数据中存在 \n 这样的换行,那么用 readline() 先让不合适,很容易产生漏读的问题,而且如果你在一个 timeout 周期内没有用 readline() 处理完所有你想要的数据的话, buffer 就刷新了,因此通过笔者的实践和项目经历读数据只推荐用 read_all() 来读取。

4. 更好的解决方案——cushy-serial

cushy-serial是一个轻量级的Serial框架,初衷是希望使Serial编程变得更加简单、快捷,因此,相较于传统的pyserial,该框架可以更加快速地构建起一个serial程序,其可以兼容pyserial的所有特性,并且自定义serial消息异步回调,无需花费精力在多线程上,项目地址: https://github.com/Undertone0809/cushy-serial

主要特性

  • 兼容pyserial的所有特性
  • 自定义serial消息异步回调,无需花费精力在多线程上
  • 提供串口定时任务
  • 方便实现和管理多个serial连接
  • 可自定义消息协议,兼容性强

快速上手

pip install cushy-serial --upgrade 
  • 下面是一个简单的serial程序,当python客户端接收到来自串口的信息时会自动回调
from cushy_serial import CushySerial  
  
serial = CushySerial("COM1", 9600)  
serial.send("I am python client")  
  
  
@serial.on_message()  
def handle_serial_message(msg: bytes):  
    str_msg = msg.decode("utf-8")    
    print(f"[serial] rec msg: {str_msg}")  
  

需要说明的是,CushySerial兼容了Serial中所有的功能,因此,你可以在CushySerial中使用Serial的所有功能。

  • 运行结果如下
  • 如果你想要执行定时任务, CushySerial 也提供了相关的解决方案,你可以方便的轮询发送指令,并获取来自串口的信息,示例如下:
from cushy_serial import CushySerial, enable_log

enable_log()
serial = CushySerial("COM1", 9600)
instruction = bytes([0x01, 0x06, 0x00, 0x7F, 0x00, 0x01, 0x79, 0xD2])

# msg为你要轮询发送的指令,interval为轮询的时间间隔,times为执行次数,可不填写
@serial.polling_task(msg=instruction, interval=0.5, times=5)
def handle_rec_msg(rec_msg):
    print(f"[serial] rec polling message: {rec_msg}")

5. 总结

  • 在平时串口通信中,最好使用 read_all() 方法,并选定合适的timeout。
  • timeout的参考资料: 相关链接
  • 要是懒一点就直接用 cushy-serial

猜你想看:


版权声明:本文为linZinan_原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。