CoreP4X
支持以下产品:
支持的组件
CoreP4X 支持以下组件:
支持的显示字体
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 支持以下内置功能和外设:
UiFlow2 示例
RTC 时钟
在 UiFlow2 中打开 corep4x_rtc_example.m5f2 项目。
读取内置 RTC,以 UTC 显示日期和蓝色 HH:MM:SS 时钟。点击 SET TIME,使用 +、- 调整时、分、秒。点击 SAVE 保存时间并保留原日期,或点击 CANCEL 放弃修改。
UiFlow2 代码块:
示例输出:
无
IMU 传感器
在 UiFlow2 中打开 corep4x_imu_example.m5f2 项目。
显示内置加速度计和陀螺仪的 X、Y、Z 三轴读数。加速度单位为 g,角速度单位为度每秒(dps)。倾斜或旋转设备即可观察数值变化。
UiFlow2 代码块:
示例输出:
无
电源管理
在 UiFlow2 中打开 corep4x_power_example.m5f2 项目。
显示 USB VBUS 和电池电压(mV)、充电状态、Port A 5 V 输出状态和充电许可。实际充电时,电池电压显示为绿色。点击 PORT A 开关外部输出,点击 CHARGE 允许或禁止充电,不显示电量百分比。
UiFlow2 代码块:
示例输出:
无
扬声器音调
在 UiFlow2 中打开 corep4x_speaker_tone_example.m5f2 项目。
使用独立滑条调节频率(200~4000 Hz)和音量(0~100%),默认值为 1000 Hz 和 70%。点击 Start tone 或 Stop tone 控制音调播放。PA 开关独立控制功放;启动时 PA 默认开启,音调默认停止。关闭 PA 仅关闭声音输出,不停止音调。
UiFlow2 代码块:
示例输出:
无
录音与播放
在 UiFlow2 中打开 corep4x_audio_example.m5f2 项目。
以 8 kHz、单声道、16 bit 将音频录入内存。点击 RECORD 开始录音,点击 STOP REC 结束,最长录制 30 秒。点击 PLAY 回放录音,点击 STOP PLAY 停止播放。音量滑条范围为 0~100%,默认 70%;播放时自动开启 PA。
UiFlow2 代码块:
示例输出:
无
红外发送与接收
在 UiFlow2 中打开 corep4x_ir_example.m5f2 项目。
使用 G13 的板载红外接收器和 G49 的发射器。点击发送按钮,发送地址为 0x08、数据字节逐次递增的 NEC 帧。界面显示发送数据、接收地址与数据以及接收次数。可使用支持 NEC 协议的红外遥控器测试接收。
UiFlow2 代码块:
示例输出:
无
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
示例输出:
无






