自学网站建设教程,北京建设工程招标网,wordpress后台不能拖动,泊头市建设网站目录前言安装pyserialpyserial大致概括整体流程硬件连接例子(简单版)详细使用serial初始化参数发包收包收包检查包并解包python struct模块结语前言
这几年#xff0c;自己也做了一些嵌入式机器人。在整个开发的过程中#xff0c;调通信通常会花费一段比较长的时间#xff…
目录前言安装pyserialpyserial大致概括整体流程硬件连接例子(简单版)详细使用serial初始化参数发包收包收包检查包并解包python struct模块结语前言
这几年自己也做了一些嵌入式机器人。在整个开发的过程中调通信通常会花费一段比较长的时间串口通信就是这样的一个部分。
而现在在百度上进行搜索发现对python串口通信的博客讲解都有点太笼统了这其中应该与python在处理硬件底层速度较慢导致用的人少有关系。
这里把python串口通信的部分进行一下个人使用过程中的总结。既是自我总结也让未来开发更快。 文章参考官方文档 https://pyserial.readthedocs.io/ python进行串口通信依赖的包就是pyserial因此本文是基于这个包进行总结。
总结过程中难免有理解不到位或者错误的地方欢迎大家提出问题并一起交流
安装pyserial
pip安装
python -m pip install pyserial
# 或者直接pip安装
pip install pyserialconda安装
conda install pyserial
#or
conda install -c conda-forge pyserialpyserial大致概括
整体流程
对于串口通信我们的大致流程如下 硬件连接
#mermaid-svg-QCPVC637ecFOoBdy {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-QCPVC637ecFOoBdy .error-icon{fill:#552222;}#mermaid-svg-QCPVC637ecFOoBdy .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-QCPVC637ecFOoBdy .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-QCPVC637ecFOoBdy .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-QCPVC637ecFOoBdy .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-QCPVC637ecFOoBdy .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-QCPVC637ecFOoBdy .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-QCPVC637ecFOoBdy .marker{fill:#333333;stroke:#333333;}#mermaid-svg-QCPVC637ecFOoBdy .marker.cross{stroke:#333333;}#mermaid-svg-QCPVC637ecFOoBdy svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-QCPVC637ecFOoBdy .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-QCPVC637ecFOoBdy .cluster-label text{fill:#333;}#mermaid-svg-QCPVC637ecFOoBdy .cluster-label span{color:#333;}#mermaid-svg-QCPVC637ecFOoBdy .label text,#mermaid-svg-QCPVC637ecFOoBdy span{fill:#333;color:#333;}#mermaid-svg-QCPVC637ecFOoBdy .node rect,#mermaid-svg-QCPVC637ecFOoBdy .node circle,#mermaid-svg-QCPVC637ecFOoBdy .node ellipse,#mermaid-svg-QCPVC637ecFOoBdy .node polygon,#mermaid-svg-QCPVC637ecFOoBdy .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-QCPVC637ecFOoBdy .node .label{text-align:center;}#mermaid-svg-QCPVC637ecFOoBdy .node.clickable{cursor:pointer;}#mermaid-svg-QCPVC637ecFOoBdy .arrowheadPath{fill:#333333;}#mermaid-svg-QCPVC637ecFOoBdy .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-QCPVC637ecFOoBdy .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-QCPVC637ecFOoBdy .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-QCPVC637ecFOoBdy .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-QCPVC637ecFOoBdy .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-QCPVC637ecFOoBdy .cluster text{fill:#333;}#mermaid-svg-QCPVC637ecFOoBdy .cluster span{color:#333;}#mermaid-svg-QCPVC637ecFOoBdy div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-QCPVC637ecFOoBdy :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}存在不存在将串口设备与电脑连接查看串口端口号代码收发包寻找原因并连接发包
#mermaid-svg-sWuMaf75ocTrALJY {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-sWuMaf75ocTrALJY .error-icon{fill:#552222;}#mermaid-svg-sWuMaf75ocTrALJY .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-sWuMaf75ocTrALJY .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-sWuMaf75ocTrALJY .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-sWuMaf75ocTrALJY .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-sWuMaf75ocTrALJY .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-sWuMaf75ocTrALJY .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-sWuMaf75ocTrALJY .marker{fill:#333333;stroke:#333333;}#mermaid-svg-sWuMaf75ocTrALJY .marker.cross{stroke:#333333;}#mermaid-svg-sWuMaf75ocTrALJY svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-sWuMaf75ocTrALJY .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-sWuMaf75ocTrALJY .cluster-label text{fill:#333;}#mermaid-svg-sWuMaf75ocTrALJY .cluster-label span{color:#333;}#mermaid-svg-sWuMaf75ocTrALJY .label text,#mermaid-svg-sWuMaf75ocTrALJY span{fill:#333;color:#333;}#mermaid-svg-sWuMaf75ocTrALJY .node rect,#mermaid-svg-sWuMaf75ocTrALJY .node circle,#mermaid-svg-sWuMaf75ocTrALJY .node ellipse,#mermaid-svg-sWuMaf75ocTrALJY .node polygon,#mermaid-svg-sWuMaf75ocTrALJY .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-sWuMaf75ocTrALJY .node .label{text-align:center;}#mermaid-svg-sWuMaf75ocTrALJY .node.clickable{cursor:pointer;}#mermaid-svg-sWuMaf75ocTrALJY .arrowheadPath{fill:#333333;}#mermaid-svg-sWuMaf75ocTrALJY .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-sWuMaf75ocTrALJY .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-sWuMaf75ocTrALJY .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-sWuMaf75ocTrALJY .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-sWuMaf75ocTrALJY .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-sWuMaf75ocTrALJY .cluster text{fill:#333;}#mermaid-svg-sWuMaf75ocTrALJY .cluster span{color:#333;}#mermaid-svg-sWuMaf75ocTrALJY div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-sWuMaf75ocTrALJY :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}导入pyserial库打开串口并设置串口参数发送数据关闭 or 循环发送收包
#mermaid-svg-U4GlsBOteAOpQaGN {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-U4GlsBOteAOpQaGN .error-icon{fill:#552222;}#mermaid-svg-U4GlsBOteAOpQaGN .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-U4GlsBOteAOpQaGN .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-U4GlsBOteAOpQaGN .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-U4GlsBOteAOpQaGN .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-U4GlsBOteAOpQaGN .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-U4GlsBOteAOpQaGN .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-U4GlsBOteAOpQaGN .marker{fill:#333333;stroke:#333333;}#mermaid-svg-U4GlsBOteAOpQaGN .marker.cross{stroke:#333333;}#mermaid-svg-U4GlsBOteAOpQaGN svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-U4GlsBOteAOpQaGN .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-U4GlsBOteAOpQaGN .cluster-label text{fill:#333;}#mermaid-svg-U4GlsBOteAOpQaGN .cluster-label span{color:#333;}#mermaid-svg-U4GlsBOteAOpQaGN .label text,#mermaid-svg-U4GlsBOteAOpQaGN span{fill:#333;color:#333;}#mermaid-svg-U4GlsBOteAOpQaGN .node rect,#mermaid-svg-U4GlsBOteAOpQaGN .node circle,#mermaid-svg-U4GlsBOteAOpQaGN .node ellipse,#mermaid-svg-U4GlsBOteAOpQaGN .node polygon,#mermaid-svg-U4GlsBOteAOpQaGN .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-U4GlsBOteAOpQaGN .node .label{text-align:center;}#mermaid-svg-U4GlsBOteAOpQaGN .node.clickable{cursor:pointer;}#mermaid-svg-U4GlsBOteAOpQaGN .arrowheadPath{fill:#333333;}#mermaid-svg-U4GlsBOteAOpQaGN .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-U4GlsBOteAOpQaGN .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-U4GlsBOteAOpQaGN .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-U4GlsBOteAOpQaGN .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-U4GlsBOteAOpQaGN .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-U4GlsBOteAOpQaGN .cluster text{fill:#333;}#mermaid-svg-U4GlsBOteAOpQaGN .cluster span{color:#333;}#mermaid-svg-U4GlsBOteAOpQaGN div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-U4GlsBOteAOpQaGN :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}导入pyserial库打开串口并设置串口参数python读取数据至缓存区从缓存区读取数据解包转换为自己需要的数据关闭串口 or 循环读取硬件连接
首先需要将串口设备与电脑相连并查看自己的串口的端口号是多少 串口的端口号就是将你的串口命名让程序或者系统能够快捷的寻找 对于windows设备
打开设备管理器 - 端口 - 寻找你的设备号 对于Windows来说串口设备端口号一般都是COMn这里COM8使用CH340串口芯片来进行通信
对于Linux设备(这里以Ubuntu为例)
ls /dev/ttyUSB*返回的就是你所有串口设备的设备号如果你具有多个设备则可以通过拔插之后查看哪个设备增删来确定你的设备名
问题
针对Ubuntu22.04可能出现找不到设备端口号的问题解决方法如下 Ubuntu22.04没有ttyUSB无法访问 ‘/dev/ttyUSB‘: 没有那个文件或目录问题解决 针对windows找不到端口一般来说都是驱动问题解决方法可参考下面博客 笔记本W10找不到端口com口及单片机串口连接的问题附51开发板的CH340串口芯片的驱动程序安装包 例子(简单版)
找到了设备的端口号之后就可以使用python来进行通信了。 我贴一个csdn上搜python串口通信的的第一个博客的代码例子。 代码来源: https://blog.csdn.net/weixin_43217958/article/details/109782000 import serial#导入串口通信库
from time import sleepser serial.Serial()def port_open_recv():#对串口的参数进行配置ser.portcom3ser.baudrate9600ser.bytesize8ser.stopbits1ser.parityN#奇偶校验位ser.open()if(ser.isOpen()):print(串口打开成功)else:print(串口打开失败)
#isOpen()函数来查看串口的开闭状态def port_close():ser.close()if(ser.isOpen()):print(串口关闭失败)else:print(串口关闭成功)def send(send_data):if(ser.isOpen()):ser.write(send_data.encode(utf-8))#编码print(发送成功,send_data)else:print(发送失败)if __name__ __main__:port_open_recv()while True:ainput(输入要发送的数据)send(a)sleep(0.5)#起到一个延时的效果这里如果不加上一个while True程序执行一次就自动跳出了但是这个例子并不适合直接拿来到嵌入式中进一步开发因为一些重要的参数和解包的方法并没有说明出来并且在python中涉及一些数据类型的转换也是比较复杂的(也是让我无数次抓狂的地方)。
详细使用
针对串口通信我们可以将其分为发包和收包。而想要比较方便的使用python来实现通信我们需要使用到python一个非常强大的功能包struct使用的讲解流程我将按照官网参数文档介绍 - 例子这样的顺序来解释。
serial初始化参数
class serial.Serial init(portNone, baudrate9600, bytesizeEIGHTBITS, parityPARITY_NONE, stopbitsSTOPBITS_ONE, timeoutNone, xonxoffFalse, rtsctsFalse, write_timeoutNone, dsrdtrFalse, inter_byte_timeoutNone, exclusiveNone) 参数
port – 串口名字(COMn或者/dev/ttyUSB)或者Nonebaudrate (int) – 波特率,比如9600或者115200bytesize – 数据位数可能的参数值有: FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITSparity – 奇偶校验可能的参数值: PARITY_NONE, PARITY_EVEN, PARITY_ODD ,PARITY_MARK, PARITY_SPACEstopbits – 停止位的比特数. 可能的参数值: STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWOtimeout (float) – 设置pyserial持续读取数据的最长时间(s)xonxoff (bool) – 是否启动软件流控制rtscts (bool) – 是否启动硬件(RTS/CTS)流控制dsrdtr (bool) – 是否启动硬件(DSR/DTR)流控制write_timeout (float) – 设置pyserial最长写入串口数据的时间(s)inter_byte_timeout (float) – 字符间超时, 没有则禁止(默认禁止).exclusive (bool) – 设置独占访问模式仅POSIX。 如果端口已经以独占访问模式打开则不能以独占访问模式打开端口。
异常退出
ValueError –如果一些参数不在允许参数内则返回ValueErro比如波特率设置SerialException – 如果设备无法被找到或者被设置则返回SerialException
说明 当我们初始化串口的时候open()函数会被调用串口就会被打开。
timeout参数会影响到read()函数的使用,这个timeout参数非常重要直接影响到我们对串口数据的读取。 timeout None: 一直等待直到设置的接收字节数满后退出 timeout 0: 非阻塞模式在任何情况下都立即返回返回零或更多最多为请求的字节数 timeout x:当请求的字节数可用时将timeout设置为x秒允许浮动立即返回否则等待超时到期并返回在此之前收到的所有字节。 而对于wrtie()(发包函数)而言默认为阻塞除非设置了write_timeout。
针对硬件流控制而言这个得观察嵌入式设备了我之前使用stm32和python通信的时候使用过一次得需要结合硬件连接和原理图说明但是我并没有完全搞透且其他时候用的也比较少这里就不展开叙述了。
发包
在嵌入式中我们使用发包一般是将我们的状态数据或者是控制指令通过转码为符合设备的通信协议的格式后将其发出。 因此我们在编写发包函数前需要先熟读通信协议并理解我们需要发送什么样的指令一般协议是16进制的一串数据。 pyserial中发包函数为write() write(data): 参数: 需要发送的数据 返回值: 写入的字节数 返回值类型: int 异常值返回 – 如果为端口配置了写入超时并且超过了时间。 将字节数据写入端口。这应该是字节类型(或兼容的如bytearray,memoryview)。必须对Unicode字符串进行编码例如“hello”.encode“utf-8”。 下面是参考实例
# Usart Library
import serial
import struct
import binascii
# Init serial port
Usart serial.Serial(port /dev/ttyUSB0, # 串口baudrate115200, # 波特率timeout 0.001 )# 判断串口是否打开成功
if Usart.isOpen():print(open success)
else:print(open failed)# 使用优雅的方式发送串口数据
# 这里的数据可以根据你的需求进行修改
send_data [0xA4,0x03,0x08,0x23,0xD2] #需要发送的串口包send_datastruct.pack(%dB%(len(send_data)),*send_data) #解析成16进制
print(send_data)
Usart.write(send_data) #发送
收包
针对收包我们一般流程就是 收包 - 检查包 - 解包,先查看官网中收包的函数文档 read(size1) 参数: size – 读取字节数
返回值: 串口读取得到的字节
返回值类型: bytes 从串行端口读取字节。如果设置了超时则返回的字符数可能少于请求的字符数。如果没有超时它将阻塞直到读取请求的字节数。
read_until(expectedLF, sizeNone) 参数: expected – 预期需要的字节。 size – 读多少字节。返回值: 串口读取到的字节数
返回值类型: bytes 读取数据直到找到预期的序列默认为“\n”、超过大小或超时。如果设置了超时则返回的字符可能少于请求的字符。如果没有超时它将阻塞直到读取请求的字节数。
in_waiting() 获得input buffer中缓存字节数 返回值类型: int 收包
我们首先需要从串口中读取缓存数据
# Usart Library
import serial
import struct
import binascii# Init serial port
Usart serial.Serial(port /dev/ttyUSB0, # 串口baudrate115200, # 波特率timeout 0.001 ) # 由于后续使用read在未收全数据的时候会按照一个timeout周期时间读取数据# 波特率115200返回数据时间大概是1ms,9600下大概是10ms# 所以读取时间设置0.001s# 判断串口是否打开成功
if Usart.isOpen():print(open success)
else:print(open failed)# ----读取串口数据-----------------------------------
try:count serial.inWaiting()if count 0:# 初始化数据Read_buffer []# 接收数据至缓存区Read_bufferserial.read(40) # 我们需要读取的是40个寄存器数据即40个字节# Read_data() # 前面两行可以注释换成后面这个函数
except KeyboardInterrupt:if serial ! None:print(close serial port)serial.close()#--------------------------------------------------------这里如果没有在0.001s的时间内读到40字节的包就会退出。因此我们需要结合通信协议来判断我们收到的包是否正确。
检查包并解包
这里根据我之前使用的一款IMU(GY-95T)为例子来演示用状态机判断包是否正确。
同时在函数中我也将解包函数放入后面再说明
def Read_data(self):Author: Liu Yuxiang Time: 2022.12.13description: 读取串口数据# 初始化数据counter 0 Recv_flag 0Read_buffer []# 接收数据至缓存区Read_bufferserial.read(40) # 我们需要读取的是40个寄存器数据即40个字节# 状态机判断收包数据是否准确while(1):# 第1帧是否是帧头ID 0xA4if (counter 0):if(Read_buffer[0] ! 0xA4):break # 第2帧是否是读功能码 0x03 elif (counter 1):if(Read_buffer[1] ! 0x03):counter0break# 第3帧判断起始帧 elif (counter 2):if(Read_buffer[2] 0x2c):start_regRead_buffer[2]else:counter0 # 第4帧判断帧有多少数量 elif (counter 3):if((start_regRead_buffer[3]) 0x2C): # 最大寄存器为2C 大于0x2C说明数据肯定错了lenRead_buffer[3]else:counter0break else:if(len5counter):#print(Recv done!)Recv_flag1# 收包完毕if(Recv_flag):Recv_flag 0sum 0#print(Read_buffer) # Read_buffer中的是byte数据字节流用struct包解包data_inspect str(binascii.b2a_hex(Read_buffer)) # data是将数据转化为原本的按照16进制的数据try: # 如果接收数据无误则执行数据解算操作for i in range(2,80,2): # 根据手册检验所有帧之和低八位是否等于末尾帧sum int(data_inspect[i:i2],16)if (str(hex(sum))[-2:] data_inspect[80:82]): # 如果数据检验没有问题则进入解包过程#print(the Rev data is right)# 数据低八位在前高八位在后#print(Read_buffer[4:-1]) unpack_data struct.unpack(hhhhhhhhhBhhhhhhhh,Read_buffer[4:-1])# 切片并将其解析为我们所需要的数据切出我们所需要的数据部分比如ACC_X unpack_data[0]/2048 * 9.8 # unit m/s^2ACC_Y unpack_data[1]/2048 * 9.8 ACC_Z unpack_data[2]/2048 * 9.8except:print(Have Error in receiving data!!)counter0 breakelse:counter 1 # 遍历整个接收数据的buffer而解包函数最关键的就是unpack_data struct.unpack(hhhhhhhhhBhhhhhhhh,Read_buffer[4:-1])
这一行代码的含义就是将Read_buffer[4:-1]的这部分数据按照小端的顺序解析成hhhhhhhhhBhhhhhhhh的排列顺序h代表short类型B代表unsigned char类型。
具体怎么根据你的情况使用就可以看一下python的struct模块。
python struct模块 tips: 一个byte8bit \xa4 这样一个数据代表了16bit 这部分内容是我在学习过程中借鉴很多网上写的好的帖子而做的笔记具体的帖子链接由于做笔记而找不着了就把自己的笔记贴出来 Python没有专门处理字节的数据类型。但由于bstr可以表示字节即bytes所以字节数组二进制str。在C语言中我们可以很方便地用struct、union来处理字节以及字节和intfloat的转换。
而在python中却会比较的麻烦但是python是提供了struct模块来解决bytes和其他二进制数据类型的转换
struct模块的两个函数struct.unpack和struct.pack函数 struct.pack(format, v1, v2, …) Return a bytes object containing the values v1, v2, … packed according to the format string format. The arguments must match the values required by the format exactly. struct.unpack(format, buffer) Unpack from the buffer buffer (presumably packed by pack(format, ...)) according to the format string format. The result is a tuple even if it contains exactly one item. The buffer’s size in bytes must match the size required by the format, as reflected by calcsize(). https://docs.python.org/3/library/struct.html#module-struct format也就是你需要将后面的数据转换为什么类型的数据而这个format主要有两部分组成指定打包数据的方式数据转换后的类型具体的表格参考如下
format可用于指示打包数据的字节顺序、大小和对齐方式如下表所示
CharacterByte orderSizeAlignmentnativenativenativenativestandardnonelittle-endianstandardnonebig-endianstandardnone!network ( big-endian)standardnone
大端(big-endian)小端(little-endian)较低的有效字节存放在较高的存储器地址中较高的有效字节存放在较低的存储器地址较高的有效字节存放在较高的存储器地址中较低的有效字节存放在较低的存储器地址比如数据是0x1234 低字节是0x12 高字节是0x34 小端读出来0x34 0x12 大端读出来就是0x12 0x34 而第二个部分也就是后面的数据要转换成什么类型。
FormatC TypePython typeStandard size(byte)Notesxpad byteno value(7)ccharbytes of length 11bsigned charinteger1(1), (2)Bunsigned charinteger1(2)?_Boolbool1(1)hshortinteger2(2)Hunsigned shortinteger2(2)iintinteger4(2)Iunsigned intinteger4(2)llonginteger4(2)Lunsigned longinteger4(2)qlong longinteger8(2)Qunsigned long longinteger8(2)nssize_tinteger(3)Nsize_tinteger(3)e(6)float2(4)ffloatfloat4(4)ddoublefloat8(4)schar[]bytes(9)pchar[]bytes(8)Pvoid*integer(5)
这么说会有点抽象
用具体的例子来看就是
import struct
struct.pack(I, 10240099) b\x00\x9cc意思就是说使用代表的字节顺序即big-endian(网络序)来将后面的数据转化成I代表的数据类型(4字节无符号整型)
(官网例子)
from struct import *
pack(bhl, 1, 2, 3)
b\x01\x00\x02\x00\x00\x00\x03
unpack(bhl, b\x01\x00\x02\x00\x00\x00\x03)
(1, 2, 3)
calcsize(bhl)
7这里和前面的例子是一个道理使用对齐的方式来将后面三个数据依次打包成b,h,l所代表的数据解包也是这样将一串byte数据按照对齐格式转换成b h l对对应的数据。
注意可以使用b4这样的写法来代表有一个数组 计算所选择的数据格式有多少字节 struct.calcsize(format) Return the size of the struct (and hence of the bytes object produced by pack(format, ...)) corresponding to the format string format. 结语
差不多这样就可以比较优雅的利用python接收和读取串口数据了。如有问题欢迎评论区提出。