Python串口读取byte类型数据并正确访问的方法
本文详细讲解如何使用Python的serial模块进行串口通信,重点说明接收到的bytes数据类型特性、整数与字节类型的转换差异,以及通过切片保留单字节对象的操作技巧。结合传感器数据解析与CSV文件写入实例,提供从零配置到完整运行的代码范例。
核心原理:Python串口数据的收发机制
Python的pyserial模块在进行串口通信时,底层严格遵循二进制传输标准。无论是字符串还是控制指令,本质上都必须以bytes(字节)序列的形式进行收发。理解这一特性是后续进行数据解析与类型安全访问的前提。
第一步:初始化串口连接参数
创建串口对象会直接触发底层串口的打开操作。需在导入模块后指定通信端口、波特率、校验位、停止位及超时策略。注意初始化语句应置于循环外部,避免反复耗时的硬件握手影响实时性。
import serial
import time
# 配置串口对象,timeout=None表示阻塞等待,0表示非阻塞,其他值为秒数
port = 'COM7' # Windows设备管理器查看端口名,Linux通常为/dev/ttyUSBx
baud = 115200
timex = 0.02 # 单次读取超时阈值
ser = serial.Serial(port, baud, timeout=timex)
第二步:执行数据写入与读取操作
发送数据使用write()方法,接收数据使用read(n)或read_all()。需要注意Python 3对编码方式的要求更为严格。
- 发送字符串:
ser.write(data.encode('utf-8')) - 发送十六进制指令:推荐使用
ser.write(bytes.fromhex('FE0107...'))(原稿中的.encode('hex')在Python 3中已废弃) - 接收数据:
data = ser.read(10)读取固定长度;read_all()清空缓冲区全部剩余数据
关键技巧:正确访问与处理byte类型数据
接收到的data变量类型为<class 'bytes'>。在实际开发中最容易踩坑的是索引访问时的类型隐式转换问题。
如果直接读取单个元素如data[0],Python 3会自动将其返回为对应的十进制整数(type(data[0])==int)。当业务逻辑需要保留原始的字节格式以便二次拼接或协议对齐时,应采用切片操作:
first_byte_as_int = data[0] # 返回 int 类型,例如 254
first_byte_as_bytes = data[0:1] # 返回 bytes 类型,即 b'\xfe'
切片[0:1]不仅能拿到第一个字节的数据,还能维持bytes容器属性,避免因类型不一致导致的后续运算报错。
第三步:按字节协议解析有效载荷
以下以读取SBT系列力传感器数据为例,展示完整的同步头识别、字节截取、32位有符号数转换及数据落盘流程。
import os
def save_data(force_val, csv_path):
"""将采集的压力值追加写入CSV文件"""
with open(csv_path, 'a', encoding='utf-8', newline='') as f:
writer = csv.writer(f)
now = time.time()
ts_fmt = "%Y-%m-%d %H:%M:%S"
time_main = time.strftime(ts_fmt, time.localtime(now))
ms_part = int((now % 1) * 1000)
timestamp = f"{time_main}.{ms_part:03d}"
writer.writerow([timestamp, force_val])
def main():
current_dir = os.path.dirname(os.path.abspath(__file__))
cur_time = time.localtime(time.time())
csv_name = f"{cur_time.tm_hour}-{cur_time.tm_min}-{cur_time.tm_sec}.csv"
csv_file = os.path.join(current_dir, csv_name)
# 预写入表头
with open(csv_file, 'w', encoding='utf-8', newline='') as f:
csv.writer(f).writerow(['timestamp(ms)', 'display(N)'])
ser = serial.Serial('COM7', 115200, timeout=0.02)
# 发送复位/读取指令(Hex格式)
ser.write(bytes.fromhex('FE010701000001CFFCCCFF'))
offset = 20 # 硬件零点偏差,需根据实际示数校准
while True:
start_sync = ser.read(1)
if not start_sync:
continue
if start_sync == b'\xFE':
raw_buf = ser.read(10)
if len(raw_buf) < 10 or raw_buf[9] != 0xFF:
continue
# 截取中间4个字节作为原始力值
raw_force = raw_buf[2:6]
# 组合为32位整数(大端序)
val = (raw_force[0] << 24) | (raw_force[1] << 16) | \
(raw_force[2] << 8) | raw_force[3]
# 处理32位有符号数溢出(补码转换)
if val > 0x7FFFFFFF:
val = val - 0x100000000
val -= offset
pressure = val / 100.0
print(f'压力值:{pressure} N')
save_data(pressure, csv_file)
if __name__ == '__main__':
import csv
main()
常见运行异常与排查建议
- 数据呈现乱码或随机大数值:首要排查项为波特率、数据位、停止位与校验位是否完全匹配上位机与下位机参数。
UnicodeDecodeError或类型错误:确保未将bytes直接当作str处理。涉及数学运算时先转换为整数,涉及文本展示再调用.decode('utf-8')。- 程序无响应或卡死:
serial.Serial()务必初始化在循环外;合理设置timeout,避免read()无限期阻塞占用主线程。
总结
以上就是Python串口读取byte类型数据并访问的详细方法与代码实现。掌握pyserial的字节流转机制、善用切片保留原始格式,并结合硬件协议规范进行掩码与补码处理,即可稳定搭建数据采集链路。更多关于Python物联网开发与串口调试的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













