CoreP4X

支持以下产品:

CoreP4X

支持的组件

CoreP4X 支持以下组件:

  • M5UI:m5ui LVGL 组件库。

  • Unit:包含 Unit 驱动的 unit 软件包。

  • Module:用于扩展模块的 module 软件包。

  • Chain:用于 Chain 设备的 chain 软件包。

  • USB:用于 HID 设备的 usb.device 软件包。

支持的显示字体

CoreP4X 固件为 LVGL 和 M5UI 提供以下 Montserrat 字体:lv.font_montserrat_12、lv.font_montserrat_14、lv.font_montserrat_16、lv.font_montserrat_18、lv.font_montserrat_20、lv.font_montserrat_22、lv.font_montserrat_24、lv.font_montserrat_30、lv.font_montserrat_36、lv.font_montserrat_40、lv.font_montserrat_44、lv.font_montserrat_48。

对于 M5.Lcd.FONTS,固件还提供 AlibabaPuHuiTiCN24、AlibabaSansJA24 和 AlibabaSansKR24,分别用于显示中文、日文和韩文。

板载功能

CoreP4X 支持以下内置功能和外设:

  • 480 × 480 显示与电容触摸输入。

  • IMU 加速度计和陀螺仪读数。

  • RTC 日期和时间显示与调整。

  • USB 与电池电压监测、充电状态检测和 Port A 5 V 输出控制。

  • 扬声器 音调播放、音量调节和 PA 控制。

  • 麦克风 录音和扬声器回放。

  • 红外 NEC 协议发送与接收。

UiFlow2 示例

RTC 时钟

在 UiFlow2 中打开 corep4x_rtc_example.m5f2 项目。

读取内置 RTC,以 UTC 显示日期和蓝色 HH:MM:SS 时钟。点击 SET TIME,使用 +、- 调整时、分、秒。点击 SAVE 保存时间并保留原日期,或点击 CANCEL 放弃修改。

UiFlow2 代码块:

corep4x_rtc_example.png

示例输出:

无

IMU 传感器

在 UiFlow2 中打开 corep4x_imu_example.m5f2 项目。

显示内置加速度计和陀螺仪的 X、Y、Z 三轴读数。加速度单位为 g,角速度单位为度每秒(dps)。倾斜或旋转设备即可观察数值变化。

UiFlow2 代码块:

corep4x_imu_example.png

示例输出:

无

电源管理

在 UiFlow2 中打开 corep4x_power_example.m5f2 项目。

显示 USB VBUS 和电池电压(mV)、充电状态、Port A 5 V 输出状态和充电许可。实际充电时,电池电压显示为绿色。点击 PORT A 开关外部输出,点击 CHARGE 允许或禁止充电,不显示电量百分比。

UiFlow2 代码块:

corep4x_power_example.png

示例输出:

无

扬声器音调

在 UiFlow2 中打开 corep4x_speaker_tone_example.m5f2 项目。

使用独立滑条调节频率(200~4000 Hz)和音量(0~100%),默认值为 1000 Hz 和 70%。点击 Start tone 或 Stop tone 控制音调播放。PA 开关独立控制功放;启动时 PA 默认开启,音调默认停止。关闭 PA 仅关闭声音输出,不停止音调。

UiFlow2 代码块:

corep4x_speaker_tone_example.png

示例输出:

无

录音与播放

在 UiFlow2 中打开 corep4x_audio_example.m5f2 项目。

以 8 kHz、单声道、16 bit 将音频录入内存。点击 RECORD 开始录音,点击 STOP REC 结束,最长录制 30 秒。点击 PLAY 回放录音,点击 STOP PLAY 停止播放。音量滑条范围为 0~100%,默认 70%;播放时自动开启 PA。

UiFlow2 代码块:

corep4x_audio_example.png

示例输出:

无

红外发送与接收

在 UiFlow2 中打开 corep4x_ir_example.m5f2 项目。

使用 G13 的板载红外接收器和 G49 的发射器。点击发送按钮,发送地址为 0x08、数据字节逐次递增的 NEC 帧。界面显示发送数据、接收地址与数据以及接收次数。可使用支持 NEC 协议的红外遥控器测试接收。

UiFlow2 代码块:

corep4x_ir_example.png

示例输出:

无

MicroPython 示例

RTC 时钟

读取内置 RTC,以 UTC 显示日期和蓝色 HH:MM:SS 时钟。点击 SET TIME,使用 +、- 调整时、分、秒。点击 SAVE 保存时间并保留原日期,或点击 CANCEL 放弃修改。

MicroPython 代码块:

   1# SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
   2#
   3# SPDX-License-Identifier: MIT
   4
   5import os, sys, io
   6import M5
   7from M5 import *
   8import m5ui
   9import lvgl as lv
  10from hardware import RTC
  11import time
  12
  13
  14page_live = None
  15page_edit = None
  16label_title = None
  17label_date = None
  18label_live_hour = None
  19label_live_colon_1 = None
  20label_live_min = None
  21label_live_colon_2 = None
  22label_live_sec = None
  23button_set = None
  24label_edit_title = None
  25label_hour_name = None
  26label_min_name = None
  27label_sec_name = None
  28label_hour = None
  29label_min = None
  30label_sec = None
  31button_hour_plus = None
  32button_hour_minus = None
  33button_min_plus = None
  34button_min_minus = None
  35button_sec_plus = None
  36button_sec_minus = None
  37button_cancel = None
  38button_save = None
  39rtc = None
  40
  41
  42edit_hour = None
  43edit_min = None
  44edit_sec = None
  45
  46
  47def button_set_clicked_event(event_struct):
  48    global \
  49        page_live, \
  50        page_edit, \
  51        label_title, \
  52        label_date, \
  53        label_live_hour, \
  54        label_live_colon_1, \
  55        label_live_min, \
  56        label_live_colon_2, \
  57        label_live_sec, \
  58        button_set, \
  59        label_edit_title, \
  60        label_hour_name, \
  61        label_min_name, \
  62        label_sec_name, \
  63        label_hour, \
  64        label_min, \
  65        label_sec, \
  66        button_hour_plus, \
  67        button_hour_minus, \
  68        button_min_plus, \
  69        button_min_minus, \
  70        button_sec_plus, \
  71        button_sec_minus, \
  72        button_cancel, \
  73        button_save, \
  74        rtc, \
  75        edit_hour, \
  76        edit_min, \
  77        edit_sec
  78    page_edit.screen_load()
  79    edit_hour = (rtc.datetime())[4]
  80    edit_min = (rtc.datetime())[5]
  81    edit_sec = (rtc.datetime())[6]
  82    if edit_hour < 10:
  83        label_hour.set_text(str((str("0") + str(edit_hour))))
  84    else:
  85        label_hour.set_text(str(edit_hour))
  86    if edit_min < 10:
  87        label_min.set_text(str((str("0") + str(edit_min))))
  88    else:
  89        label_min.set_text(str(edit_min))
  90    if edit_sec < 10:
  91        label_sec.set_text(str((str("0") + str(edit_sec))))
  92    else:
  93        label_sec.set_text(str(edit_sec))
  94
  95
  96def button_hour_plus_clicked_event(event_struct):
  97    global \
  98        page_live, \
  99        page_edit, \
 100        label_title, \
 101        label_date, \
 102        label_live_hour, \
 103        label_live_colon_1, \
 104        label_live_min, \
 105        label_live_colon_2, \
 106        label_live_sec, \
 107        button_set, \
 108        label_edit_title, \
 109        label_hour_name, \
 110        label_min_name, \
 111        label_sec_name, \
 112        label_hour, \
 113        label_min, \
 114        label_sec, \
 115        button_hour_plus, \
 116        button_hour_minus, \
 117        button_min_plus, \
 118        button_min_minus, \
 119        button_sec_plus, \
 120        button_sec_minus, \
 121        button_cancel, \
 122        button_save, \
 123        rtc, \
 124        edit_hour, \
 125        edit_min, \
 126        edit_sec
 127    edit_hour = (edit_hour + 1) % 24
 128    if edit_hour < 10:
 129        label_hour.set_text(str((str("0") + str(edit_hour))))
 130    else:
 131        label_hour.set_text(str(edit_hour))
 132
 133
 134def button_hour_minus_clicked_event(event_struct):
 135    global \
 136        page_live, \
 137        page_edit, \
 138        label_title, \
 139        label_date, \
 140        label_live_hour, \
 141        label_live_colon_1, \
 142        label_live_min, \
 143        label_live_colon_2, \
 144        label_live_sec, \
 145        button_set, \
 146        label_edit_title, \
 147        label_hour_name, \
 148        label_min_name, \
 149        label_sec_name, \
 150        label_hour, \
 151        label_min, \
 152        label_sec, \
 153        button_hour_plus, \
 154        button_hour_minus, \
 155        button_min_plus, \
 156        button_min_minus, \
 157        button_sec_plus, \
 158        button_sec_minus, \
 159        button_cancel, \
 160        button_save, \
 161        rtc, \
 162        edit_hour, \
 163        edit_min, \
 164        edit_sec
 165    edit_hour = (edit_hour + -1) % 24
 166    if edit_hour < 10:
 167        label_hour.set_text(str((str("0") + str(edit_hour))))
 168    else:
 169        label_hour.set_text(str(edit_hour))
 170
 171
 172def button_min_plus_clicked_event(event_struct):
 173    global \
 174        page_live, \
 175        page_edit, \
 176        label_title, \
 177        label_date, \
 178        label_live_hour, \
 179        label_live_colon_1, \
 180        label_live_min, \
 181        label_live_colon_2, \
 182        label_live_sec, \
 183        button_set, \
 184        label_edit_title, \
 185        label_hour_name, \
 186        label_min_name, \
 187        label_sec_name, \
 188        label_hour, \
 189        label_min, \
 190        label_sec, \
 191        button_hour_plus, \
 192        button_hour_minus, \
 193        button_min_plus, \
 194        button_min_minus, \
 195        button_sec_plus, \
 196        button_sec_minus, \
 197        button_cancel, \
 198        button_save, \
 199        rtc, \
 200        edit_hour, \
 201        edit_min, \
 202        edit_sec
 203    edit_min = (edit_min + 1) % 60
 204    if edit_min < 10:
 205        label_min.set_text(str((str("0") + str(edit_min))))
 206    else:
 207        label_min.set_text(str(edit_min))
 208
 209
 210def button_min_minus_clicked_event(event_struct):
 211    global \
 212        page_live, \
 213        page_edit, \
 214        label_title, \
 215        label_date, \
 216        label_live_hour, \
 217        label_live_colon_1, \
 218        label_live_min, \
 219        label_live_colon_2, \
 220        label_live_sec, \
 221        button_set, \
 222        label_edit_title, \
 223        label_hour_name, \
 224        label_min_name, \
 225        label_sec_name, \
 226        label_hour, \
 227        label_min, \
 228        label_sec, \
 229        button_hour_plus, \
 230        button_hour_minus, \
 231        button_min_plus, \
 232        button_min_minus, \
 233        button_sec_plus, \
 234        button_sec_minus, \
 235        button_cancel, \
 236        button_save, \
 237        rtc, \
 238        edit_hour, \
 239        edit_min, \
 240        edit_sec
 241    edit_min = (edit_min + -1) % 60
 242    if edit_min < 10:
 243        label_min.set_text(str((str("0") + str(edit_min))))
 244    else:
 245        label_min.set_text(str(edit_min))
 246
 247
 248def button_sec_plus_clicked_event(event_struct):
 249    global \
 250        page_live, \
 251        page_edit, \
 252        label_title, \
 253        label_date, \
 254        label_live_hour, \
 255        label_live_colon_1, \
 256        label_live_min, \
 257        label_live_colon_2, \
 258        label_live_sec, \
 259        button_set, \
 260        label_edit_title, \
 261        label_hour_name, \
 262        label_min_name, \
 263        label_sec_name, \
 264        label_hour, \
 265        label_min, \
 266        label_sec, \
 267        button_hour_plus, \
 268        button_hour_minus, \
 269        button_min_plus, \
 270        button_min_minus, \
 271        button_sec_plus, \
 272        button_sec_minus, \
 273        button_cancel, \
 274        button_save, \
 275        rtc, \
 276        edit_hour, \
 277        edit_min, \
 278        edit_sec
 279    edit_sec = (edit_sec + 1) % 60
 280    if edit_sec < 10:
 281        label_sec.set_text(str((str("0") + str(edit_sec))))
 282    else:
 283        label_sec.set_text(str(edit_sec))
 284
 285
 286def button_sec_minus_clicked_event(event_struct):
 287    global \
 288        page_live, \
 289        page_edit, \
 290        label_title, \
 291        label_date, \
 292        label_live_hour, \
 293        label_live_colon_1, \
 294        label_live_min, \
 295        label_live_colon_2, \
 296        label_live_sec, \
 297        button_set, \
 298        label_edit_title, \
 299        label_hour_name, \
 300        label_min_name, \
 301        label_sec_name, \
 302        label_hour, \
 303        label_min, \
 304        label_sec, \
 305        button_hour_plus, \
 306        button_hour_minus, \
 307        button_min_plus, \
 308        button_min_minus, \
 309        button_sec_plus, \
 310        button_sec_minus, \
 311        button_cancel, \
 312        button_save, \
 313        rtc, \
 314        edit_hour, \
 315        edit_min, \
 316        edit_sec
 317    edit_sec = (edit_sec + -1) % 60
 318    if edit_sec < 10:
 319        label_sec.set_text(str((str("0") + str(edit_sec))))
 320    else:
 321        label_sec.set_text(str(edit_sec))
 322
 323
 324def button_cancel_clicked_event(event_struct):
 325    global \
 326        page_live, \
 327        page_edit, \
 328        label_title, \
 329        label_date, \
 330        label_live_hour, \
 331        label_live_colon_1, \
 332        label_live_min, \
 333        label_live_colon_2, \
 334        label_live_sec, \
 335        button_set, \
 336        label_edit_title, \
 337        label_hour_name, \
 338        label_min_name, \
 339        label_sec_name, \
 340        label_hour, \
 341        label_min, \
 342        label_sec, \
 343        button_hour_plus, \
 344        button_hour_minus, \
 345        button_min_plus, \
 346        button_min_minus, \
 347        button_sec_plus, \
 348        button_sec_minus, \
 349        button_cancel, \
 350        button_save, \
 351        rtc, \
 352        edit_hour, \
 353        edit_min, \
 354        edit_sec
 355    page_live.screen_load()
 356
 357
 358def button_save_clicked_event(event_struct):
 359    global \
 360        page_live, \
 361        page_edit, \
 362        label_title, \
 363        label_date, \
 364        label_live_hour, \
 365        label_live_colon_1, \
 366        label_live_min, \
 367        label_live_colon_2, \
 368        label_live_sec, \
 369        button_set, \
 370        label_edit_title, \
 371        label_hour_name, \
 372        label_min_name, \
 373        label_sec_name, \
 374        label_hour, \
 375        label_min, \
 376        label_sec, \
 377        button_hour_plus, \
 378        button_hour_minus, \
 379        button_min_plus, \
 380        button_min_minus, \
 381        button_sec_plus, \
 382        button_sec_minus, \
 383        button_cancel, \
 384        button_save, \
 385        rtc, \
 386        edit_hour, \
 387        edit_min, \
 388        edit_sec
 389    rtc.init(
 390        (
 391            ((rtc.datetime())[0]),
 392            ((rtc.datetime())[1]),
 393            ((rtc.datetime())[2]),
 394            edit_hour,
 395            edit_min,
 396            edit_sec,
 397            0,
 398            0,
 399        )
 400    )
 401    page_live.screen_load()
 402
 403
 404def button_set_event_handler(event_struct):
 405    global \
 406        page_live, \
 407        page_edit, \
 408        label_title, \
 409        label_date, \
 410        label_live_hour, \
 411        label_live_colon_1, \
 412        label_live_min, \
 413        label_live_colon_2, \
 414        label_live_sec, \
 415        button_set, \
 416        label_edit_title, \
 417        label_hour_name, \
 418        label_min_name, \
 419        label_sec_name, \
 420        label_hour, \
 421        label_min, \
 422        label_sec, \
 423        button_hour_plus, \
 424        button_hour_minus, \
 425        button_min_plus, \
 426        button_min_minus, \
 427        button_sec_plus, \
 428        button_sec_minus, \
 429        button_cancel, \
 430        button_save, \
 431        rtc, \
 432        edit_hour, \
 433        edit_min, \
 434        edit_sec
 435    event = event_struct.code
 436    if event == lv.EVENT.CLICKED and True:
 437        button_set_clicked_event(event_struct)
 438    return
 439
 440
 441def button_hour_plus_event_handler(event_struct):
 442    global \
 443        page_live, \
 444        page_edit, \
 445        label_title, \
 446        label_date, \
 447        label_live_hour, \
 448        label_live_colon_1, \
 449        label_live_min, \
 450        label_live_colon_2, \
 451        label_live_sec, \
 452        button_set, \
 453        label_edit_title, \
 454        label_hour_name, \
 455        label_min_name, \
 456        label_sec_name, \
 457        label_hour, \
 458        label_min, \
 459        label_sec, \
 460        button_hour_plus, \
 461        button_hour_minus, \
 462        button_min_plus, \
 463        button_min_minus, \
 464        button_sec_plus, \
 465        button_sec_minus, \
 466        button_cancel, \
 467        button_save, \
 468        rtc, \
 469        edit_hour, \
 470        edit_min, \
 471        edit_sec
 472    event = event_struct.code
 473    if event == lv.EVENT.CLICKED and True:
 474        button_hour_plus_clicked_event(event_struct)
 475    return
 476
 477
 478def button_hour_minus_event_handler(event_struct):
 479    global \
 480        page_live, \
 481        page_edit, \
 482        label_title, \
 483        label_date, \
 484        label_live_hour, \
 485        label_live_colon_1, \
 486        label_live_min, \
 487        label_live_colon_2, \
 488        label_live_sec, \
 489        button_set, \
 490        label_edit_title, \
 491        label_hour_name, \
 492        label_min_name, \
 493        label_sec_name, \
 494        label_hour, \
 495        label_min, \
 496        label_sec, \
 497        button_hour_plus, \
 498        button_hour_minus, \
 499        button_min_plus, \
 500        button_min_minus, \
 501        button_sec_plus, \
 502        button_sec_minus, \
 503        button_cancel, \
 504        button_save, \
 505        rtc, \
 506        edit_hour, \
 507        edit_min, \
 508        edit_sec
 509    event = event_struct.code
 510    if event == lv.EVENT.CLICKED and True:
 511        button_hour_minus_clicked_event(event_struct)
 512    return
 513
 514
 515def button_min_plus_event_handler(event_struct):
 516    global \
 517        page_live, \
 518        page_edit, \
 519        label_title, \
 520        label_date, \
 521        label_live_hour, \
 522        label_live_colon_1, \
 523        label_live_min, \
 524        label_live_colon_2, \
 525        label_live_sec, \
 526        button_set, \
 527        label_edit_title, \
 528        label_hour_name, \
 529        label_min_name, \
 530        label_sec_name, \
 531        label_hour, \
 532        label_min, \
 533        label_sec, \
 534        button_hour_plus, \
 535        button_hour_minus, \
 536        button_min_plus, \
 537        button_min_minus, \
 538        button_sec_plus, \
 539        button_sec_minus, \
 540        button_cancel, \
 541        button_save, \
 542        rtc, \
 543        edit_hour, \
 544        edit_min, \
 545        edit_sec
 546    event = event_struct.code
 547    if event == lv.EVENT.CLICKED and True:
 548        button_min_plus_clicked_event(event_struct)
 549    return
 550
 551
 552def button_min_minus_event_handler(event_struct):
 553    global \
 554        page_live, \
 555        page_edit, \
 556        label_title, \
 557        label_date, \
 558        label_live_hour, \
 559        label_live_colon_1, \
 560        label_live_min, \
 561        label_live_colon_2, \
 562        label_live_sec, \
 563        button_set, \
 564        label_edit_title, \
 565        label_hour_name, \
 566        label_min_name, \
 567        label_sec_name, \
 568        label_hour, \
 569        label_min, \
 570        label_sec, \
 571        button_hour_plus, \
 572        button_hour_minus, \
 573        button_min_plus, \
 574        button_min_minus, \
 575        button_sec_plus, \
 576        button_sec_minus, \
 577        button_cancel, \
 578        button_save, \
 579        rtc, \
 580        edit_hour, \
 581        edit_min, \
 582        edit_sec
 583    event = event_struct.code
 584    if event == lv.EVENT.CLICKED and True:
 585        button_min_minus_clicked_event(event_struct)
 586    return
 587
 588
 589def button_sec_plus_event_handler(event_struct):
 590    global \
 591        page_live, \
 592        page_edit, \
 593        label_title, \
 594        label_date, \
 595        label_live_hour, \
 596        label_live_colon_1, \
 597        label_live_min, \
 598        label_live_colon_2, \
 599        label_live_sec, \
 600        button_set, \
 601        label_edit_title, \
 602        label_hour_name, \
 603        label_min_name, \
 604        label_sec_name, \
 605        label_hour, \
 606        label_min, \
 607        label_sec, \
 608        button_hour_plus, \
 609        button_hour_minus, \
 610        button_min_plus, \
 611        button_min_minus, \
 612        button_sec_plus, \
 613        button_sec_minus, \
 614        button_cancel, \
 615        button_save, \
 616        rtc, \
 617        edit_hour, \
 618        edit_min, \
 619        edit_sec
 620    event = event_struct.code
 621    if event == lv.EVENT.CLICKED and True:
 622        button_sec_plus_clicked_event(event_struct)
 623    return
 624
 625
 626def button_sec_minus_event_handler(event_struct):
 627    global \
 628        page_live, \
 629        page_edit, \
 630        label_title, \
 631        label_date, \
 632        label_live_hour, \
 633        label_live_colon_1, \
 634        label_live_min, \
 635        label_live_colon_2, \
 636        label_live_sec, \
 637        button_set, \
 638        label_edit_title, \
 639        label_hour_name, \
 640        label_min_name, \
 641        label_sec_name, \
 642        label_hour, \
 643        label_min, \
 644        label_sec, \
 645        button_hour_plus, \
 646        button_hour_minus, \
 647        button_min_plus, \
 648        button_min_minus, \
 649        button_sec_plus, \
 650        button_sec_minus, \
 651        button_cancel, \
 652        button_save, \
 653        rtc, \
 654        edit_hour, \
 655        edit_min, \
 656        edit_sec
 657    event = event_struct.code
 658    if event == lv.EVENT.CLICKED and True:
 659        button_sec_minus_clicked_event(event_struct)
 660    return
 661
 662
 663def button_cancel_event_handler(event_struct):
 664    global \
 665        page_live, \
 666        page_edit, \
 667        label_title, \
 668        label_date, \
 669        label_live_hour, \
 670        label_live_colon_1, \
 671        label_live_min, \
 672        label_live_colon_2, \
 673        label_live_sec, \
 674        button_set, \
 675        label_edit_title, \
 676        label_hour_name, \
 677        label_min_name, \
 678        label_sec_name, \
 679        label_hour, \
 680        label_min, \
 681        label_sec, \
 682        button_hour_plus, \
 683        button_hour_minus, \
 684        button_min_plus, \
 685        button_min_minus, \
 686        button_sec_plus, \
 687        button_sec_minus, \
 688        button_cancel, \
 689        button_save, \
 690        rtc, \
 691        edit_hour, \
 692        edit_min, \
 693        edit_sec
 694    event = event_struct.code
 695    if event == lv.EVENT.CLICKED and True:
 696        button_cancel_clicked_event(event_struct)
 697    return
 698
 699
 700def button_save_event_handler(event_struct):
 701    global \
 702        page_live, \
 703        page_edit, \
 704        label_title, \
 705        label_date, \
 706        label_live_hour, \
 707        label_live_colon_1, \
 708        label_live_min, \
 709        label_live_colon_2, \
 710        label_live_sec, \
 711        button_set, \
 712        label_edit_title, \
 713        label_hour_name, \
 714        label_min_name, \
 715        label_sec_name, \
 716        label_hour, \
 717        label_min, \
 718        label_sec, \
 719        button_hour_plus, \
 720        button_hour_minus, \
 721        button_min_plus, \
 722        button_min_minus, \
 723        button_sec_plus, \
 724        button_sec_minus, \
 725        button_cancel, \
 726        button_save, \
 727        rtc, \
 728        edit_hour, \
 729        edit_min, \
 730        edit_sec
 731    event = event_struct.code
 732    if event == lv.EVENT.CLICKED and True:
 733        button_save_clicked_event(event_struct)
 734    return
 735
 736
 737def setup():
 738    global \
 739        page_live, \
 740        page_edit, \
 741        label_title, \
 742        label_date, \
 743        label_live_hour, \
 744        label_live_colon_1, \
 745        label_live_min, \
 746        label_live_colon_2, \
 747        label_live_sec, \
 748        button_set, \
 749        label_edit_title, \
 750        label_hour_name, \
 751        label_min_name, \
 752        label_sec_name, \
 753        label_hour, \
 754        label_min, \
 755        label_sec, \
 756        button_hour_plus, \
 757        button_hour_minus, \
 758        button_min_plus, \
 759        button_min_minus, \
 760        button_sec_plus, \
 761        button_sec_minus, \
 762        button_cancel, \
 763        button_save, \
 764        rtc, \
 765        edit_hour, \
 766        edit_min, \
 767        edit_sec
 768
 769    M5.begin()
 770    Widgets.setRotation(0)
 771    m5ui.init()
 772    page_live = m5ui.M5Page(bg_c=0x080808)
 773    page_edit = m5ui.M5Page(bg_c=0x080808)
 774    label_title = m5ui.M5Label(
 775        "RTC (UTC)",
 776        x=24,
 777        y=22,
 778        text_c=0xF1F5F7,
 779        bg_c=0x101820,
 780        bg_opa=0,
 781        font=lv.font_montserrat_24,
 782        parent=page_live,
 783    )
 784    label_date = m5ui.M5Label(
 785        "---- -- --",
 786        x=175,
 787        y=104,
 788        text_c=0xF1F5F7,
 789        bg_c=0x101820,
 790        bg_opa=0,
 791        font=lv.font_montserrat_24,
 792        parent=page_live,
 793    )
 794    label_live_hour = m5ui.M5Label(
 795        "--",
 796        x=105,
 797        y=160,
 798        text_c=0x4DA6FF,
 799        bg_c=0x101820,
 800        bg_opa=0,
 801        font=lv.font_montserrat_48,
 802        parent=page_live,
 803    )
 804    label_live_colon_1 = m5ui.M5Label(
 805        ":",
 806        x=175,
 807        y=156,
 808        text_c=0x4DA6FF,
 809        bg_c=0x101820,
 810        bg_opa=0,
 811        font=lv.font_montserrat_48,
 812        parent=page_live,
 813    )
 814    label_live_min = m5ui.M5Label(
 815        "--",
 816        x=205,
 817        y=160,
 818        text_c=0x4DA6FF,
 819        bg_c=0x101820,
 820        bg_opa=0,
 821        font=lv.font_montserrat_48,
 822        parent=page_live,
 823    )
 824    label_live_colon_2 = m5ui.M5Label(
 825        ":",
 826        x=275,
 827        y=156,
 828        text_c=0x4DA6FF,
 829        bg_c=0x101820,
 830        bg_opa=0,
 831        font=lv.font_montserrat_48,
 832        parent=page_live,
 833    )
 834    label_live_sec = m5ui.M5Label(
 835        "--",
 836        x=305,
 837        y=160,
 838        text_c=0x4DA6FF,
 839        bg_c=0x101820,
 840        bg_opa=0,
 841        font=lv.font_montserrat_48,
 842        parent=page_live,
 843    )
 844    button_set = m5ui.M5Button(
 845        text="SET TIME",
 846        x=32,
 847        y=368,
 848        bg_c=0x245A85,
 849        text_c=0xFFFFFF,
 850        font=lv.font_montserrat_18,
 851        parent=page_live,
 852    )
 853    label_edit_title = m5ui.M5Label(
 854        "Set UTC Time",
 855        x=158,
 856        y=22,
 857        text_c=0xF1F5F7,
 858        bg_c=0x101820,
 859        bg_opa=0,
 860        font=lv.font_montserrat_24,
 861        parent=page_edit,
 862    )
 863    label_hour_name = m5ui.M5Label(
 864        "HOUR",
 865        x=62,
 866        y=72,
 867        text_c=0xA9BAC4,
 868        bg_c=0x101820,
 869        bg_opa=0,
 870        font=lv.font_montserrat_18,
 871        parent=page_edit,
 872    )
 873    label_min_name = m5ui.M5Label(
 874        "MIN",
 875        x=212,
 876        y=72,
 877        text_c=0xA9BAC4,
 878        bg_c=0x101820,
 879        bg_opa=0,
 880        font=lv.font_montserrat_18,
 881        parent=page_edit,
 882    )
 883    label_sec_name = m5ui.M5Label(
 884        "SEC",
 885        x=362,
 886        y=72,
 887        text_c=0xA9BAC4,
 888        bg_c=0x101820,
 889        bg_opa=0,
 890        font=lv.font_montserrat_18,
 891        parent=page_edit,
 892    )
 893    label_hour = m5ui.M5Label(
 894        "00",
 895        x=56,
 896        y=190,
 897        text_c=0x4DA6FF,
 898        bg_c=0x101820,
 899        bg_opa=0,
 900        font=lv.font_montserrat_48,
 901        parent=page_edit,
 902    )
 903    label_min = m5ui.M5Label(
 904        "00",
 905        x=206,
 906        y=190,
 907        text_c=0x4DA6FF,
 908        bg_c=0x101820,
 909        bg_opa=0,
 910        font=lv.font_montserrat_48,
 911        parent=page_edit,
 912    )
 913    label_sec = m5ui.M5Label(
 914        "00",
 915        x=356,
 916        y=190,
 917        text_c=0x4DA6FF,
 918        bg_c=0x101820,
 919        bg_opa=0,
 920        font=lv.font_montserrat_48,
 921        parent=page_edit,
 922    )
 923    button_hour_plus = m5ui.M5Button(
 924        text="+",
 925        x=36,
 926        y=106,
 927        bg_c=0x176C48,
 928        text_c=0xFFFFFF,
 929        font=lv.font_montserrat_18,
 930        parent=page_edit,
 931    )
 932    button_hour_minus = m5ui.M5Button(
 933        text="-",
 934        x=36,
 935        y=270,
 936        bg_c=0x7A2731,
 937        text_c=0xFFFFFF,
 938        font=lv.font_montserrat_18,
 939        parent=page_edit,
 940    )
 941    button_min_plus = m5ui.M5Button(
 942        text="+",
 943        x=186,
 944        y=106,
 945        bg_c=0x176C48,
 946        text_c=0xFFFFFF,
 947        font=lv.font_montserrat_18,
 948        parent=page_edit,
 949    )
 950    button_min_minus = m5ui.M5Button(
 951        text="-",
 952        x=186,
 953        y=270,
 954        bg_c=0x7A2731,
 955        text_c=0xFFFFFF,
 956        font=lv.font_montserrat_18,
 957        parent=page_edit,
 958    )
 959    button_sec_plus = m5ui.M5Button(
 960        text="+",
 961        x=336,
 962        y=106,
 963        bg_c=0x176C48,
 964        text_c=0xFFFFFF,
 965        font=lv.font_montserrat_18,
 966        parent=page_edit,
 967    )
 968    button_sec_minus = m5ui.M5Button(
 969        text="-",
 970        x=336,
 971        y=270,
 972        bg_c=0x7A2731,
 973        text_c=0xFFFFFF,
 974        font=lv.font_montserrat_18,
 975        parent=page_edit,
 976    )
 977    button_cancel = m5ui.M5Button(
 978        text="CANCEL",
 979        x=32,
 980        y=368,
 981        bg_c=0x3B4850,
 982        text_c=0xFFFFFF,
 983        font=lv.font_montserrat_18,
 984        parent=page_edit,
 985    )
 986    button_save = m5ui.M5Button(
 987        text="SAVE",
 988        x=252,
 989        y=368,
 990        bg_c=0x245A85,
 991        text_c=0xFFFFFF,
 992        font=lv.font_montserrat_18,
 993        parent=page_edit,
 994    )
 995
 996    button_set.add_event_cb(button_set_event_handler, lv.EVENT.ALL, None)
 997    button_hour_plus.add_event_cb(button_hour_plus_event_handler, lv.EVENT.ALL, None)
 998    button_hour_minus.add_event_cb(button_hour_minus_event_handler, lv.EVENT.ALL, None)
 999    button_min_plus.add_event_cb(button_min_plus_event_handler, lv.EVENT.ALL, None)
1000    button_min_minus.add_event_cb(button_min_minus_event_handler, lv.EVENT.ALL, None)
1001    button_sec_plus.add_event_cb(button_sec_plus_event_handler, lv.EVENT.ALL, None)
1002    button_sec_minus.add_event_cb(button_sec_minus_event_handler, lv.EVENT.ALL, None)
1003    button_cancel.add_event_cb(button_cancel_event_handler, lv.EVENT.ALL, None)
1004    button_save.add_event_cb(button_save_event_handler, lv.EVENT.ALL, None)
1005
1006    page_live.screen_load()
1007    rtc = RTC()
1008    button_set.set_size(416, 72)
1009    button_hour_plus.set_size(108, 54)
1010    button_hour_minus.set_size(108, 54)
1011    button_min_plus.set_size(108, 54)
1012    button_min_minus.set_size(108, 54)
1013    button_sec_plus.set_size(108, 54)
1014    button_sec_minus.set_size(108, 54)
1015    button_cancel.set_size(196, 72)
1016    button_save.set_size(196, 72)
1017    label_date.align_to(page_live, lv.ALIGN.TOP_MID, 0, 104)
1018
1019
1020def loop():
1021    global \
1022        page_live, \
1023        page_edit, \
1024        label_title, \
1025        label_date, \
1026        label_live_hour, \
1027        label_live_colon_1, \
1028        label_live_min, \
1029        label_live_colon_2, \
1030        label_live_sec, \
1031        button_set, \
1032        label_edit_title, \
1033        label_hour_name, \
1034        label_min_name, \
1035        label_sec_name, \
1036        label_hour, \
1037        label_min, \
1038        label_sec, \
1039        button_hour_plus, \
1040        button_hour_minus, \
1041        button_min_plus, \
1042        button_min_minus, \
1043        button_sec_plus, \
1044        button_sec_minus, \
1045        button_cancel, \
1046        button_save, \
1047        rtc, \
1048        edit_hour, \
1049        edit_min, \
1050        edit_sec
1051    M5.update()
1052    label_date.set_text(
1053        str(
1054            (
1055                str(
1056                    (
1057                        str((str((str("") + str(((rtc.datetime())[0])))) + str("-")))
1058                        + str(((rtc.datetime())[1]))
1059                    )
1060                )
1061                + str((str("-") + str(((rtc.datetime())[2]))))
1062            )
1063        )
1064    )
1065    if (rtc.datetime())[4] < 10:
1066        label_live_hour.set_text(str((str("0") + str(((rtc.datetime())[4])))))
1067    else:
1068        label_live_hour.set_text(str((rtc.datetime())[4]))
1069    if (rtc.datetime())[5] < 10:
1070        label_live_min.set_text(str((str("0") + str(((rtc.datetime())[5])))))
1071    else:
1072        label_live_min.set_text(str((rtc.datetime())[5]))
1073    if (rtc.datetime())[6] < 10:
1074        label_live_sec.set_text(str((str("0") + str(((rtc.datetime())[6])))))
1075    else:
1076        label_live_sec.set_text(str((rtc.datetime())[6]))
1077    label_date.align_to(page_live, lv.ALIGN.TOP_MID, 0, 104)
1078    time.sleep_ms(100)
1079
1080
1081if __name__ == "__main__":
1082    try:
1083        setup()
1084        while True:
1085            loop()
1086    except (Exception, KeyboardInterrupt) as e:
1087        try:
1088            m5ui.deinit()
1089            from utility import print_error_msg
1090
1091            print_error_msg(e)
1092        except ImportError:
1093            print("please update to latest firmware")

示例输出:

无

IMU 传感器

显示内置加速度计和陀螺仪的 X、Y、Z 三轴读数。加速度单位为 g,角速度单位为度每秒(dps)。倾斜或旋转设备即可观察数值变化。

MicroPython 代码块:

  1# SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
  2#
  3# SPDX-License-Identifier: MIT
  4
  5import os, sys, io
  6import M5
  7from M5 import *
  8import m5ui
  9import lvgl as lv
 10import time
 11
 12
 13page0 = None
 14label_title = None
 15label_subtitle = None
 16label_acc_x = None
 17label_acc_y = None
 18label_acc_z = None
 19label_gyro_x = None
 20label_gyro_y = None
 21label_gyro_z = None
 22label_gyro_title = None
 23accel = None
 24gyro = None
 25acc_x = None
 26acc_y = None
 27acc_z = None
 28gyro_x = None
 29gyro_y = None
 30gyro_z = None
 31
 32
 33def setup():
 34    global \
 35        page0, \
 36        label_title, \
 37        label_subtitle, \
 38        label_acc_x, \
 39        label_acc_y, \
 40        label_acc_z, \
 41        label_gyro_x, \
 42        label_gyro_y, \
 43        label_gyro_z, \
 44        label_gyro_title, \
 45        accel, \
 46        gyro, \
 47        acc_x, \
 48        acc_y, \
 49        acc_z, \
 50        gyro_x, \
 51        gyro_y, \
 52        gyro_z
 53
 54    M5.begin()
 55    Widgets.setRotation(0)
 56    m5ui.init()
 57    page0 = m5ui.M5Page(bg_c=0x080808)
 58    label_title = m5ui.M5Label(
 59        "IMU",
 60        x=24,
 61        y=18,
 62        text_c=0xF1F5F7,
 63        bg_c=0x101820,
 64        bg_opa=0,
 65        font=lv.font_montserrat_24,
 66        parent=page0,
 67    )
 68    label_subtitle = m5ui.M5Label(
 69        "Accel (g)",
 70        x=199,
 71        y=82,
 72        text_c=0xA9BAC4,
 73        bg_c=0x101820,
 74        bg_opa=0,
 75        font=lv.font_montserrat_18,
 76        parent=page0,
 77    )
 78    label_acc_x = m5ui.M5Label(
 79        "X: -- g",
 80        x=48,
 81        y=116,
 82        text_c=0x45D483,
 83        bg_c=0x101820,
 84        bg_opa=0,
 85        font=lv.font_montserrat_24,
 86        parent=page0,
 87    )
 88    label_acc_y = m5ui.M5Label(
 89        "Y: -- g",
 90        x=48,
 91        y=156,
 92        text_c=0x45D483,
 93        bg_c=0x101820,
 94        bg_opa=0,
 95        font=lv.font_montserrat_24,
 96        parent=page0,
 97    )
 98    label_acc_z = m5ui.M5Label(
 99        "Z: -- g",
100        x=48,
101        y=196,
102        text_c=0x45D483,
103        bg_c=0x101820,
104        bg_opa=0,
105        font=lv.font_montserrat_24,
106        parent=page0,
107    )
108    label_gyro_x = m5ui.M5Label(
109        "X: -- dps",
110        x=48,
111        y=300,
112        text_c=0xFFD04D,
113        bg_c=0x101820,
114        bg_opa=0,
115        font=lv.font_montserrat_24,
116        parent=page0,
117    )
118    label_gyro_y = m5ui.M5Label(
119        "Y: -- dps",
120        x=48,
121        y=340,
122        text_c=0xFFD04D,
123        bg_c=0x101820,
124        bg_opa=0,
125        font=lv.font_montserrat_24,
126        parent=page0,
127    )
128    label_gyro_z = m5ui.M5Label(
129        "Z: -- dps",
130        x=48,
131        y=380,
132        text_c=0xFFD04D,
133        bg_c=0x101820,
134        bg_opa=0,
135        font=lv.font_montserrat_24,
136        parent=page0,
137    )
138    label_gyro_title = m5ui.M5Label(
139        "Gyro (dps)",
140        x=192,
141        y=266,
142        text_c=0xA9BAC4,
143        bg_c=0x101820,
144        bg_opa=0,
145        font=lv.font_montserrat_18,
146        parent=page0,
147    )
148
149    page0.screen_load()
150
151
152def loop():
153    global \
154        page0, \
155        label_title, \
156        label_subtitle, \
157        label_acc_x, \
158        label_acc_y, \
159        label_acc_z, \
160        label_gyro_x, \
161        label_gyro_y, \
162        label_gyro_z, \
163        label_gyro_title, \
164        accel, \
165        gyro, \
166        acc_x, \
167        acc_y, \
168        acc_z, \
169        gyro_x, \
170        gyro_y, \
171        gyro_z
172    M5.update()
173    accel = Imu.getAccel()
174    gyro = Imu.getGyro()
175    acc_x = accel[0]
176    acc_y = accel[1]
177    acc_z = accel[2]
178    gyro_x = gyro[0]
179    gyro_y = gyro[1]
180    gyro_z = gyro[2]
181    label_acc_x.set_text(str((str("X: ") + str((str(acc_x) + str(" g"))))))
182    label_acc_y.set_text(str((str("Y: ") + str((str(acc_y) + str(" g"))))))
183    label_acc_z.set_text(str((str("Z: ") + str((str(acc_z) + str(" g"))))))
184    label_gyro_x.set_text(str((str("X: ") + str((str(gyro_x) + str(" dps"))))))
185    label_gyro_y.set_text(str((str("Y: ") + str((str(gyro_y) + str(" dps"))))))
186    label_gyro_z.set_text(str((str("Z: ") + str((str(gyro_z) + str(" dps"))))))
187    time.sleep_ms(200)
188
189
190if __name__ == "__main__":
191    try:
192        setup()
193        while True:
194            loop()
195    except (Exception, KeyboardInterrupt) as e:
196        try:
197            m5ui.deinit()
198            from utility import print_error_msg
199
200            print_error_msg(e)
201        except ImportError:
202            print("please update to latest firmware")

示例输出:

无

电源管理

显示 USB VBUS 和电池电压(mV)、充电状态、Port A 5 V 输出状态和充电许可。实际充电时,电池电压显示为绿色。点击 PORT A 开关外部输出,点击 CHARGE 允许或禁止充电,不显示电量百分比。

MicroPython 代码块:

  1# SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
  2#
  3# SPDX-License-Identifier: MIT
  4
  5import os, sys, io
  6import M5
  7from M5 import *
  8import m5ui
  9import lvgl as lv
 10import time
 11
 12
 13page0 = None
 14label_title = None
 15label_vbus = None
 16label_battery = None
 17label_charging = None
 18label_port_a = None
 19label_charge_control = None
 20label_action = None
 21label_vbus_name = None
 22label_battery_name = None
 23label_charging_name = None
 24label_port_a_name = None
 25label_charge_control_name = None
 26button_port_a = None
 27button_charge = None
 28
 29
 30port_a_enabled = None
 31charge_enabled = None
 32
 33
 34def button_port_a_clicked_event(event_struct):
 35    global \
 36        page0, \
 37        label_title, \
 38        label_vbus, \
 39        label_battery, \
 40        label_charging, \
 41        label_port_a, \
 42        label_charge_control, \
 43        label_action, \
 44        label_vbus_name, \
 45        label_battery_name, \
 46        label_charging_name, \
 47        label_port_a_name, \
 48        label_charge_control_name, \
 49        button_port_a, \
 50        button_charge, \
 51        port_a_enabled, \
 52        charge_enabled
 53    port_a_enabled = not port_a_enabled
 54    if port_a_enabled:
 55        Power.setExtOutput(True, 1)
 56    else:
 57        Power.setExtOutput(False, 1)
 58    if port_a_enabled:
 59        button_port_a.set_btn_text(str("PORT A: ON"))
 60        label_port_a.set_text(str("ON"))
 61    else:
 62        button_port_a.set_btn_text(str("PORT A: OFF"))
 63        label_port_a.set_text(str("OFF"))
 64    label_action.set_text(str("Port A 5V updated"))
 65
 66
 67def button_charge_clicked_event(event_struct):
 68    global \
 69        page0, \
 70        label_title, \
 71        label_vbus, \
 72        label_battery, \
 73        label_charging, \
 74        label_port_a, \
 75        label_charge_control, \
 76        label_action, \
 77        label_vbus_name, \
 78        label_battery_name, \
 79        label_charging_name, \
 80        label_port_a_name, \
 81        label_charge_control_name, \
 82        button_port_a, \
 83        button_charge, \
 84        port_a_enabled, \
 85        charge_enabled
 86    charge_enabled = not charge_enabled
 87    if charge_enabled:
 88        Power.setBatteryCharge(True)
 89    else:
 90        Power.setBatteryCharge(False)
 91    if charge_enabled:
 92        button_charge.set_btn_text(str("CHARGE: ON"))
 93        label_charge_control.set_text(str("ON"))
 94    else:
 95        button_charge.set_btn_text(str("CHARGE: OFF"))
 96        label_charge_control.set_text(str("OFF"))
 97    label_action.set_text(str("Charge control updated"))
 98
 99
100def button_port_a_event_handler(event_struct):
101    global \
102        page0, \
103        label_title, \
104        label_vbus, \
105        label_battery, \
106        label_charging, \
107        label_port_a, \
108        label_charge_control, \
109        label_action, \
110        label_vbus_name, \
111        label_battery_name, \
112        label_charging_name, \
113        label_port_a_name, \
114        label_charge_control_name, \
115        button_port_a, \
116        button_charge, \
117        port_a_enabled, \
118        charge_enabled
119    event = event_struct.code
120    if event == lv.EVENT.CLICKED and True:
121        button_port_a_clicked_event(event_struct)
122    return
123
124
125def button_charge_event_handler(event_struct):
126    global \
127        page0, \
128        label_title, \
129        label_vbus, \
130        label_battery, \
131        label_charging, \
132        label_port_a, \
133        label_charge_control, \
134        label_action, \
135        label_vbus_name, \
136        label_battery_name, \
137        label_charging_name, \
138        label_port_a_name, \
139        label_charge_control_name, \
140        button_port_a, \
141        button_charge, \
142        port_a_enabled, \
143        charge_enabled
144    event = event_struct.code
145    if event == lv.EVENT.CLICKED and True:
146        button_charge_clicked_event(event_struct)
147    return
148
149
150def setup():
151    global \
152        page0, \
153        label_title, \
154        label_vbus, \
155        label_battery, \
156        label_charging, \
157        label_port_a, \
158        label_charge_control, \
159        label_action, \
160        label_vbus_name, \
161        label_battery_name, \
162        label_charging_name, \
163        label_port_a_name, \
164        label_charge_control_name, \
165        button_port_a, \
166        button_charge, \
167        port_a_enabled, \
168        charge_enabled
169
170    M5.begin()
171    Widgets.setRotation(0)
172    m5ui.init()
173    page0 = m5ui.M5Page(bg_c=0x080808)
174    label_title = m5ui.M5Label(
175        "Power",
176        x=24,
177        y=18,
178        text_c=0xF1F5F7,
179        bg_c=0x101820,
180        bg_opa=0,
181        font=lv.font_montserrat_24,
182        parent=page0,
183    )
184    label_vbus = m5ui.M5Label(
185        "---- mV",
186        x=284,
187        y=82,
188        text_c=0xF1F5F7,
189        bg_c=0x101820,
190        bg_opa=0,
191        font=lv.font_montserrat_18,
192        parent=page0,
193    )
194    label_battery = m5ui.M5Label(
195        "---- mV",
196        x=284,
197        y=124,
198        text_c=0xF1F5F7,
199        bg_c=0x101820,
200        bg_opa=0,
201        font=lv.font_montserrat_18,
202        parent=page0,
203    )
204    label_charging = m5ui.M5Label(
205        "--",
206        x=284,
207        y=166,
208        text_c=0xF1F5F7,
209        bg_c=0x101820,
210        bg_opa=0,
211        font=lv.font_montserrat_18,
212        parent=page0,
213    )
214    label_port_a = m5ui.M5Label(
215        "OFF",
216        x=284,
217        y=208,
218        text_c=0xF1F5F7,
219        bg_c=0x101820,
220        bg_opa=0,
221        font=lv.font_montserrat_18,
222        parent=page0,
223    )
224    label_charge_control = m5ui.M5Label(
225        "ON",
226        x=284,
227        y=250,
228        text_c=0xF1F5F7,
229        bg_c=0x101820,
230        bg_opa=0,
231        font=lv.font_montserrat_18,
232        parent=page0,
233    )
234    label_action = m5ui.M5Label(
235        "Power controls ready",
236        x=24,
237        y=342,
238        text_c=0xA9BAC4,
239        bg_c=0x101820,
240        bg_opa=0,
241        font=lv.font_montserrat_18,
242        parent=page0,
243    )
244    label_vbus_name = m5ui.M5Label(
245        "USB VBUS",
246        x=24,
247        y=82,
248        text_c=0xA9BAC4,
249        bg_c=0x101820,
250        bg_opa=0,
251        font=lv.font_montserrat_18,
252        parent=page0,
253    )
254    label_battery_name = m5ui.M5Label(
255        "Battery",
256        x=24,
257        y=124,
258        text_c=0xA9BAC4,
259        bg_c=0x101820,
260        bg_opa=0,
261        font=lv.font_montserrat_18,
262        parent=page0,
263    )
264    label_charging_name = m5ui.M5Label(
265        "Charging",
266        x=24,
267        y=166,
268        text_c=0xA9BAC4,
269        bg_c=0x101820,
270        bg_opa=0,
271        font=lv.font_montserrat_18,
272        parent=page0,
273    )
274    label_port_a_name = m5ui.M5Label(
275        "Port A 5 V",
276        x=24,
277        y=208,
278        text_c=0xA9BAC4,
279        bg_c=0x101820,
280        bg_opa=0,
281        font=lv.font_montserrat_18,
282        parent=page0,
283    )
284    label_charge_control_name = m5ui.M5Label(
285        "Charge control",
286        x=24,
287        y=250,
288        text_c=0xA9BAC4,
289        bg_c=0x101820,
290        bg_opa=0,
291        font=lv.font_montserrat_18,
292        parent=page0,
293    )
294    button_port_a = m5ui.M5Button(
295        text="PORT A: OFF",
296        x=24,
297        y=388,
298        bg_c=0x245A85,
299        text_c=0xF1F5F7,
300        font=lv.font_montserrat_18,
301        parent=page0,
302    )
303    button_charge = m5ui.M5Button(
304        text="CHARGE: ON",
305        x=252,
306        y=388,
307        bg_c=0x245A85,
308        text_c=0xF1F5F7,
309        font=lv.font_montserrat_18,
310        parent=page0,
311    )
312
313    button_port_a.add_event_cb(button_port_a_event_handler, lv.EVENT.ALL, None)
314    button_charge.add_event_cb(button_charge_event_handler, lv.EVENT.ALL, None)
315
316    page0.screen_load()
317    Power.setExtOutput(False, 1)
318    Power.setBatteryCharge(True)
319    port_a_enabled = False
320    charge_enabled = True
321    button_port_a.set_size(204, 64)
322    button_charge.set_size(204, 64)
323
324
325def loop():
326    global \
327        page0, \
328        label_title, \
329        label_vbus, \
330        label_battery, \
331        label_charging, \
332        label_port_a, \
333        label_charge_control, \
334        label_action, \
335        label_vbus_name, \
336        label_battery_name, \
337        label_charging_name, \
338        label_port_a_name, \
339        label_charge_control_name, \
340        button_port_a, \
341        button_charge, \
342        port_a_enabled, \
343        charge_enabled
344    M5.update()
345    label_vbus.set_text(str((str("") + str((str((Power.getVBUSVoltage())) + str(" mV"))))))
346    label_battery.set_text(str((str("") + str((str((Power.getBatteryVoltage())) + str(" mV"))))))
347    if Power.isCharging():
348        label_charging.set_text(str("YES"))
349        label_battery.set_text_color(0x8EDA91, 255, 0)
350    else:
351        label_charging.set_text(str("NO"))
352        label_battery.set_text_color(0xF1F5F7, 255, 0)
353    time.sleep_ms(500)
354
355
356if __name__ == "__main__":
357    try:
358        setup()
359        while True:
360            loop()
361    except (Exception, KeyboardInterrupt) as e:
362        try:
363            m5ui.deinit()
364            from utility import print_error_msg
365
366            print_error_msg(e)
367        except ImportError:
368            print("please update to latest firmware")

示例输出:

无

扬声器音调

使用独立滑条调节频率(200~4000 Hz)和音量(0~100%),默认值为 1000 Hz 和 70%。点击 Start tone 或 Stop tone 控制音调播放。PA 开关独立控制功放;启动时 PA 默认开启,音调默认停止。关闭 PA 仅关闭声音输出,不停止音调。

MicroPython 代码块:

  1# SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
  2#
  3# SPDX-License-Identifier: MIT
  4
  5import os, sys, io
  6import M5
  7from M5 import *
  8import m5ui
  9import lvgl as lv
 10import time
 11
 12
 13page0 = None
 14label_title = None
 15label_output = None
 16label_pa = None
 17pa_switch = None
 18label_frequency_title = None
 19label_frequency = None
 20frequency_slider = None
 21label_frequency_min = None
 22label_frequency_max = None
 23label_volume_title = None
 24label_volume = None
 25volume_slider = None
 26label_volume_min = None
 27label_volume_max = None
 28tone_button = None
 29
 30
 31pa_requested = None
 32frequency = None
 33tone_toggle_pending = None
 34volume = None
 35pa_change_pending = None
 36frequency_change_pending = None
 37volume_change_pending = None
 38tone_enabled = None
 39pa_enabled = None
 40
 41
 42def pa_switch_checked_event(event_struct):
 43    global \
 44        page0, \
 45        label_title, \
 46        label_output, \
 47        label_pa, \
 48        pa_switch, \
 49        label_frequency_title, \
 50        label_frequency, \
 51        frequency_slider, \
 52        label_frequency_min, \
 53        label_frequency_max, \
 54        label_volume_title, \
 55        label_volume, \
 56        volume_slider, \
 57        label_volume_min, \
 58        label_volume_max, \
 59        tone_button, \
 60        pa_requested, \
 61        frequency, \
 62        tone_toggle_pending, \
 63        volume, \
 64        pa_change_pending, \
 65        frequency_change_pending, \
 66        volume_change_pending, \
 67        tone_enabled, \
 68        pa_enabled
 69    pa_requested = pa_switch.has_state(lv.STATE.CHECKED)
 70    pa_change_pending = True
 71
 72
 73def pa_switch_unchecked_event(event_struct):
 74    global \
 75        page0, \
 76        label_title, \
 77        label_output, \
 78        label_pa, \
 79        pa_switch, \
 80        label_frequency_title, \
 81        label_frequency, \
 82        frequency_slider, \
 83        label_frequency_min, \
 84        label_frequency_max, \
 85        label_volume_title, \
 86        label_volume, \
 87        volume_slider, \
 88        label_volume_min, \
 89        label_volume_max, \
 90        tone_button, \
 91        pa_requested, \
 92        frequency, \
 93        tone_toggle_pending, \
 94        volume, \
 95        pa_change_pending, \
 96        frequency_change_pending, \
 97        volume_change_pending, \
 98        tone_enabled, \
 99        pa_enabled
100    pa_requested = pa_switch.has_state(lv.STATE.CHECKED)
101    pa_change_pending = True
102
103
104def frequency_slider_value_changed_event(event_struct):
105    global \
106        page0, \
107        label_title, \
108        label_output, \
109        label_pa, \
110        pa_switch, \
111        label_frequency_title, \
112        label_frequency, \
113        frequency_slider, \
114        label_frequency_min, \
115        label_frequency_max, \
116        label_volume_title, \
117        label_volume, \
118        volume_slider, \
119        label_volume_min, \
120        label_volume_max, \
121        tone_button, \
122        pa_requested, \
123        frequency, \
124        tone_toggle_pending, \
125        volume, \
126        pa_change_pending, \
127        frequency_change_pending, \
128        volume_change_pending, \
129        tone_enabled, \
130        pa_enabled
131    frequency = frequency_slider.get_value()
132    label_frequency.set_text(str((str(frequency) + str(" Hz"))))
133    label_frequency.align_to(page0, lv.ALIGN.TOP_RIGHT, -24, 152)
134    frequency_change_pending = True
135
136
137def tone_button_clicked_event(event_struct):
138    global \
139        page0, \
140        label_title, \
141        label_output, \
142        label_pa, \
143        pa_switch, \
144        label_frequency_title, \
145        label_frequency, \
146        frequency_slider, \
147        label_frequency_min, \
148        label_frequency_max, \
149        label_volume_title, \
150        label_volume, \
151        volume_slider, \
152        label_volume_min, \
153        label_volume_max, \
154        tone_button, \
155        pa_requested, \
156        frequency, \
157        tone_toggle_pending, \
158        volume, \
159        pa_change_pending, \
160        frequency_change_pending, \
161        volume_change_pending, \
162        tone_enabled, \
163        pa_enabled
164    tone_toggle_pending = True
165
166
167def volume_slider_value_changed_event(event_struct):
168    global \
169        page0, \
170        label_title, \
171        label_output, \
172        label_pa, \
173        pa_switch, \
174        label_frequency_title, \
175        label_frequency, \
176        frequency_slider, \
177        label_frequency_min, \
178        label_frequency_max, \
179        label_volume_title, \
180        label_volume, \
181        volume_slider, \
182        label_volume_min, \
183        label_volume_max, \
184        tone_button, \
185        pa_requested, \
186        frequency, \
187        tone_toggle_pending, \
188        volume, \
189        pa_change_pending, \
190        frequency_change_pending, \
191        volume_change_pending, \
192        tone_enabled, \
193        pa_enabled
194    volume = volume_slider.get_value()
195    label_volume.set_text(str((str(volume) + str("%"))))
196    label_volume.align_to(page0, lv.ALIGN.TOP_RIGHT, -24, 272)
197    volume_change_pending = True
198
199
200def pa_switch_event_handler(event_struct):
201    global \
202        page0, \
203        label_title, \
204        label_output, \
205        label_pa, \
206        pa_switch, \
207        label_frequency_title, \
208        label_frequency, \
209        frequency_slider, \
210        label_frequency_min, \
211        label_frequency_max, \
212        label_volume_title, \
213        label_volume, \
214        volume_slider, \
215        label_volume_min, \
216        label_volume_max, \
217        tone_button, \
218        pa_requested, \
219        frequency, \
220        tone_toggle_pending, \
221        volume, \
222        pa_change_pending, \
223        frequency_change_pending, \
224        volume_change_pending, \
225        tone_enabled, \
226        pa_enabled
227    event = event_struct.code
228    obj = event_struct.get_target_obj()
229    if event == lv.EVENT.VALUE_CHANGED:
230        if obj.has_state(lv.STATE.CHECKED):
231            pa_switch_checked_event(event_struct)
232        else:
233            pa_switch_unchecked_event(event_struct)
234    return
235
236
237def frequency_slider_event_handler(event_struct):
238    global \
239        page0, \
240        label_title, \
241        label_output, \
242        label_pa, \
243        pa_switch, \
244        label_frequency_title, \
245        label_frequency, \
246        frequency_slider, \
247        label_frequency_min, \
248        label_frequency_max, \
249        label_volume_title, \
250        label_volume, \
251        volume_slider, \
252        label_volume_min, \
253        label_volume_max, \
254        tone_button, \
255        pa_requested, \
256        frequency, \
257        tone_toggle_pending, \
258        volume, \
259        pa_change_pending, \
260        frequency_change_pending, \
261        volume_change_pending, \
262        tone_enabled, \
263        pa_enabled
264    event = event_struct.code
265    if event == lv.EVENT.VALUE_CHANGED and True:
266        frequency_slider_value_changed_event(event_struct)
267    return
268
269
270def tone_button_event_handler(event_struct):
271    global \
272        page0, \
273        label_title, \
274        label_output, \
275        label_pa, \
276        pa_switch, \
277        label_frequency_title, \
278        label_frequency, \
279        frequency_slider, \
280        label_frequency_min, \
281        label_frequency_max, \
282        label_volume_title, \
283        label_volume, \
284        volume_slider, \
285        label_volume_min, \
286        label_volume_max, \
287        tone_button, \
288        pa_requested, \
289        frequency, \
290        tone_toggle_pending, \
291        volume, \
292        pa_change_pending, \
293        frequency_change_pending, \
294        volume_change_pending, \
295        tone_enabled, \
296        pa_enabled
297    event = event_struct.code
298    if event == lv.EVENT.CLICKED and True:
299        tone_button_clicked_event(event_struct)
300    return
301
302
303def volume_slider_event_handler(event_struct):
304    global \
305        page0, \
306        label_title, \
307        label_output, \
308        label_pa, \
309        pa_switch, \
310        label_frequency_title, \
311        label_frequency, \
312        frequency_slider, \
313        label_frequency_min, \
314        label_frequency_max, \
315        label_volume_title, \
316        label_volume, \
317        volume_slider, \
318        label_volume_min, \
319        label_volume_max, \
320        tone_button, \
321        pa_requested, \
322        frequency, \
323        tone_toggle_pending, \
324        volume, \
325        pa_change_pending, \
326        frequency_change_pending, \
327        volume_change_pending, \
328        tone_enabled, \
329        pa_enabled
330    event = event_struct.code
331    if event == lv.EVENT.VALUE_CHANGED and True:
332        volume_slider_value_changed_event(event_struct)
333    return
334
335
336def setup():
337    global \
338        page0, \
339        label_title, \
340        label_output, \
341        label_pa, \
342        pa_switch, \
343        label_frequency_title, \
344        label_frequency, \
345        frequency_slider, \
346        label_frequency_min, \
347        label_frequency_max, \
348        label_volume_title, \
349        label_volume, \
350        volume_slider, \
351        label_volume_min, \
352        label_volume_max, \
353        tone_button, \
354        pa_requested, \
355        frequency, \
356        tone_toggle_pending, \
357        volume, \
358        pa_change_pending, \
359        frequency_change_pending, \
360        volume_change_pending, \
361        tone_enabled, \
362        pa_enabled
363
364    M5.begin()
365    Widgets.setRotation(0)
366    m5ui.init()
367    page0 = m5ui.M5Page(bg_c=0x080808)
368    label_title = m5ui.M5Label(
369        "Speaker",
370        x=24,
371        y=24,
372        text_c=0xF4F4F5,
373        bg_c=0x080808,
374        bg_opa=0,
375        font=lv.font_montserrat_24,
376        parent=page0,
377    )
378    label_output = m5ui.M5Label(
379        "Stopped",
380        x=384,
381        y=28,
382        text_c=0x9A9A9F,
383        bg_c=0x080808,
384        bg_opa=0,
385        font=lv.font_montserrat_18,
386        parent=page0,
387    )
388    label_pa = m5ui.M5Label(
389        "Amplifier on",
390        x=24,
391        y=96,
392        text_c=0x8EDA91,
393        bg_c=0x080808,
394        bg_opa=0,
395        font=lv.font_montserrat_18,
396        parent=page0,
397    )
398    pa_switch = m5ui.M5Switch(
399        x=384,
400        y=84,
401        w=72,
402        h=40,
403        bg_c=0x38383C,
404        bg_c_checked=0x8EDA91,
405        circle_c=0xF4F4F5,
406        parent=page0,
407    )
408    label_frequency_title = m5ui.M5Label(
409        "Frequency",
410        x=24,
411        y=158,
412        text_c=0x9A9A9F,
413        bg_c=0x080808,
414        bg_opa=0,
415        font=lv.font_montserrat_18,
416        parent=page0,
417    )
418    label_frequency = m5ui.M5Label(
419        "1000 Hz",
420        x=320,
421        y=152,
422        text_c=0xF4F4F5,
423        bg_c=0x080808,
424        bg_opa=0,
425        font=lv.font_montserrat_24,
426        parent=page0,
427    )
428    frequency_slider = m5ui.M5Slider(
429        x=40,
430        y=206,
431        w=400,
432        h=16,
433        mode=lv.slider.MODE.NORMAL,
434        min_value=200,
435        max_value=4000,
436        value=1000,
437        bg_c=0x38383C,
438        color=0x4DA6FF,
439        parent=page0,
440    )
441    label_frequency_min = m5ui.M5Label(
442        "200",
443        x=40,
444        y=232,
445        text_c=0x9A9A9F,
446        bg_c=0x080808,
447        bg_opa=0,
448        font=lv.font_montserrat_18,
449        parent=page0,
450    )
451    label_frequency_max = m5ui.M5Label(
452        "4000",
453        x=384,
454        y=232,
455        text_c=0x9A9A9F,
456        bg_c=0x080808,
457        bg_opa=0,
458        font=lv.font_montserrat_18,
459        parent=page0,
460    )
461    label_volume_title = m5ui.M5Label(
462        "Volume",
463        x=24,
464        y=278,
465        text_c=0x9A9A9F,
466        bg_c=0x080808,
467        bg_opa=0,
468        font=lv.font_montserrat_18,
469        parent=page0,
470    )
471    label_volume = m5ui.M5Label(
472        "70%",
473        x=320,
474        y=272,
475        text_c=0xF4F4F5,
476        bg_c=0x080808,
477        bg_opa=0,
478        font=lv.font_montserrat_24,
479        parent=page0,
480    )
481    volume_slider = m5ui.M5Slider(
482        x=40,
483        y=326,
484        w=400,
485        h=16,
486        mode=lv.slider.MODE.NORMAL,
487        min_value=0,
488        max_value=100,
489        value=70,
490        bg_c=0x38383C,
491        color=0x4DA6FF,
492        parent=page0,
493    )
494    label_volume_min = m5ui.M5Label(
495        "0",
496        x=40,
497        y=352,
498        text_c=0x9A9A9F,
499        bg_c=0x080808,
500        bg_opa=0,
501        font=lv.font_montserrat_18,
502        parent=page0,
503    )
504    label_volume_max = m5ui.M5Label(
505        "100%",
506        x=384,
507        y=352,
508        text_c=0x9A9A9F,
509        bg_c=0x080808,
510        bg_opa=0,
511        font=lv.font_montserrat_18,
512        parent=page0,
513    )
514    tone_button = m5ui.M5Button(
515        text="Start tone",
516        x=24,
517        y=388,
518        bg_c=0x245A85,
519        text_c=0xF4F4F5,
520        font=lv.font_montserrat_18,
521        parent=page0,
522    )
523
524    pa_switch.add_event_cb(pa_switch_event_handler, lv.EVENT.ALL, None)
525    frequency_slider.add_event_cb(frequency_slider_event_handler, lv.EVENT.ALL, None)
526    tone_button.add_event_cb(tone_button_event_handler, lv.EVENT.ALL, None)
527    volume_slider.add_event_cb(volume_slider_event_handler, lv.EVENT.ALL, None)
528
529    page0.screen_load()
530    Speaker.stop()
531    frequency = 1000
532    frequency_change_pending = False
533    pa_requested = True
534    pa_change_pending = False
535    Speaker.setPA(True)
536    pa_enabled = True
537    tone_toggle_pending = False
538    tone_enabled = False
539    volume = 70
540    volume_change_pending = False
541    pa_requested = pa_enabled
542    pa_switch.set_state(lv.STATE.CHECKED, pa_enabled)
543    Speaker.setVolume(int((volume * 255 + 50) / 100))
544    if pa_enabled:
545        label_pa.set_text(str("Amplifier on"))
546        label_pa.set_text_color(0x8EDA91, 255, 0)
547    else:
548        label_pa.set_text(str("Amplifier off"))
549        label_pa.set_text_color(0x9A9A9F, 255, 0)
550    if tone_enabled and (Speaker.isPlaying()):
551        label_output.set_text(str("Playing"))
552        label_output.align_to(page0, lv.ALIGN.TOP_RIGHT, -24, 28)
553        label_output.set_text_color(0x8EDA91, 255, 0)
554    else:
555        label_output.set_text(str("Stopped"))
556        label_output.align_to(page0, lv.ALIGN.TOP_RIGHT, -24, 28)
557        label_output.set_text_color(0x9A9A9F, 255, 0)
558    if tone_enabled:
559        tone_button.set_btn_text(str("Stop tone"))
560        tone_button.set_bg_color(0x8EDA91, 255, lv.PART.MAIN | lv.STATE.DEFAULT)
561        tone_button.set_text_color(0x000000, 255, lv.PART.MAIN | lv.STATE.DEFAULT)
562    else:
563        tone_button.set_btn_text(str("Start tone"))
564        tone_button.set_bg_color(0x245A85, 255, lv.PART.MAIN | lv.STATE.DEFAULT)
565        tone_button.set_text_color(0xF4F4F5, 255, lv.PART.MAIN | lv.STATE.DEFAULT)
566    tone_button.set_size(432, 64)
567    label_frequency.align_to(page0, lv.ALIGN.TOP_RIGHT, -24, 152)
568    label_volume.align_to(page0, lv.ALIGN.TOP_RIGHT, -24, 272)
569    label_frequency_max.align_to(page0, lv.ALIGN.TOP_RIGHT, -40, 232)
570    label_volume_max.align_to(page0, lv.ALIGN.TOP_RIGHT, -40, 352)
571    frequency_slider.set_bg_color(0x4DA6FF, 255, lv.PART.KNOB | lv.STATE.DEFAULT)
572    volume_slider.set_bg_color(0x4DA6FF, 255, lv.PART.KNOB | lv.STATE.DEFAULT)
573    frequency_slider.set_bg_color(0x38383C, 255, lv.PART.MAIN | lv.STATE.DEFAULT)
574    volume_slider.set_bg_color(0x38383C, 255, lv.PART.MAIN | lv.STATE.DEFAULT)
575
576
577def loop():
578    global \
579        page0, \
580        label_title, \
581        label_output, \
582        label_pa, \
583        pa_switch, \
584        label_frequency_title, \
585        label_frequency, \
586        frequency_slider, \
587        label_frequency_min, \
588        label_frequency_max, \
589        label_volume_title, \
590        label_volume, \
591        volume_slider, \
592        label_volume_min, \
593        label_volume_max, \
594        tone_button, \
595        pa_requested, \
596        frequency, \
597        tone_toggle_pending, \
598        volume, \
599        pa_change_pending, \
600        frequency_change_pending, \
601        volume_change_pending, \
602        tone_enabled, \
603        pa_enabled
604    M5.update()
605    if pa_change_pending:
606        pa_change_pending = False
607        if pa_requested:
608            Speaker.setPA(True)
609            pa_enabled = True
610        else:
611            Speaker.setPA(False)
612            pa_enabled = False
613        if pa_enabled:
614            label_pa.set_text(str("Amplifier on"))
615            label_pa.set_text_color(0x8EDA91, 255, 0)
616        else:
617            label_pa.set_text(str("Amplifier off"))
618            label_pa.set_text_color(0x9A9A9F, 255, 0)
619        if tone_enabled and (Speaker.isPlaying()):
620            label_output.set_text(str("Playing"))
621            label_output.align_to(page0, lv.ALIGN.TOP_RIGHT, -24, 28)
622            label_output.set_text_color(0x8EDA91, 255, 0)
623        else:
624            label_output.set_text(str("Stopped"))
625            label_output.align_to(page0, lv.ALIGN.TOP_RIGHT, -24, 28)
626            label_output.set_text_color(0x9A9A9F, 255, 0)
627        if tone_enabled:
628            tone_button.set_btn_text(str("Stop tone"))
629            tone_button.set_bg_color(0x8EDA91, 255, lv.PART.MAIN | lv.STATE.DEFAULT)
630            tone_button.set_text_color(0x000000, 255, lv.PART.MAIN | lv.STATE.DEFAULT)
631        else:
632            tone_button.set_btn_text(str("Start tone"))
633            tone_button.set_bg_color(0x245A85, 255, lv.PART.MAIN | lv.STATE.DEFAULT)
634            tone_button.set_text_color(0xF4F4F5, 255, lv.PART.MAIN | lv.STATE.DEFAULT)
635    if tone_toggle_pending:
636        tone_toggle_pending = False
637        tone_enabled = not tone_enabled
638        if tone_enabled:
639            Speaker.tone(frequency, 60000)
640        else:
641            Speaker.stop()
642        if pa_enabled:
643            label_pa.set_text(str("Amplifier on"))
644            label_pa.set_text_color(0x8EDA91, 255, 0)
645        else:
646            label_pa.set_text(str("Amplifier off"))
647            label_pa.set_text_color(0x9A9A9F, 255, 0)
648        if tone_enabled and (Speaker.isPlaying()):
649            label_output.set_text(str("Playing"))
650            label_output.align_to(page0, lv.ALIGN.TOP_RIGHT, -24, 28)
651            label_output.set_text_color(0x8EDA91, 255, 0)
652        else:
653            label_output.set_text(str("Stopped"))
654            label_output.align_to(page0, lv.ALIGN.TOP_RIGHT, -24, 28)
655            label_output.set_text_color(0x9A9A9F, 255, 0)
656        if tone_enabled:
657            tone_button.set_btn_text(str("Stop tone"))
658            tone_button.set_bg_color(0x8EDA91, 255, lv.PART.MAIN | lv.STATE.DEFAULT)
659            tone_button.set_text_color(0x000000, 255, lv.PART.MAIN | lv.STATE.DEFAULT)
660        else:
661            tone_button.set_btn_text(str("Start tone"))
662            tone_button.set_bg_color(0x245A85, 255, lv.PART.MAIN | lv.STATE.DEFAULT)
663            tone_button.set_text_color(0xF4F4F5, 255, lv.PART.MAIN | lv.STATE.DEFAULT)
664    if frequency_change_pending:
665        frequency_change_pending = False
666        if tone_enabled:
667            Speaker.stop()
668            Speaker.tone(frequency, 60000)
669        if pa_enabled:
670            label_pa.set_text(str("Amplifier on"))
671            label_pa.set_text_color(0x8EDA91, 255, 0)
672        else:
673            label_pa.set_text(str("Amplifier off"))
674            label_pa.set_text_color(0x9A9A9F, 255, 0)
675        if tone_enabled and (Speaker.isPlaying()):
676            label_output.set_text(str("Playing"))
677            label_output.align_to(page0, lv.ALIGN.TOP_RIGHT, -24, 28)
678            label_output.set_text_color(0x8EDA91, 255, 0)
679        else:
680            label_output.set_text(str("Stopped"))
681            label_output.align_to(page0, lv.ALIGN.TOP_RIGHT, -24, 28)
682            label_output.set_text_color(0x9A9A9F, 255, 0)
683        if tone_enabled:
684            tone_button.set_btn_text(str("Stop tone"))
685            tone_button.set_bg_color(0x8EDA91, 255, lv.PART.MAIN | lv.STATE.DEFAULT)
686            tone_button.set_text_color(0x000000, 255, lv.PART.MAIN | lv.STATE.DEFAULT)
687        else:
688            tone_button.set_btn_text(str("Start tone"))
689            tone_button.set_bg_color(0x245A85, 255, lv.PART.MAIN | lv.STATE.DEFAULT)
690            tone_button.set_text_color(0xF4F4F5, 255, lv.PART.MAIN | lv.STATE.DEFAULT)
691    if tone_enabled and not (Speaker.isPlaying()):
692        Speaker.tone(frequency, 60000)
693    time.sleep_ms(10)
694    if volume_change_pending:
695        volume_change_pending = False
696        Speaker.setVolume(int((volume * 255 + 50) / 100))
697
698
699if __name__ == "__main__":
700    try:
701        setup()
702        while True:
703            loop()
704    except (Exception, KeyboardInterrupt) as e:
705        try:
706            m5ui.deinit()
707            from utility import print_error_msg
708
709            print_error_msg(e)
710        except ImportError:
711            print("please update to latest firmware")

示例输出:

无

录音与播放

以 8 kHz、单声道、16 bit 将音频录入内存。点击 RECORD 开始录音,点击 STOP REC 结束,最长录制 30 秒。点击 PLAY 回放录音,点击 STOP PLAY 停止播放。音量滑条范围为 0~100%,默认 70%;播放时自动开启 PA。

MicroPython 代码块:

  1# SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
  2#
  3# SPDX-License-Identifier: MIT
  4
  5import os, sys, io
  6import M5
  7from M5 import *
  8import m5ui
  9import lvgl as lv
 10import time
 11
 12
 13page0 = None
 14label_title = None
 15label_state = None
 16label_duration = None
 17label_message = None
 18label_volume_name = None
 19label_volume = None
 20volume_slider = None
 21record_button = None
 22play_button = None
 23
 24
 25record_pending = None
 26play_pending = None
 27volume = None
 28volume_pending = None
 29stop_requested = None
 30record_buffer = None
 31state = None
 32queued_chunks = None
 33next_is_a = None
 34recorded_bytes = None
 35buffer_a = None
 36buffer_b = None
 37record_start = None
 38speaker_ready = None
 39play_started = None
 40
 41
 42def record_button_clicked_event(event_struct):
 43    global \
 44        page0, \
 45        label_title, \
 46        label_state, \
 47        label_duration, \
 48        label_message, \
 49        label_volume_name, \
 50        label_volume, \
 51        volume_slider, \
 52        record_button, \
 53        play_button, \
 54        record_pending, \
 55        play_pending, \
 56        volume, \
 57        volume_pending, \
 58        stop_requested, \
 59        record_buffer, \
 60        state, \
 61        queued_chunks, \
 62        next_is_a, \
 63        recorded_bytes, \
 64        buffer_a, \
 65        buffer_b, \
 66        record_start, \
 67        speaker_ready, \
 68        play_started
 69    record_pending = True
 70
 71
 72def play_button_clicked_event(event_struct):
 73    global \
 74        page0, \
 75        label_title, \
 76        label_state, \
 77        label_duration, \
 78        label_message, \
 79        label_volume_name, \
 80        label_volume, \
 81        volume_slider, \
 82        record_button, \
 83        play_button, \
 84        record_pending, \
 85        play_pending, \
 86        volume, \
 87        volume_pending, \
 88        stop_requested, \
 89        record_buffer, \
 90        state, \
 91        queued_chunks, \
 92        next_is_a, \
 93        recorded_bytes, \
 94        buffer_a, \
 95        buffer_b, \
 96        record_start, \
 97        speaker_ready, \
 98        play_started
 99    play_pending = True
100
101
102def volume_slider_value_changed_event(event_struct):
103    global \
104        page0, \
105        label_title, \
106        label_state, \
107        label_duration, \
108        label_message, \
109        label_volume_name, \
110        label_volume, \
111        volume_slider, \
112        record_button, \
113        play_button, \
114        record_pending, \
115        play_pending, \
116        volume, \
117        volume_pending, \
118        stop_requested, \
119        record_buffer, \
120        state, \
121        queued_chunks, \
122        next_is_a, \
123        recorded_bytes, \
124        buffer_a, \
125        buffer_b, \
126        record_start, \
127        speaker_ready, \
128        play_started
129    volume = volume_slider.get_value()
130    label_volume.set_text(str((str(volume) + str("%"))))
131    volume_pending = True
132
133
134def record_button_event_handler(event_struct):
135    global \
136        page0, \
137        label_title, \
138        label_state, \
139        label_duration, \
140        label_message, \
141        label_volume_name, \
142        label_volume, \
143        volume_slider, \
144        record_button, \
145        play_button, \
146        record_pending, \
147        play_pending, \
148        volume, \
149        volume_pending, \
150        stop_requested, \
151        record_buffer, \
152        state, \
153        queued_chunks, \
154        next_is_a, \
155        recorded_bytes, \
156        buffer_a, \
157        buffer_b, \
158        record_start, \
159        speaker_ready, \
160        play_started
161    event = event_struct.code
162    if event == lv.EVENT.CLICKED and True:
163        record_button_clicked_event(event_struct)
164    return
165
166
167def play_button_event_handler(event_struct):
168    global \
169        page0, \
170        label_title, \
171        label_state, \
172        label_duration, \
173        label_message, \
174        label_volume_name, \
175        label_volume, \
176        volume_slider, \
177        record_button, \
178        play_button, \
179        record_pending, \
180        play_pending, \
181        volume, \
182        volume_pending, \
183        stop_requested, \
184        record_buffer, \
185        state, \
186        queued_chunks, \
187        next_is_a, \
188        recorded_bytes, \
189        buffer_a, \
190        buffer_b, \
191        record_start, \
192        speaker_ready, \
193        play_started
194    event = event_struct.code
195    if event == lv.EVENT.CLICKED and True:
196        play_button_clicked_event(event_struct)
197    return
198
199
200def volume_slider_event_handler(event_struct):
201    global \
202        page0, \
203        label_title, \
204        label_state, \
205        label_duration, \
206        label_message, \
207        label_volume_name, \
208        label_volume, \
209        volume_slider, \
210        record_button, \
211        play_button, \
212        record_pending, \
213        play_pending, \
214        volume, \
215        volume_pending, \
216        stop_requested, \
217        record_buffer, \
218        state, \
219        queued_chunks, \
220        next_is_a, \
221        recorded_bytes, \
222        buffer_a, \
223        buffer_b, \
224        record_start, \
225        speaker_ready, \
226        play_started
227    event = event_struct.code
228    if event == lv.EVENT.VALUE_CHANGED and True:
229        volume_slider_value_changed_event(event_struct)
230    return
231
232
233def setup():
234    global \
235        page0, \
236        label_title, \
237        label_state, \
238        label_duration, \
239        label_message, \
240        label_volume_name, \
241        label_volume, \
242        volume_slider, \
243        record_button, \
244        play_button, \
245        record_pending, \
246        play_pending, \
247        volume, \
248        volume_pending, \
249        stop_requested, \
250        record_buffer, \
251        state, \
252        queued_chunks, \
253        next_is_a, \
254        recorded_bytes, \
255        buffer_a, \
256        buffer_b, \
257        record_start, \
258        speaker_ready, \
259        play_started
260
261    M5.begin()
262    Widgets.setRotation(0)
263    m5ui.init()
264    page0 = m5ui.M5Page(bg_c=0x080808)
265    label_title = m5ui.M5Label(
266        "Audio",
267        x=24,
268        y=24,
269        text_c=0xF4F4F5,
270        bg_c=0x080808,
271        bg_opa=0,
272        font=lv.font_montserrat_24,
273        parent=page0,
274    )
275    label_state = m5ui.M5Label(
276        "IDLE",
277        x=48,
278        y=90,
279        text_c=0xF4F4F5,
280        bg_c=0x080808,
281        bg_opa=0,
282        font=lv.font_montserrat_48,
283        parent=page0,
284    )
285    label_duration = m5ui.M5Label(
286        "0.0 / 30 s",
287        x=48,
288        y=170,
289        text_c=0x9A9A9F,
290        bg_c=0x080808,
291        bg_opa=0,
292        font=lv.font_montserrat_24,
293        parent=page0,
294    )
295    label_message = m5ui.M5Label(
296        "Tap RECORD to start",
297        x=48,
298        y=227,
299        text_c=0x9A9A9F,
300        bg_c=0x080808,
301        bg_opa=0,
302        font=lv.font_montserrat_18,
303        parent=page0,
304    )
305    label_volume_name = m5ui.M5Label(
306        "Volume",
307        x=24,
308        y=280,
309        text_c=0x9A9A9F,
310        bg_c=0x080808,
311        bg_opa=0,
312        font=lv.font_montserrat_18,
313        parent=page0,
314    )
315    label_volume = m5ui.M5Label(
316        "70%",
317        x=384,
318        y=280,
319        text_c=0xF4F4F5,
320        bg_c=0x080808,
321        bg_opa=0,
322        font=lv.font_montserrat_24,
323        parent=page0,
324    )
325    volume_slider = m5ui.M5Slider(
326        x=40,
327        y=335,
328        w=400,
329        h=16,
330        mode=lv.slider.MODE.NORMAL,
331        min_value=0,
332        max_value=100,
333        value=70,
334        bg_c=0x38383C,
335        color=0x8EDA91,
336        parent=page0,
337    )
338    record_button = m5ui.M5Button(
339        text="RECORD",
340        x=24,
341        y=388,
342        bg_c=0x7A2731,
343        text_c=0xF4F4F5,
344        font=lv.font_montserrat_18,
345        parent=page0,
346    )
347    play_button = m5ui.M5Button(
348        text="PLAY",
349        x=252,
350        y=388,
351        bg_c=0x303034,
352        text_c=0xF4F4F5,
353        font=lv.font_montserrat_18,
354        parent=page0,
355    )
356
357    record_button.add_event_cb(record_button_event_handler, lv.EVENT.ALL, None)
358    play_button.add_event_cb(play_button_event_handler, lv.EVENT.ALL, None)
359    volume_slider.add_event_cb(volume_slider_event_handler, lv.EVENT.ALL, None)
360
361    page0.screen_load()
362    Speaker.stop()
363    Speaker.end()
364    Mic.end()
365    record_buffer = bytearray(0)
366    buffer_a = bytearray(4000)
367    buffer_b = bytearray(4000)
368    Speaker.setPA(True)
369    state = "IDLE"
370    volume = 70
371    record_pending = False
372    play_pending = False
373    volume_pending = False
374    next_is_a = True
375    queued_chunks = 0
376    stop_requested = False
377    record_start = 0
378    recorded_bytes = 0
379    speaker_ready = False
380    play_started = False
381    record_button.set_size(204, 64)
382    play_button.set_size(204, 64)
383
384
385def loop():
386    global \
387        page0, \
388        label_title, \
389        label_state, \
390        label_duration, \
391        label_message, \
392        label_volume_name, \
393        label_volume, \
394        volume_slider, \
395        record_button, \
396        play_button, \
397        record_pending, \
398        play_pending, \
399        volume, \
400        volume_pending, \
401        stop_requested, \
402        record_buffer, \
403        state, \
404        queued_chunks, \
405        next_is_a, \
406        recorded_bytes, \
407        buffer_a, \
408        buffer_b, \
409        record_start, \
410        speaker_ready, \
411        play_started
412    M5.update()
413    if record_pending:
414        record_pending = False
415        if state == "RECORDING":
416            stop_requested = True
417            state = "STOPPING"
418            label_state.set_text(str(state))
419            label_message.set_text(str("Finishing recording..."))
420        else:
421            if state != "STOPPING":
422                Speaker.stop()
423                Speaker.end()
424                play_button.set_btn_text(str("PLAY"))
425                Mic.end()
426                Mic.setSampleRate(8000)
427                Mic.begin()
428                record_buffer = bytearray(0)
429                recorded_bytes = 0
430                queued_chunks = 0
431                next_is_a = True
432                stop_requested = False
433                label_duration.set_text(str((str((recorded_bytes / 16000)) + str(" / 30 s"))))
434                if Mic.isRunning():
435                    Mic.record(buffer_a, 8000, False)
436                    Mic.record(buffer_b, 8000, False)
437                    if (Mic.isRecording()) == 2:
438                        queued_chunks = 2
439                        record_start = time.ticks_ms()
440                        state = "RECORDING"
441                        label_state.set_text(str(state))
442                        label_message.set_text(str("Tap STOP REC to finish"))
443                        record_button.set_btn_text(str("STOP REC"))
444                    else:
445                        Mic.end()
446                        queued_chunks = 0
447                        state = "IDLE"
448                        label_state.set_text(str(state))
449                        label_message.set_text(str("Recorder failed"))
450                        record_button.set_btn_text(str("RECORD"))
451                else:
452                    state = "IDLE"
453                    label_state.set_text(str(state))
454                    label_message.set_text(str("Microphone failed"))
455                    record_button.set_btn_text(str("RECORD"))
456    if state == "RECORDING" or state == "STOPPING":
457        if (Mic.isRecording()) < queued_chunks:
458            if next_is_a:
459                record_buffer.extend(buffer_a)
460            else:
461                record_buffer.extend(buffer_b)
462            recorded_bytes = recorded_bytes + 4000
463            queued_chunks = queued_chunks - 1
464            record_start = time.ticks_ms()
465            if not stop_requested and recorded_bytes + queued_chunks * 4000 < 480000:
466                if next_is_a:
467                    Mic.record(buffer_a, 8000, False)
468                else:
469                    Mic.record(buffer_b, 8000, False)
470                queued_chunks = queued_chunks + 1
471            next_is_a = not next_is_a
472            label_duration.set_text(str((str((recorded_bytes / 16000)) + str(" / 30 s"))))
473            if queued_chunks == 0:
474                Mic.end()
475                state = "READY"
476                label_state.set_text(str(state))
477                if recorded_bytes >= 480000:
478                    label_message.set_text(str("30 s limit reached"))
479                else:
480                    label_message.set_text(str("Recording ready"))
481                record_button.set_btn_text(str("RECORD"))
482                play_button.set_btn_text(str("PLAY"))
483        if (state == "RECORDING" or state == "STOPPING") and (
484            time.ticks_diff((time.ticks_ms()), record_start)
485        ) > 2000:
486            Mic.end()
487            if recorded_bytes > 0:
488                state = "READY"
489            else:
490                state = "IDLE"
491            label_state.set_text(str(state))
492            queued_chunks = 0
493            label_message.set_text(str("Recording timed out"))
494            record_button.set_btn_text(str("RECORD"))
495    if play_pending:
496        play_pending = False
497        if state == "PLAYING":
498            Speaker.stop()
499            Speaker.end()
500            state = "READY"
501            label_state.set_text(str(state))
502            play_button.set_btn_text(str("PLAY"))
503        else:
504            if state == "READY":
505                Mic.end()
506                speaker_ready = Speaker.begin()
507                if speaker_ready:
508                    Speaker.setVolume(int((volume * 255 + 50) / 100))
509                    Speaker.setPA(True)
510                    play_started = Speaker.playRaw(record_buffer, 8000)
511                    if play_started:
512                        state = "PLAYING"
513                        label_state.set_text(str(state))
514                        label_message.set_text(str(""))
515                        play_button.set_btn_text(str("STOP PLAY"))
516                    else:
517                        label_message.set_text(str("Playback failed"))
518                else:
519                    label_message.set_text(str("Speaker failed"))
520    if state == "PLAYING" and (Speaker.isPlaying()) == 0:
521        Speaker.stop()
522        Speaker.end()
523        state = "READY"
524        label_state.set_text(str(state))
525        play_button.set_btn_text(str("PLAY"))
526    if volume_pending:
527        volume_pending = False
528        if state == "PLAYING":
529            Speaker.setVolume(int((volume * 255 + 50) / 100))
530    time.sleep_ms(10)
531
532
533if __name__ == "__main__":
534    try:
535        setup()
536        while True:
537            loop()
538    except (Exception, KeyboardInterrupt) as e:
539        try:
540            m5ui.deinit()
541            from utility import print_error_msg
542
543            print_error_msg(e)
544        except ImportError:
545            print("please update to latest firmware")

示例输出:

无

红外发送与接收

使用 G13 的板载红外接收器和 G49 的发射器。点击发送按钮,发送地址为 0x08、数据字节逐次递增的 NEC 帧。界面显示发送数据、接收地址与数据以及接收次数。可使用支持 NEC 协议的红外遥控器测试接收。

MicroPython 代码块:

  1# SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
  2#
  3# SPDX-License-Identifier: MIT
  4
  5import time
  6
  7import lvgl as lv
  8import M5
  9from M5 import *
 10import m5ui
 11from unit import IRUnit
 12
 13
 14BACKGROUND = 0x080808
 15PANEL = 0x222224
 16TEXT = 0xF4F4F5
 17MUTED = 0x9A9A9F
 18GOOD = 0x8EDA91
 19
 20BUTTON_X = 24
 21BUTTON_Y = 388
 22BUTTON_W = 432
 23BUTTON_H = 64
 24TX_TONE_HZ = 1800
 25RX_TONE_HZ = 900
 26TONE_DURATION_MS = 55
 27TONE_GAP_MS = 25
 28
 29ir = None
 30page = None
 31label_tx = None
 32label_rx = None
 33label_count = None
 34tx_data = 0
 35rx_count = 0
 36rx_pending = False
 37rx_data = 0
 38rx_addr = 0
 39tx_pending = False
 40speaker_ready = False
 41tone_queue = []
 42tone_ready_ms = 0
 43
 44
 45def make_label(parent, text, x, y, width, font, color=TEXT, align=lv.TEXT_ALIGN.LEFT):
 46    label = m5ui.M5Label(text, x, y, color, BACKGROUND, 0, font, parent)
 47    label.set_width(width)
 48    label.set_style_text_align(align, lv.PART.MAIN)
 49    label.remove_flag(lv.obj.FLAG.CLICKABLE)
 50    return label
 51
 52
 53def make_page(title):
 54    screen = m5ui.M5Page(bg_c=BACKGROUND)
 55    screen.set_style_pad_all(0, lv.PART.MAIN)
 56    screen.set_style_border_width(0, lv.PART.MAIN)
 57    screen.set_style_shadow_width(0, lv.PART.MAIN)
 58    screen.remove_flag(lv.obj.FLAG.SCROLLABLE)
 59    make_label(screen, title, 24, 24, 432, lv.font_montserrat_24)
 60    return screen
 61
 62
 63def make_panel(parent, x, y, width, height, color=PANEL):
 64    panel = lv.obj(parent)
 65    panel.remove_style_all()
 66    panel.set_pos(x, y)
 67    panel.set_size(width, height)
 68    panel.set_style_radius(24, lv.PART.MAIN)
 69    panel.set_style_pad_all(0, lv.PART.MAIN)
 70    panel.set_style_bg_color(lv.color_hex(color), lv.PART.MAIN)
 71    panel.set_style_bg_opa(255, lv.PART.MAIN)
 72    panel.remove_flag(lv.obj.FLAG.SCROLLABLE)
 73    panel.remove_flag(lv.obj.FLAG.CLICKABLE)
 74    return panel
 75
 76
 77def make_button(parent, text, x, y, width, height, color=0x303034):
 78    button = m5ui.M5Button(text, x, y, width, height, color, TEXT, lv.font_montserrat_18, parent)
 79    button.set_style_radius(18, lv.PART.MAIN)
 80    button.set_style_pad_all(0, lv.PART.MAIN)
 81    button.set_style_shadow_width(0, lv.PART.MAIN)
 82    button.set_style_shadow_width(0, lv.PART.MAIN | lv.STATE.PRESSED)
 83    button.label.set_width(width - 16)
 84    button.label.set_style_text_align(lv.TEXT_ALIGN.CENTER, lv.PART.MAIN)
 85    button.label.center()
 86    return button
 87
 88
 89def ir_rx_event(data, addr, ctrl):
 90    global rx_count, rx_pending, rx_data, rx_addr
 91
 92    rx_count += 1
 93    rx_data = data
 94    rx_addr = addr
 95    rx_pending = True
 96
 97
 98def queue_tone(frequency):
 99    if speaker_ready and len(tone_queue) < 4:
100        tone_queue.append(frequency)
101
102
103def update_tone():
104    global tone_ready_ms
105
106    if not speaker_ready or not tone_queue:
107        return
108    now = time.ticks_ms()
109    if time.ticks_diff(now, tone_ready_ms) >= 0:
110        Speaker.tone(tone_queue.pop(0), TONE_DURATION_MS)
111        tone_ready_ms = time.ticks_add(now, TONE_DURATION_MS + TONE_GAP_MS)
112
113
114def send_button_event(event_struct):
115    global tx_pending
116
117    if event_struct.code == lv.EVENT.CLICKED:
118        tx_pending = True
119
120
121def setup():
122    global ir, page, label_tx, label_rx, label_count
123    global speaker_ready, tone_ready_ms
124
125    M5.begin()
126    m5ui.init()
127    page = make_page("Infrared")
128    panel = make_panel(page, 24, 84, 432, 260)
129    make_label(
130        panel, "Addr / Data", 140, 20, 272, lv.font_montserrat_18, MUTED, lv.TEXT_ALIGN.RIGHT
131    )
132    values = []
133    for index, name in enumerate(("TX", "RX", "Received")):
134        y = 64 + index * 68
135        make_label(panel, name, 20, y + 4, 112, lv.font_montserrat_18, MUTED)
136        values.append(
137            make_label(panel, "--", 140, y, 272, lv.font_montserrat_24, TEXT, lv.TEXT_ALIGN.RIGHT)
138        )
139    label_tx, label_rx, label_count = values
140    label_tx.set_text("Ready")
141    label_rx.set_text("Waiting")
142    label_count.set_text("0")
143    send_button = make_button(page, "SEND NEC", BUTTON_X, BUTTON_Y, BUTTON_W, BUTTON_H)
144    send_button.add_event_cb(send_button_event, lv.EVENT.ALL, None)
145    page.screen_load()
146    # Use the same explicit board IR pins as the graphical IR Unit example.
147    ir = IRUnit((13, 49))
148    ir.rx_cb(ir_rx_event)
149    speaker_ready = Speaker.begin()
150    if speaker_ready:
151        Speaker.setVolume(128)
152    tone_ready_ms = time.ticks_ms()
153
154
155def loop():
156    global tx_data, rx_pending, tx_pending
157
158    M5.update()
159    if tx_pending:
160        tx_pending = False
161        tx_data = (tx_data + 1) & 0xFF
162        ir.tx(0x08, tx_data)
163        queue_tone(TX_TONE_HZ)
164        label_tx.set_text("08 / %02X" % tx_data)
165    if rx_pending:
166        rx_pending = False
167        label_rx.set_text("%02X / %02X" % (rx_addr, rx_data))
168        label_count.set_text("%d" % rx_count)
169        queue_tone(RX_TONE_HZ)
170    update_tone()
171    time.sleep_ms(10)
172
173
174if __name__ == "__main__":
175    try:
176        setup()
177        while True:
178            loop()
179    except (Exception, KeyboardInterrupt):
180        Speaker.stop()
181        Speaker.end()
182        m5ui.deinit()
183        raise

示例输出:

无