跳到主要内容

MicroPython 开发

本章节包含以下部分,请按需阅读:

MicroPython 入门教程

初次接触 Pico MicroPython 开发,想要快速上手?我们为您准备了一套通用的入门教程。此教程旨在帮助开发者快速熟悉 Thonny IDE 并上手开发。教程内容涵盖环境搭建、项目创建、组件使用及外设编程等,帮助您迈出 MicroPython 编程的第一步。

配置开发环境

请参考 安装和配置 Thonny IDE 教程 下载安装 Thonny IDE。

示例程序

MicroPython 示例程序位于 示例程序包examples\MicroPython 目录中。

示例程序基础例程说明依赖库
01_GUI液晶 GUI 显示程序-
02_SD挂载 SD 卡-
03_IMU获取六轴传感器数据-
04_LVGL液晶 LVGL 显示程序LVGL V9.3

01_GUI

【程序说明】

  • 使用 SPI 与 液晶通讯,并通过 GUI 实现液晶显示触摸轨迹。

【硬件连接】

  • 使用 USB 线把板子接入电脑

【代码分析】

  • lcd = LCD_1inch54():创建 LCD 对象。
  • touch = Touch_CST816T():初始化触摸对象。
  • touch_gesture():手势测试。
  • touch_hand_writing():画点并显示在液晶。

【运行效果】

  • 通过 thonny 将 01_GUI 文件下的所有 py 文件上传到开发板中,运行 RP2350-Touch-LCD-1.54.py 程序。

    MicroPython-Example-1

02_SD

【程序说明】

  • 使用 SPI 与 SD 卡通讯,并将 SD 卡挂载到开发板,挂载成功后,可通过 Thonny 查看和修改 SD 卡中的内容。

【硬件连接】

  • 插入 SD 卡
  • 使用 USB 线把板子接入电脑

【代码分析】

  • sdcard.SDCard(spi, cs, baudrate):创建 SD 卡对象,并将初始化的 SPI 接口与 CS 引脚绑定到 SD 卡驱动中。
  • uos.mount(sd, '/sd'):将 SD 卡文件系统挂载到 /sd 目录下。挂载成功后,用户即可通过 /sd 路径对 SD 卡进行文件读写操作,例如创建、读取或删除文件。

【运行效果】

  • 通过 thonny 将 02_SD 文件下的所有 py 文件上传到开发板中,并复位。开发板复位后会根据 boot.py 的程序,自动将 SD 挂载到 sd 目录下。

    MicroPython-Example-2

03_IMU

【程序说明】

  • 使用 I2C 与 板载六轴传感器通讯,读取六轴传感器数据。

【硬件连接】

  • 使用 USB 线把板子接入电脑

【代码分析】

  • IMU = QMI8658():创建 IMU 对象。
  • IMU.Read_XYZ():读取六轴传感器数据。

【运行效果】

  • 使用 thonny 运行 03_IMU 文件下的 py 文件。

    MicroPython-Example-4

04_LVGL

【程序说明】

  • 使用 SPI 与液晶通讯,并通过 LVGL 实现显示文本和图片等功能。使用的版本号为 9.3,LVGL V9 的开发文档中没有提供 Python 示例,具体开发请参考 LVGL 开发文档

【硬件连接】

  • 使用 USB 线把板子接入电脑

【编译运行】

  • 操作步骤

    • 按住板上的 boot 按键,通过 USB 线将板子接到电脑的 USB 接口,然后松开按键,电脑会将开发板识别为一个可移动盘,将例程 firmware\MicroPython 目录下的 XXX-LVGL.uf2 文件复制到开发板中

    • 打开 Thonny,将例程中的 exampleslib 目录上传至开发板

      MicroPython-Example-5

    • 打开 examples 目录下的文件 XXX_LVGL_test.py,参考下图步骤运行程序

      MicroPython-Example-6

  • 构建固件

【代码分析】

源码结构

  • LVGL 库的源码请参考 lv_micropython

  • LVGL 库的相关设置在 lv_micropython\lib\lv_bindings\lv_conf.h 文件中,可以设置显示刷新频率、系统占用数据等。

  • LVGL 库的应用代码位于工程文件夹的 examples\LVGL_example.pylib\LVGL.py

    MicroPython-Example-7

LVGL 初始化

在使用 LVGL 图像库之前,您需要导入 LVGL 库

  • 导入 LVGL 库

    代码位置:lib\LVGL.py

    实现功能:导入 LVGL 库,并使用别名 lv 以方便调用其功能。

    import lvgl as lv
  • LVGL 初始化

    代码位置:lib\LVGL.py

    代码说明:LVGL 核心初始化位于 LVGL 类的初始化函数,在创建 LVGL 对象时自动调用。

    if not lv.is_initialized(): lv.init()
  • 创建 LVGL 对象

    代码位置:examples\XXX_LVGL_test.py

    实现功能:创建 LVGL 对象,并传入 LCD 和 TSC 对象作为参数。

    # Init LVGL
    LVGL(LCD=LCD,TSC=TSC)

LVGL 运行

LVGL 库定时调用心跳接口函数 lv.tick_inc 来通知 LVGL 过去的时间,以便 LVGL 能够更新其内部的时间状态,处理与时间相关的任务,例如动画、定时器等。此外还需要调用 lv.task_handler 函数,以便 LVGL 及时处理事件和任务,保证用户界面的响应和刷新。

  • LVGL 运行接口

    代码位置:lib\LVGL.py

    实现方式:创建一个 event_loop 对象。在该类的初始化函数中,我们创建一个定时器。该定时器会在设定的时间间隔内自动调用心跳接口函数和事件处理函数。调用的时间间隔可以通过传递 freq 参数调节,例如 lv_utils.event_loop(freq=200),默认为 40 ms。

    # Create event loop if not yet present
    if not lv_utils.event_loop.is_running(): self.event_loop=lv_utils.event_loop()
  • LVGL 心跳接口

    代码位置:lib\lv_utils.py

    实现方式:需要确保 lv.task_handler 的优先级低于 lv.tick_inc 的优先级,所以在本例中,lv.tick_inc 在定时器回调函数中调用。

    # 每 5ms 调用一次定时器回调函数
    self.timer.init(mode=Timer.PERIODIC, period=self.delay, callback=self.timer_cb) # 本例中 self.delay = 5

    def timer_cb(self, t):
    lv.tick_inc(self.delay)
    if self.scheduled < self.max_scheduled:
    try:
    micropython.schedule(self.task_handler_ref, 0)
    self.scheduled += 1 # 正在处理的任务数增加
    except:
    pass
  • LVGL 任务处理器

    代码位置:lib\lv_utils.py

    实现方式:要处理 LVGL 的任务,需要定期调用 lv.task_handler,本例在定时器回调函数中调用 lv.tick_inc 之后再进行调用。

    def task_handler(self, _):
    try:
    if lv._nesting.value == 0:
    lv.task_handler()
    if self.refresh_cb: self.refresh_cb()
    self.scheduled -= 1 # 正在处理的任务数减少
    except Exception as e:
    if self.exception_sink:
    self.exception_sink(e)

LVGL 显示

要实现 LVGL 显示,必须初始化一个显示驱动,并设置显示驱动的各个属性,例如,颜色格式、绘制缓冲区、渲染模式以及显示回调函数。在每个 LV_DEF_REFR_PERIOD(在 lv_conf.h 中设置),LVGL 会检测 UI 上是否发生了一些需要重绘的事情。例如,按下按钮、更改图表、发生动画等。需要重新绘制时,LVGL 调用显示回调函数完成图像在刷新区的绘制。

  • LVGL 显示刷新率设置

    代码位置:lv_micropython\lib\lv_bindings\lv_conf.h

    设置方式:在 lv_conf.h 中可以修改 LV_DEF_REFR_PERIOD 来改变屏幕的刷新时间。

    #define LV_DEF_REFR_PERIOD 10 // 单位:ms,这里为10ms
  • LVGL 显示相关变量定义

    代码位置:lib\LVGL.py

    实现功能:buf0buf1 大小设置为屏幕显示面积的 50% 是为了实现 LVGL 双缓冲机制,能够在降低大面积刷屏锯齿的同时有效提高屏幕刷新率。

    # Init LVGL display
    buf1 = lv.draw_buf_create(self.LCD.width, self.LCD.height // 2 , color_format, 0)
    buf2 = lv.draw_buf_create(self.LCD.width, self.LCD.height // 2 , color_format, 0)
  • LVGL 显示设备注册

    代码位置:lib\LVGL.py

    实现功能:根据设计需求完善 LVGL 库核心结构体变量,初始化显示驱动 disp_drv,并设置绘制缓冲区,该缓冲区是 LVGL 用来渲染屏幕内容的简单数组。一旦渲染准备就绪,绘制缓冲区的内容将使用显示驱动程序中设置的 disp_drv_flush_cb 函数发送到显示器。

    self.disp_drv = lv.display_create(self.LCD.width, self.LCD.height) # 创建显示驱动器对象,并设置宽度和高度
    self.disp_drv.set_color_format(color_format) # 设置颜色格式为 RGB565
    self.disp_drv.set_draw_buffers(buf1, buf2) # 设置绘制缓冲区
    self.disp_drv.set_render_mode(lv.DISPLAY_RENDER_MODE.PARTIAL) # 设置渲染模式为部分刷新模式
    self.disp_drv.set_flush_cb(self.disp_drv_flush_cb) # 设置显示回调函数
  • LVGL 显示回调函数

    代码位置:lib\LVGL.py

    实现功能:主要完成图像在刷新区的绘制。

    def disp_drv_flush_cb(self,disp_drv,area,color_p)
    参数:
    disp_drv : 显示驱动结构体指针,包含了与显示相关的信息和函数指针。该参数常用于通知刷新完成
    area : 区域结构体指针,包含待刷新区域的位置信息。在本例中,用于创建 TFT 显示的窗口
    color_p : 颜色结构体指针,表示要在刷新区域内显示的颜色数据。在本例中,作为DMA输入读取地址将数据传输到SPI总线,完成图像的绘制
  • LVGL 显示回调函数实现

    代码位置:lib\LVGL.py

    实现方式:在本例中为了最大化降低处理器的利用率,使用 DMA 来进行颜色数据的传输,设置 color_p 作为读地址,SPI 总线的输出数据寄存器为写地址。代码较长仅展示部分,完整代码请下载示例查看。

    def disp_drv_flush_cb(self,disp_drv,area,color_p):
    self.rp2_wait_dma() # 等待 DMA 空闲

    ......
    self.rgb565_swap_func(data_view, size) # 转换颜色格式

    self.LCD.setWindows(area.x1, area.y1, area.x2+1, area.y2+1) # 设置 LVGL 界面显示位置

    ...... # DMA 配置

    self.rp2_dma.enable() # 使能 DMA

    self.rp2_wait_dma() # 等待 DMA 空闲

    self.disp_drv.flush_ready() # 通知 LVGL 数据传输完成

LVGL 输入

在 LVGL 中,允许用户注册输入设备,如触摸板、鼠标、键盘或编码器等设备。用户可以通过这些输入设备控制用户界面,实现更好的交互。

  • LVGL 调用输入设备回调函数的频率设置

    代码位置:lv_micropython\lib\lv_bindings\lv_conf.h

    设置方式:与屏幕的刷新时间使用的是相同的宏,每 10ms 调用一次输入设备回调函数来更新输入设备所触发的事件,可通过修改 LV_DEF_REFR_PERIOD 定义进行设置。

    #define LV_DEF_REFR_PERIOD 10 // 单位:ms,这里为 10ms
  • LVGL 输入设备注册

    代码位置:examples\LVGL_example.py

    设置方式:注册触摸屏设备 indev_drv 并初始化。

    # Init touch screen as input device
    self.indev_drv = lv.indev_create() # 创建对象
    self.indev_drv.set_type(lv.INDEV_TYPE.POINTER) # 注册触摸屏设备
    self.indev_drv.set_read_cb(self.indev_drv_read_cb) # 设置回调函数
  • LVGL 的输入设备回调函数

    代码位置:lib\LVGL.py

    实现功能:主要用于更新输入事件。

    def indev_drv_read_cb(indev_drv, data)
    参数:
    indev_drv : LVGL 中的输入设备驱动结构体指针。在本例中,该结构体为触摸屏输入设备驱动
    data : LVGL 中的输入设备数据结构体指针。在本例中,该结构体用于存储输入设备的状态和数据,包括当前的触摸状态(按下或释放)以及触摸点的坐标
  • 触摸屏输入设备的回调函数实现

    代码位置:lib\CST816T.pylib\LVGL.py

    实现方式:主要是通过触摸中断更新触摸屏的触摸状态和触摸点坐标。

    def Int_Callback(self,pin):
    if self.Mode == 0 :
    self.Gestures = self._read_byte(0x01)

    elif self.Mode == 1 :
    self.Flag = 1
    self.get_point()

    elif self.Mode == 2 :
    self.Flag = 1
    self.get_point()
    self.Gestures = self._read_byte(0x01)

    def indev_drv_read_cb( self, indev_drv, data):
    self.rp2_wait_dma()

    data.point.x = self.TSC.X_point
    data.point.y = self.TSC.Y_point

    data.state = 1 if self.TSC.Flag == 1 else 0
    self.TSC.Flag = 0

LVGL 控件布局

在 LVGL 中,我们能够建立各种不同的用户界面。界面的基本组成部分是对象,也称为控件(Widgets),比如按钮(Button)、标签(Label)、图像(Image)、列表(List)、图表或文本区域。在一个界面中,可以同时创建多个控件,并且我们可以设置它们的位置、尺寸、父对象、样式以及事件处理程序等基本属性。

  • 创建 LVGL 界面对象

    代码位置:examples\LVGL_example.py

    实现功能:创建 LVGL 界面对象,并传入 LCD 、 TSC 、 IMU 对象作为参数。

    # Init WIDGETS
    WIDGETS(LCD=LCD,TSC=TSC,IMU=IMU)
  • LVGL 创建图块

    代码位置:examples\LVGL_example.py

    实现功能:Tile 视图是一个容器对象,其元素(称为图块)可以按网格形式排列。用户可以通过滑动来在各个图块之间导航。使用 Tile 视图对象调用 add_tile(tileview, row_id, col_id, dir) 在第 row_id 行和第 col_id 列上创建一个新图块。dir 可传入 lv.DIR.LEFT/RIGHT/TOP/BOTTOM/HOR/VER/ALL 等参数,以便通过滑动移动到给定方向的相邻图块。

    # 在 (0,0) 创建一个图块,支持向下滑动到 (0,1)
    self.tv = lv.tileview(self.scr)
    self.tile1 = self.tv.add_tile(0, 0, lv.DIR.BOTTOM)
  • LVGL 创建控件

    代码位置:examples\LVGL_example.py

    实现功能:创建控件,不同控件需要使用不同的函数接口,可以选择父对象进行创建。

    # 创建一个 table 控件,其中 tile2 为该控件的父对象,可以替换为 list、title 等可以有子对象的控件
    self.table_imu_data = lv.table(self.tile2)
  • LVGL 控件的对齐定位

    代码位置:examples\LVGL_example.py

    实现功能:使控件能够基于参考点进行偏移定位。控件对齐偏移的参考点控件的中心。

    对齐标准: LVGL 库具备内部对齐和外部对齐两种方式。默认以左上角作为原点,向左为水平方向的正方向,向下为垂直方向的正方向。

    # 将控件定位在中心点右偏移15个像素
    self.table_imu_data.align(lv.ALIGN.CENTER, 15 ,0)

    MicroPython-Example-8

  • LVGL 控件切换字体大小

    代码位置:lv_micropython\lib\lv_bindings\lv_conf.hexamples\LVGL_example.py

    实现功能:在实际运用时一个界面可能需要运用多种字体大小,可以在 lv_conf.h 中使能多种字体大小,且可以设置默认字体大小。设置字体大小时需要对控件风格化,使控件能够按照设置的风格进行渲染。利用 add_style 函数可以实现对控件各个部位在不同状态下的渲染。

    // lv_micropython\lib\lv_bindings\lv_conf.h
    #define LV_FONT_MONTSERRAT_16 1 // 使能16号字体
    #define LV_FONT_MONTSERRAT_18 1 // 使能18号字体
    #define LV_FONT_DEFAULT &lv_font_montserrat_18 // 设置默认字体大小为18号
    # examples\LVGL_example.py
    table_imu_data= lv.style_t() # 创建对象
    table_imu_data.init() # 初始化
    table_imu_data.set_text_font(lv.font_montserrat_16) # 设置字体大小为16

    self.table_imu_data.add_style(style_imu_table, 0) # 设置风格
  • LVGL 控件事件处理

    代码位置:examples\LVGL_example.py

    实现功能:在 LVGL 中,可以给控件添加事件处理回调函数,使控件发生被点击、滚动、重绘等事件时,触发事件从而进入事件处理回调函数。在程序中调用 obj.add_event_cb(event_cb, filter, None) 函数,为控件 obj 添加事件 filter 的处理函数 event_cb,当控件 obj 触发 filter 事件时,系统会自动调用 event_cb 函数。最后一个参数是指向事件中可用的任何自定义数据的指针。

    # 为控件 sw 添加事件 LV_EVENT_VALUE_CHANGED 的处理函数 sw_event_cb
    self.sw.add_event_cb(self.sw_event_cb, lv.EVENT.VALUE_CHANGED, None)

【运行效果】

  • 使用 thonny 运行 04_LVGL\examples 目录下的 LCD_1in54_LVGL_test.py 文件。

    接线图