【雕爷学编程】MicroPython手册之特定的库 machine — 与硬件相关的功能

在这里插入图片描述

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 的 machine 模块是一个用于与特定板上的硬件相关的功能的接口。该模块中的大多数函数允许实现对系统硬件块(如 CPU、定时器、总线等)的直接和不受限制的访问和控制。使用不当,这可能会导致电路板故障、锁定、崩溃,在极端情况下还会导致硬件损坏。

machine 模块的主要特点有:

它提供了一些与重置、中断、电源、唯一标识符等相关的函数,用于控制和查询设备的状态和行为。
它提供了一些用于原始内存访问的对象,可以通过下标运算符来读写指定地址的 8 位、16 位或 32 位数据。
它提供了一些用于创建和操作位图图像的类,可以使用不同的颜色格式和绘图方法来绘制像素、线条、矩形、文本等图形。
它提供了一些用于控制和检测外部 I/O 设备的类,如引脚、信号、模数转换器、脉宽调制器、串行通信总线等。
它提供了一些用于控制硬件定时器、实时时钟和看门狗定时器的类,用于实现精确的时间测量和控制。
它提供了一些用于操作安全数字存储卡的类,用于实现数据的持久化存储和管理。

machine 模块可以用于以下一些应用场景:

设备控制:利用 machine 模块,可以实现对设备的控制和配置。例如,可以使用 machine 模块来设置 CPU 的频率、重置或进入引导加载程序模式、禁用或启用中断请求等。
外设驱动:利用 machine 模块,可以实现对外部设备的驱动和通信。例如,可以使用 machine 模块来控制 LED 的亮度、读取温度传感器的数据、与其他设备进行串行或并行通信等。
图形显示:利用 machine 模块,可以实现对图形显示器的显示和控制。例如,可以使用 machine 模块来显示一些文本、图标、动画等,并根据需要进行滚动、旋转、缩放等变换。

使用 machine 模块时,需要注意以下事项:

在使用该模块上的任何其他方法之前,必须先调用相应类的构造函数来创建一个对象。创建时,需要传入一些与硬件相关的参数,如引脚号、频率、颜色格式等。
在对硬件进行修改操作后(如添加、删除或更新像素或图形),需要调用 flush 方法来将修改写入到硬件中。否则,修改可能会丢失或不一致。
在处理数据时,需要注意数据类型和长度的限制和转换。键和值都必须是 bytes 类型的对象,且长度不能超过 255 字节。如果要存储其他类型的对象,需要先序列化为 bytes 类型。

以下是一些使用 MicroPython 的 machine 模块的实际运用程序案例:

案例1:LED 闪烁:这是一个使用 machine 模块来控制 LED 的闪烁频率和亮度的程序案例。:

# 导入 machine 和 time 模块
import machine
import time

# 创建一个 Pin 对象,连接到 LED 的引脚
led = machine.Pin(2, machine.Pin.OUT)
# 创建一个 PWM 对象,连接到 LED 的引脚
pwm = machine.PWM(led)
# 设置 PWM 的频率为 1 Hz
pwm.freq(1)
# 循环改变 PWM 的占空比,从而改变 LED 的亮度
while True:
    # 从 0 到 1023 循环递增占空比
    for duty in range(1024):
        # 设置 PWM 的占空比
        pwm.duty(duty)
        # 等待 2 毫秒
        time.sleep_ms(2)
    # 从 1023 到 0 循环递减占空比
    for duty in range(1023, -1, -1):
        # 设置 PWM 的占空比
        pwm.duty(duty)
        # 等待 2 毫秒
        time.sleep_ms(2)

案例2:温度测量:这是一个使用 machine 模块来读取 DS18B20 温度传感器的数据,并将结果显示在 OLED 屏幕上的程序案例。:

# 导入 machine 和 framebuf 模块
import machine
import framebuf

# 创建一个 Pin 对象,连接到 DS18B20 的数据引脚
ds_pin = machine.Pin(5)
# 创建一个 OneWire 对象,连接到 DS18B20 的数据引脚
ds = machine.OneWire(ds_pin)
# 创建一个 DS18X20 对象,连接到 DS18B20 的数据引脚
ds_sensor = machine.DS18X20(ds)

# 创建一个 SPI 对象,连接到 SSD1306 OLED 显示器
spi = machine.SPI(1, baudrate=10000000, polarity=0, phase=0)
# 创建一个 Pin 对象,用于控制显示器的数据/命令选择
dc = machine.Pin(2)
# 创建一个 Pin 对象,用于控制显示器的复位
rst = machine.Pin(4)
# 创建一个 Pin 对象,用于控制显示器的片选
cs = machine.Pin(15)
# 创建一个 SSD1306_SPI 对象,用于控制显示器
oled = framebuf.SSD1306_SPI(128, 64, spi, dc, rst, cs)

# 创建一个字节数组作为缓冲区
buffer = bytearray(128 * 64 // 8)
# 创建一个 FrameBuffer 对象,使用单色垂直最低有效位格式
fbuf = framebuf.FrameBuffer(buffer, 128, 64, framebuf.MONO_VLSB)

# 循环读取温度数据,并显示在 OLED 上
while True:
    # 启动 DS18B20 的温度转换
    ds_sensor.convert_temp()
    # 等待一秒钟,让转换完成
    time.sleep(1)
    # 读取 DS18B20 的温度值,单位为摄氏度
    temp = ds_sensor.read_temp()
    # 将温度值转换为字符串,并添加单位符号
    temp_str = "{:.1f} C".format(temp)
    # 填充整个 FrameBuffer 为黑色
    fbuf.fill(0)
    # 在 FrameBuffer 上写入温度字符串,使用白色,并居中对齐
    fbuf.text(temp_str, (fbuf.width - len(temp_str) * 8) // 2, (fbuf.height - 8) // 2, 1)
    # 将 FrameBuffer 的内容显示在 OLED 上
    oled.blit(fbuf, 0, 0)
    # 刷新 OLED
    oled.show()

图形绘制:这是一个使用 machine 模块来绘制一些简单的几何图形,并将结果保存为 BMP 图像文件的程序案例。

# 导入 machine 和 ubinascii 模块
import machine
import ubinascii

# 定义一个函数,用于创建一个 BMP 图像文件的头部信息,并返回头部信息的字节对象
def create_bmp_header(width, height, bit_count):
    # 计算每行像素所占的字节数(需要对齐到 4 字节边界)
    row_size = (width * bit_count + 31) // 32 * 4
    # 计算图像数据所占的字节数(不包括头部信息)
    data_size = row_size * height
    # 计算文件大小(包括头部信息)
    file_size = data_size + 54
    # 计算数据偏移量(从文件开始到数据开始的字节数)
    data_offset = 54
    # 创建一个字节数组,用于存储头部信息
    header = bytearray(54)
    # 将文件类型标识符("BM")写入头部信息的前两个字节
    header[0:2] = b"BM"
    # 将文件大小(4 字节)写入头部信息的第 2 到第 6 个字节,使用小端序
    header[2:6] = file_size.to_bytes(4, "little")
    # 将数据偏移量(4 字节)写入头部信息的第 10 到第 14 个字节,使用小端序
    header[10:14] = data_offset.to_bytes(4, "little")
    # 将信息头大小(4 字节,固定为 40)写入头部信息的第 14 到第 18 个字节,使用小端序
    header[14:18] = (40).to_bytes(4, "little")
    # 将图像宽度(4 字节)写入头部信息的第 18 到第 22 个字节,使用小端序
    header[18:22] = width.to_bytes(4, "little")
    # 将图像高度(4 字节)写入头部信息的第 22 到第 26 个字节,使用小端序
    header[22:26] = height.to_bytes(4, "little")
    # 将颜色平面数(2 字节,固定为 1)写入头部信息的第 26 到第 28 个字节,使用小端序
    header[26:28] = (1).to_bytes(2, "little")
    # 将颜色位数(2 字节)写入头部信息的第 28 到第 30 个字节,使用小端序
    header[28:30] = bit_count.to_bytes(2, "little")
    # 返回头部信息的字节对象
    return header

# 定义一个函数,用于将 RGB888 颜色格式转换为 RGB565 颜色格式,并返回转换后的颜色值
def rgb888_to_rgb565(color):
    # 将颜色值分解为三个分量:红、绿、蓝
    r, g, b = color[0], color[1], color[2]
    # 将红色分量右移 3 位,保留最低 5 位
    r = r >> 3
    # 将绿色分量右移 2 位,保留最低 6 位
    g = g >> 2
    # 将蓝色分量右移 3 位,保留最低 5 位
    b = b >> 3
    # 将三个分量合并为一个 16 位的整数,按照 RGB565 的布局
    rgb565 = (r << 11) | (g << 5) | b
    # 返回转换后的颜色值
    return rgb565

# 定义一个函数,用于绘制一些简单的几何图形,并将结果保存为 BMP 图像文件
def draw_and_save_bmp(filename, width, height, bit_count):
    # 创建一个字节数组作为缓冲区,大小为 width * height * bit_count // 8(每个像素占 bit_count // 8 字节)
    buffer = bytearray(width * height * bit_count // 8)
    # 创建一个 FrameBuffer 对象,使用 RGB565 格式
    fbuf = framebuf.FrameBuffer(buffer, width, height, framebuf.RGB565)
    # 填充整个 FrameBuffer 为白色
    fbuf.fill(0xFFFF)
    # 在 FrameBuffer 上绘制一个红色的矩形,左上角坐标为 (10, 10),宽度为 50,高度为 30
    fbuf.fill_rect(10, 10, 50, 30, rgb888_to_rgb565((255, 0, 0)))
    # 在 FrameBuffer 上绘制一个绿色的圆形,圆心坐标为 (80, 40),半径为 20
    fbuf.fill_circle(80, 40, 20, rgb888_to_rgb565((0, 255, 0)))
    # 在 FrameBuffer 上绘制一个蓝色的三角形,顶点坐标分别为 (40, 70),(70, 90),(100, 70)
    fbuf.fill_triangle(40, 70, 70, 90, 100, 70, rgb888_to_rgb565((0, 0, 255)))
    # 打开 BMP 图像文件,以二进制模式写入
    with open(filename, "wb") as f:
        # 创建 BMP 图像文件的头部信息,并写入文件中
        header = create_bmp_header(width, height, bit_count)
        f.write(header)
        # 将缓冲区中的数据写入文件中
        f.write(buffer)

# 调用函数,绘制一些简单的几何图形,并将结果保存为 BMP 图像文件
draw_and_save_bmp("test.bmp", 128, 128, 16)

案例4:控制LED灯:

import machine
import time

# 初始化LED引脚
led_pin = machine.Pin(2, machine.Pin.OUT)

# 控制LED灯亮灭
led_pin.on()  # 打开LED灯
time.sleep(1)  # 延迟1秒
led_pin.off()  # 关闭LED灯
time.sleep(1)  # 延迟1秒

print("LED灯控制成功!")

在这个例子中,我们使用machine.Pin()函数初始化一个引脚对象,将其设置为输出模式。通过调用on()方法打开LED灯,调用off()方法关闭LED灯。使用time.sleep()函数进行延迟,以便观察LED灯的亮灭变化。

案例5:读取按钮输入::

import machine

# 初始化按钮引脚
button_pin = machine.Pin(4, machine.Pin.IN, machine.Pin.PULL_UP)

# 读取按钮状态
button_state = button_pin.value()

if button_state == 0:
    print("按钮被按下!")
else:
    print("按钮未被按下!")

在这个例子中,我们使用machine.Pin()函数初始化一个引脚对象,将其设置为输入模式,并启用上拉电阻。通过调用value()方法读取按钮引脚的状态,如果返回值为0,则表示按钮被按下,否则表示按钮未被按下。

案例6:PWM输出控制::

import machine

# 初始化PWM引脚
pwm_pin = machine.Pin(5)
pwm = machine.PWM(pwm_pin)

# 设置PWM参数
pwm.freq(1000)  # 设置频率为1kHz
pwm.duty(512)  # 设置占空比为50%

# 修改PWM参数
pwm.duty(256)  # 设置占空比为25%

# 关闭PWM输出
pwm.deinit()

print("PWM输出控制成功!")

在这个例子中,我们使用machine.Pin()函数初始化一个引脚对象,并使用machine.PWM()函数创建一个PWM对象。通过调用freq()方法设置PWM的频率,调用duty()方法设置PWM的占空比。可以根据需要多次调用duty()方法修改占空比。最后,调用deinit()方法关闭PWM输出。

案例7:控制LED灯:使用machine模块控制开发板上的LED灯的开关状态。

import machine
import time

# 配置LED引脚
led_pin = machine.Pin(2, machine.Pin.OUT)

# 开启LED灯
led_pin.on()
time.sleep(1)

# 关闭LED灯
led_pin.off()
time.sleep(1)

案例8:读取模拟传感器数据:使用machine模块读取模拟传感器的数据,如光敏电阻的电压。:

import machine

# 配置光敏电阻引脚
light_pin = machine.Pin(34, machine.Pin.IN)
adc = machine.ADC(light_pin)

# 读取光敏电阻的电压
voltage = adc.read() * 3.3 / 4095
print("Light Voltage:", voltage)

案例9:定时器中断处理:使用machine模块设置定时器中断,并在中断处理函数中执行特定操作,如定时采集传感器数据。:

import machine
import time

# 定义定时器中断处理函数
def timer_callback(timer):
    print("Timer interrupt occurred!")
    # 在此处执行需要定时执行的操作

# 配置定时器
timer = machine.Timer(0)
timer.init(period=5000, mode=machine.Timer.PERIODIC, callback=timer_callback)

# 主循环
while True:
    # 执行其他任务
    time.sleep(1)

这些案例展示了MicroPython的machine模块的一些实际运用程序。通过使用machine模块,可以对硬件资源进行访问和控制,如控制LED灯、读取模拟传感器数据和设置定时器中断等操作。你可以根据具体的应用需求进一步扩展和优化这些案例。请注意,在使用machine模块时,需要根据具体的硬件平台和引脚配置进行适配和调整。

在这里插入图片描述

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

驴友花雕

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

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

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

打赏作者

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

抵扣说明:

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

余额充值