【雕爷学编程】MicroPython手册之内置模块 struct:二进制数据的打包和解包

在这里插入图片描述

MicroPython是为了在嵌入式系统中运行Python 3编程语言而设计的轻量级版本解释器。与常规Python相比,MicroPython解释器体积小(仅100KB左右),通过编译成二进制Executable文件运行,执行效率较高。它使用了轻量级的垃圾回收机制并移除了大部分Python标准库,以适应资源限制的微控制器。

MicroPython主要特点包括:
1、语法和功能与标准Python兼容,易学易用。支持Python大多数核心语法。
2、对硬件直接访问和控制,像Arduino一样控制GPIO、I2C、SPI等。
3、强大的模块系统,提供文件系统、网络、图形界面等功能。
4、支持交叉编译生成高效的原生代码,速度比解释器快10-100倍。
5、代码量少,内存占用小,适合运行在MCU和内存小的开发板上。
6、开源许可,免费使用。Shell交互环境为开发测试提供便利。
7、内置I/O驱动支持大量微控制器平台,如ESP8266、ESP32、STM32、micro:bit、掌控板和PyBoard等。有活跃的社区。

MicroPython的应用场景包括:
1、为嵌入式产品快速构建原型和用户交互。
2、制作一些小型的可 programmable 硬件项目。
3、作为教育工具,帮助初学者学习Python和物联网编程。
4、构建智能设备固件,实现高级控制和云连接。
5、各种微控制器应用如物联网、嵌入式智能、机器人等。

使用MicroPython需要注意:
1、内存和Flash空间有限。
2、解释执行效率不如C语言。
3、部分库函数与标准版有差异。
4、针对平台优化语法,订正与标准Python的差异。
5、合理使用内存资源,避免频繁分配大内存块。
6、利用原生代码提升速度关键部位的性能。
7、适当使用抽象来封装底层硬件操作。

总体来说,MicroPython让Python进入了微控制器领域,是一项重要的创新,既降低了编程门槛,又提供了良好的硬件控制能力。非常适合各类物联网和智能硬件的开发。

在这里插入图片描述
MicroPython的内置模块struct是一个用于打包和解包原始数据类型的模块,它可以用来在字节对象和其他数据类型之间进行转换。它的主要特点是:

1、它可以使用compile()方法将一个格式字符串编译为一个struct对象,以提高打包和解包的效率和复用性。
2、它可以使用pack()和unpack()方法在字节对象和元组之间进行打包和解包,或使用pack_into()和unpack_from()方法在字节对象和缓冲区3之间进行打包和解包。
3、它可以使用calcsize()方法计算给定格式字符串所需的字节数,或使用iter_unpack()方法在一个字节对象上迭代解包多个元组。
4、它支持一些常用的大小/字节顺序前缀,如@, <, >, !等,以指定数据的大小和对齐方式。
5、它支持一些常用的格式代码,如b, B, h, H, i, I, l, L, q, Q, s, P, f, d等,以指定数据的类型和长度。

struct模块的应用场景有:

1、用于进行一些二进制数据处理或分析的任务,例如读写文件,网络通信,协议解析等。
2、用于实现一些复杂的数据结构或逻辑,例如位域,位图,校验和等。
3、用于学习或教授一些二进制数据相关的知识或技能,例如字节序,数据对齐,数据压缩等。

struct模块的注意事项有:

1、struct模块实现了CPython模块的一个子集12,并且不支持空格在格式字符串中12,因此不能完全兼容CPython的功能和性能。
2、struct模块提供了对二进制数据的直接和不受限制的访问和控制,使用不当可能会导致数据错误,损坏或丢失。使用时需要谨慎并遵循相关的规范和指南。
3、struct模块使用的回调函数是在中断上下文中执行132 ,需要尽量简短和快速,避免执行复杂或耗时的操作,以免影响系统性能和稳定性。

以下是MicroPython的内置模块struct几个实际运用程序案例:

案例一:使用struct模块读取一个BMP文件的头部信息

# 导入struct模块
import struct

# 打开一个BMP文件
f = open('image.bmp', 'rb')

# 读取文件头部14个字节,并解包为一个元组
file_header = struct.unpack('<2sIHHI', f.read(14))

# 打印文件头部信息
print('File type:', file_header[0]) # 文件类型
print('File size:', file_header[1]) # 文件大小
print('Reserved 1:', file_header[2]) # 保留字段1
print('Reserved 2:', file_header[3]) # 保留字段2
print('Offset:', file_header[4]) # 偏移量

# 读取位图信息头部40个字节,并解包为一个元组
bitmap_header = struct.unpack('<IHHIIIIHHIIII', f.read(40))

# 打印位图信息头部信息
print('Header size:', bitmap_header[0]) # 头部大小
print('Width:', bitmap_header[1]) # 图像宽度
print('Height:', bitmap_header[2]) # 图像高度
print('Planes:', bitmap_header[3]) # 颜色平面数
print('Bits per pixel:', bitmap_header[4]) # 每像素位数
print('Compression:', bitmap_header[5]) # 压缩方式
print('Image size:', bitmap_header[6]) # 图像大小
print('X pixels per meter:', bitmap_header[7]) # 水平分辨率
print('Y pixels per meter:', bitmap_header[8]) # 垂直分辨率
print('Colors used:', bitmap_header[9]) # 使用的颜色数
print('Important colors:', bitmap_header[10]) # 重要的颜色数

# 关闭文件
f.close()

案例二:使用struct模块构造一个TCP数据包

# 导入struct模块
import struct

# 定义一个TCP数据包的格式字符串
tcp_format = '!HHIIHHHH'

# 定义一个TCP数据包的各个字段的值
source_port = 1234 # 源端口号
destination_port = 80 # 目的端口号
sequence_number = 1000 # 序列号
acknowledgment_number = 0 # 确认号
data_offset = 5 # 数据偏移
reserved = 0 # 保留字段
flags = 2 # 标志位,表示SYN
window_size = 65535 # 窗口大小
checksum = 0 # 校验和
urgent_pointer = 0 # 紧急指针

# 使用pack()方法将各个字段打包为一个字节对象
tcp_packet = struct.pack(tcp_format, source_port, destination_port, sequence_number, acknowledgment_number, (data_offset << 12) | (reserved << 6) | flags, window_size, checksum, urgent_pointer)

# 打印打包后的字节对象
print(tcp_packet)

案例三:使用struct模块解析一个浮点数的二进制表示

# 导入struct模块
import struct

# 定义一个浮点数的值
x = 3.14

# 使用pack()方法将浮点数打包为一个字节对象,使用'f'格式代码表示单精度浮点数,使用'>'前缀表示大端字节序
x_bytes = struct.pack('>f', x)

# 打印打包后的字节对象,以十六进制显示每个字节的值
print(x_bytes.hex())

# 使用unpack()方法将字节对象解包为一个元组,使用'I'格式代码表示无符号整数,使用'>'前缀表示大端字节序
x_int = struct.unpack('>I', x_bytes)[0]

# 打印解包后的整数值,以二进制显示每一位的值,使用format()方法指定32位长度和前缀'0b'
print(format(x_int, '032b'))

# 根据IEEE 754标准,单精度浮点数由1位符号位,8位指数位和23位尾数位组成,因此可以使用位运算和移位运算来提取各个部分的值
sign = (x_int >> 31) & 1 # 符号位为最高位,右移31位并与1按位与得到符号位的值
exponent = (x_int >> 23) & 0xff # 指数位为次高8位,右移23位并与0xff按位与得到指数位的值
mantissa = x_int & 0x7fffff # 尾数位为最低23位,与0x7fffff按位与得到尾数位的值

# 打印各个部分的值,以二进制显示每一位的值,使用format()方法指定长度和前缀'0b'
print('Sign:', format(sign, '01b'))
print('Exponent:', format(exponent, '08b'))
print('Mantissa:', format(mantissa, '023b'))

案例四:打包和解包数据:

import struct

# 打包数据
packed_data = struct.pack('i f s', 42, 3.14, b'Hello')
print("Packed Data:", packed_data)

# 解包数据
unpacked_data = struct.unpack('i f s', packed_data)
print("Unpacked Data:", unpacked_data)

在这个示例中,我们使用struct模块进行数据的打包和解包。我们使用pack()函数将数据打包成指定格式的字节流。在这里,我们打包了一个整数42,一个浮点数3.14,和一个字节串b’Hello’。然后,我们使用unpack()函数将打包后的字节流解包成原始数据。最后,我们打印出打包后的数据和解包后的数据。

案例五:处理二进制文件数据:

import struct

# 读取二进制文件
with open('data.bin', 'rb') as file:
    # 读取4字节的整数
    data = file.read(4)
    value = struct.unpack('i', data)[0]
    print("Value:", value)

在这个示例中,我们使用struct模块读取二进制文件中的数据。我们打开一个名为data.bin的二进制文件,并使用read()方法读取4字节的数据。然后,我们使用unpack()函数解包读取到的字节为一个整数。最后,我们打印出读取到的整数值。

案例六:将数据转换为网络字节序:

import struct
import socket

# 将整数转换为网络字节序
value = 12345
network_byte_order = socket.htonl(value)
packed_data = struct.pack('!L', network_byte_order)
print("Packed Data:", packed_data)

在这个示例中,我们使用struct模块将整数转换为网络字节序。首先,我们使用socket模块的htonl()函数将整数值12345转换为网络字节序。然后,我们使用pack()函数将转换后的网络字节序打包为一个无符号长整型数据。在这里,我们使用了!L来表示网络字节序和无符号长整型。最后,我们打印出打包后的数据。这些实际运用程序案例展示了使用MicroPython内置模块struct的功能。通过使用struct模块,可以进行数据的打包和解包,处理二进制文件数据,以及进行字节序转换等操作。这些功能在与底层数据交互、网络通信和二进制数据处理等场景中非常有用。

案例七:将数据打包为二进制格式

import struct

# 定义数据
name = "Alice"
age = 25
height = 1.65

# 使用 struct.pack() 打包数据
packed_data = struct.pack("5sif", name.encode(), age, height)

# 打印打包后的二进制数据
print("打包后的数据:", packed_data)

在这个例子中,我们使用 struct.pack() 函数将数据打包为二进制格式。我们定义了一个字符串类型的 name,一个整数类型的 age,和一个浮点数类型的 height。使用格式字符串 “5sif”,其中 “5s” 表示一个长度为 5 的字符串,“i” 表示一个整数,“f” 表示一个浮点数。我们将 name 使用 encode() 方法转换为字节串,然后将数据传递给 struct.pack() 函数。打包后的二进制数据将被打印出来。

案例八:从二进制数据中解包数据

import struct

# 定义二进制数据
packed_data = b'\x41\x6c\x69\x63\x65\x00\x00\x00\x19\x00\x00\xb0?\x00\x00\x00\x00'

# 使用 struct.unpack() 解包数据
unpacked_data = struct.unpack("5sif", packed_data)

# 打印解包后的数据
name, age, height = unpacked_data
print("解包后的数据:")
print("姓名:", name.decode())
print("年龄:", age)
print("身高:", height)

在这个例子中,我们有一段打包好的二进制数据 packed_data。使用 struct.unpack() 函数,我们可以从二进制数据中解包出原始的数据。我们使用与前面示例相同的格式字符串 “5sif” 进行解包。解包后的数据将返回一个元组,我们可以将其拆分为变量 name、age 和 height。我们将 name 使用 decode() 方法转换为字符串,并打印出解包后的数据。

案例九:计算校验和

import struct

# 定义数据
data = [10, 20, 30, 40, 50]

# 计算校验和
checksum = sum(data) & 0xFF

# 使用 struct.pack() 打包校验和
packed_checksum = struct.pack("B", checksum)

# 打印打包后的校验和
print("打包后的校验和:", packed_checksum)

在这个例子中,我们有一组数据 data,其中包含了一些整数。我们计算这些数据的校验和,使用 sum() 函数对数据求和,并使用位运算 & 0xFF 将结果限制在一个字节的范围内。然后,我们使用 struct.pack() 函数将校验和打包为一个字节的二进制格式。打包后的校验和将被打印出来。

这些示例展示了 struct 模块在 MicroPython 中的实际应用。你可以根据自己的需求进行修改和扩展。

在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

驴友花雕

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值