pdf-icon

移植到M5Unified上的要点

本文档简要概述了用于Arduino IDE和ESP-IDF的各个M5Stack库迁移到库M5Unified的注意事项。
* 本文档是基于库M5Unified版本v0.0.7来介绍的。

M5概述

M5Unified是一个用于处理具有不同规格的M5Stack产品的库文件,使他们具有通用 API 。虽然需要更多的配置,但是相同的源代码可以用于不同的设备,这在以下情况下很有用。

  • 在M5Stack上开发应用,在M5Atom上运行。
    M5Unified 可以和M5Atom 共享源码,M5Atom 没有屏幕渲染功能。
    * 代码占用空间和内存消耗会增加。
  • 开发适用于 M5Stack 或 M5StickC 的应用程序。
    通过在相对坐标(例如,显示器的中心)中指定图形坐标来缩放到不同的屏幕尺寸。
  • 扬声器和蜂鸣器可用于播放声音。

与现有M5Stack库的主要区别

  • 包含文件可以统一定义。
    过去,每个设备的 Include 头文件都不同,例如M5Stack Basic的#include <M5Stack.h> 和M5StickC的#include <M5StickC.h>, 但对于M5Unified的#include <M5Unified.h>,设备类型在库中自动识别。

  • M5.begin()的参数不同。
    在传统的M5.begin()中,每个设备库的参数内容和数量都不同。为了统一它们,使用结构作为参数。有关详细信息,请参阅 M5.begin()

  • 不支持 M5Atom 和其他 RGB LED 控件。
    M5Unified版本为v0.0.7时,不支持M5Atom的RGB LED控制。请单独安装库文件 FastLED

  • TFCard (SDCard) 未自动安装 (SD.begin())
    为了支持ESP-IDF,默认不使用SD.h,内部不执行SD.begin(),前提是可用TF卡库中也选择了SDFat。

  • 图形库从TFT-eSPI更改为M5GFX
    现有库内部有 TFT_eSPI,但M5Unified依赖于M5GFX,已更改为使用M5GFX。请注意,API 是不同的。
    关于M5GFX库的更多信息,请参考M5GFX库的教程 Getting Started with M5GFX

  • 扬声器功能
    Core1 声音中有噪音,但比之前的库有所改进。此外,带有压电蜂鸣器的型号可以播放音频文件等,蜂鸣器也是一样的道理。
    *请注意不要以高音量或低频连续播放音频文件,否则可能会损坏扬声器。

  • Button名称的区别
    为了通用起见,即使设备只有一个按钮,名称也是BtnA而不是Btn。

M5Unified使用注意事项

  • 它不能与其他M5Stack库结合使用。
    因为同名M5,编译时会出现如下错误。
error: reference to 'jpeg_div_t' is ambiguous jpeg_div_t scale = JPEG_DIV_NONE);
error: conflicting declaration 'M5Stack M5' extern M5Stack M5;
  • 当使用M5Atom Matrix和FastLED库时,RGB LED的亮度应小于20(设置范围:0~100)。使用高于该亮度的亮度会因热量而损坏亚克力板和LED。

M5.begin()

M5.config()和M5.begin()的使用

M5.begin()的参数由结构体设置,应在setup()函数开始时执行。

如果您是初学者,即使您使用默认设置,也请在代码设置功能的开头写下以下内容。
auto cfg = M5.config(); // Assign a structure for setup.

// Set the items you want to configure. Omit the following two lines if you use the default settings.
cfg.serial_baudrate = 115200;
cfg.output_power = true;

M5.begin(cfg); // start the device with the value you set.

M5.config()的参数

有关详细信息,请参阅以下链接。

M5.config()

M5.begin()格式

传统的 M5.begin()对于每个设备具有不同的内容和参数数量,如下所示。

// M5Stack
M5.begin(bool LCDEnable = true, bool SDEnable = true, bool SerialEnable = true, bool I2CEnable = false);

// M5Core2
M5.begin(bool LCDEnable = true, bool SDEnable = true, bool SerialEnable = true, bool I2CEnable = false, mbus_mode_t mode = KMBusModeOutput);

// M5StickC
M5.begin(bool LCDEnable = true, bool PowerEnable = true, bool SerialEnable = true);

// M5StickCPlus
M5.begin(bool LCDEnable = true, bool PowerEnable = true, bool SerialEnable = true);

// M5Atom
M5.begin(bool SerialEnable = true, bool I2CEnable = true, bool DisplayEnable = false);

关于按钮

可用按钮因M5Stack产品而异。

  • BtnA, BtnB, BtnC
    可自定义按钮
  • BtnPWR
    电源按钮在某些设备上也可自定义。
  • BtnEXT
    更多信息,请参考以下链接。

About Buttons

如何使用按钮

Basics

按下按钮A时,显示消息“BtnA isPressed”; 释放时,显示消息“BtnA isReleased”。

#include <M5Unified.h>

void setup() {
    auto cfg = M5.config();
    cfg.clear_display = true;
    M5.begin(cfg);
    M5.Lcd.setTextSize(2);
    M5.Lcd.println("Press BtnA");
}

void loop() {
    // update the button state.
    M5.update();

    if (M5.BtnA.isPressed()) {
        M5.Display.setCursor(0, 16);
        M5.Display.println("BtnA isPressed ");
    } else {
        M5.Display.setCursor(0, 16);
        M5.Display.println("BtnA isReleased");
    }
}

对于多个函数

必须执行M5.update()来更新按钮状态。请注意,如果有更多函数,则这些函数也需要M5.update()。

#include <M5Unified.h>

uint32_t loop_count = 0;

void setup() {
    auto cfg = M5.config();
    cfg.clear_display = true;
    M5.begin(cfg);
    M5.Lcd.setTextSize(2);
    M5.Lcd.println("Press BtnA");
}

void loop() {

    M5.update(); // update the button state.

    if (M5.BtnA.wasPressed()) {
        M5.Display.fillScreen(TFT_BLACK);
        M5.Display.setCursor(0, 0);
        M5.Display.println("BtnA wasPressed");
        M5.Display.println("Press BtnA Stop Count");

        while (true) {
        
            M5.update(); // update the button state within the subloop.

            M5.Display.setCursor(0, 32);
            M5.Display.printf("count: %10d\n", loop_count);
            if (M5.BtnA.wasPressed()) {
                M5.Display.println("Count Stop");
                loop_count = 0;
                break;
            }
            loop_count++;
        }
    }
}

关于按钮状态

可以使用以下函数获取按钮的状态。初学者应首先尝试使用wasPressed()或wasClicked()。

  • was
    检测状态是否发生在执行M5.update()之前。

    • wasPressed
      是否被按下。
    • wasReleased
      是否被释放
  • is
    检测状态是否发生在执行M5.update()时。

    • isPressed
      是否被按下
    • isReleased
      是否被释放
  • Click
    检测是否进行了单击。

    • wasClicked
      每次点击时返回true。
    • wasSingleClicked
      当检测到单击时返回true。
    • wasDoubleClicked
      当检测到两次点击时返回true。
    • wasDecideClickCount
      在连续点击的情况下检测到最后一次点击时返回true。(错别字里有一个wasDeciedClickCount的版本。)
  • longPressed
    检测在指定时间内长按或释放按钮。

    • pressedFor(uint32_t msec)
      当按钮被按下指定时间或更长时间时返回true。
    • releasedFor(uint32_t msec)
      如果按钮被释放指定时间或更长时间,则返回 true。

点击次数

添加连续单击按钮的次数。次数可以通过M5.Btn.getClickCount()获得。

关于屏幕绘制

M5Unified依赖于 M5GFX library 如果尚未安装,应一起安装。(ArduinoIDE在安装M5Unified时会显示对话框消息,PlatformIO会自动安装它。)

M5.Display (or M5.Lcd)

对于带屏幕的设备,M5GFX API可与M5.Display一起使用。不需要定义。

使用M5Unified的HelloWorld

要在M5Unified使用HelloWorld,请编写以下代码,该代码对于LCD和e-Ink显示设备都是相同的来源。相同的源代码可用于LCD和电子墨水屏设备,也可用于M5Atom设备。

#include <M5Unified.h>

void setup() {

  auto cfg = M5.config();
  M5.begin(cfg);
  M5.Display.setTextSize(3);
  M5.Display.println("HelloWorld!");

}

void loop() {
}

更改为M5Unified时的重大变化。

API也有一些差异,但我省略了细节。

更改包含的头文件

从特定产品的库文件标题更改为M5Unified.h,并在需要访问SD卡时添加SD.h。

- #include <M5Stack.h>
+ #include <SD.h>
+ #include <M5Unified.h>

M5.begin()变更

通过执行M5.config()来更改M5.begin(),如下

- M5.begin(true, true, true, true);
+ auto cfg = M5.config();
+ cfg.internal_imu = true;
+
+ M5.begin(cfg);

IMU处理

更改M5.Imu为IMU。

添加SD.begin()

添加SD.begin()

+    while (false == SD.begin(GPIO_NUM_4, SPI, 25000000))
+    {
+      delay(500);
+    }

内部I2C释放

如果你想使用M5Stack Basic/Gray/Fire等的Port.A而不是I2C,你需要运行M5.In_I2C.release()。

auto cfg = M5.config();
.
.
.
M5.begin(cfg);
M5.In_I2C.release();

[参考]FactoryTest.ino的M5Unified

如果将M5Stack的Example FactoryTest.ino改成M5Unified,就会变成下面这样。

  • 更改头文件
  • 更改IMU流程
  • 添加SD.begin
  • 添加SPEAKER_PIN的定义
  • 更改了M5.Btn.pressedFor的参数
diff --git a/src/main.cpp b/src/main.cpp
index b735e30..dae9b99 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,10 +1,10 @@
 #include <Arduino.h>
-#include <M5Stack.h>
+#include <SD.h>
+#include <M5Unified.h>
 #include <stdlib.h>
 //#include "FastLED.h"
 
 #include "WiFi.h"
-#include "utility/MPU9250.h"
 
 extern const unsigned char gImage_logoM5[];
 extern const unsigned char m5stack_startup_music[];
@@ -13,7 +13,8 @@ extern const unsigned char m5stack_startup_music[];
 #define min(a, b) (((a) < (b)) ? (a) : (b))
 #endif
 
-MPU9250 IMU;
+
+#define SPEAKER_PIN 25
 
 // #define LEDS_PIN 15
 // #define LEDS_NUM 10
@@ -127,15 +128,15 @@ void writeFile(fs::FS &fs, const char *path, const char *message) {
 }
 
 void buttons_test() {
-    if (M5.BtnA.wasReleased() || M5.BtnA.pressedFor(1000, 200)) {
+    if (M5.BtnA.wasReleased() || M5.BtnA.pressedFor(1000)) {
         M5.Lcd.printf("A");
         Serial.printf("A");
     }
-    if (M5.BtnB.wasReleased() || M5.BtnB.pressedFor(1000, 200)) {
+    if (M5.BtnB.wasReleased() || M5.BtnB.pressedFor(1000)) {
         M5.Lcd.printf("B");
         Serial.printf("B");
     }
-    if (M5.BtnC.wasReleased() || M5.BtnC.pressedFor(1000, 200)) {
+    if (M5.BtnC.wasReleased() || M5.BtnC.pressedFor(1000)) {
         M5.Lcd.printf("C");
         Serial.printf("C");
     }
@@ -475,8 +476,11 @@ void setup() {
     //     GPIO_test();
     // }
 
+    auto cfg = M5.config();
+    cfg.internal_imu = true;
+
     // initialize the M5Stack object
-    M5.begin();
+    M5.begin(cfg);
 
     /*
       Power chip connected to gpio21, gpio22, I2C device
@@ -484,6 +488,10 @@ void setup() {
       If used battery, please call this function in your project
     */
     M5.Power.begin();
+    while (false == SD.begin(GPIO_NUM_4, SPI, 25000000))
+    {
+      delay(500);
+    }
 
     // dac test
     // if (gpio_test_flg)
@@ -492,7 +500,6 @@ void setup() {
     // }
     startupLogo();
     // ledBar();
-    Wire.begin();
 
     // Lcd display
     M5.Lcd.setBrightness(100);
@@ -609,54 +616,33 @@ void setup() {
         M5.Lcd.setBrightness(i);
         delay(2);
     }
-
-    byte c = IMU.readByte(MPU9250_ADDRESS, WHO_AM_I_MPU9250);
-    Serial.print("MPU9250 ");
-    Serial.print("I AM ");
-    Serial.print(c, HEX);
-    Serial.print(" I should be ");
-    Serial.println(0x71, HEX);
-    Serial.println("");
-    M5.Lcd.setCursor(20, 0);
-    M5.Lcd.print("MPU9250");
-    M5.Lcd.setCursor(0, 10);
-    M5.Lcd.print("I AM");
-    M5.Lcd.setCursor(0, 20);
-    M5.Lcd.print(c, HEX);
-    M5.Lcd.setCursor(0, 30);
-    M5.Lcd.print("I Should Be");
-    M5.Lcd.setCursor(0, 40);
-    M5.Lcd.println(0x71, HEX);
-    M5.Lcd.println();
-    delay(100);
-
-    IMU.initMPU9250();
-    // Initialize device for active mode read of acclerometer, gyroscope, and
-    // temperature
-    Serial.println("MPU9250 initialized for active data mode....");
-
-    // Read the WHO_AM_I register of the magnetometer, this is a good test of
-    // communication
-    byte d = IMU.readByte(AK8963_ADDRESS, WHO_AM_I_AK8963);
-    Serial.print("AK8963 ");
-    Serial.print("I AM ");
-    Serial.print(d, HEX);
-    Serial.print(" I should be ");
-    Serial.println(0x48, HEX);
-
-    // M5.Lcd.fillScreen(BLACK);
-    M5.Lcd.setCursor(20, 100);
-    M5.Lcd.print("AK8963");
-    M5.Lcd.setCursor(0, 110);
-    M5.Lcd.print("I AM");
-    M5.Lcd.setCursor(0, 120);
-    M5.Lcd.print(d, HEX);
-    M5.Lcd.setCursor(0, 130);
-    M5.Lcd.print("I Should Be");
-    M5.Lcd.setCursor(0, 140);
-    M5.Lcd.print(0x48, HEX);
+    const char* name;
+    // run-time branch : imu model check
+    switch (M5.Imu.getType())
+    {
+      case m5::imu_t::imu_mpu6050:
+        name = "MPU6050";
+        break;
+      case m5::imu_t::imu_mpu6886:
+        name = "MPU6886";
+        break;
+      case m5::imu_t::imu_mpu9250:
+        name = "MPU9250";
+        break;
+      case m5::imu_t::imu_sh200q:
+        name = "SH200Q";
+        break;
+      default:
+        name = "none";
+        break;
+    }
+    M5.Display.print("IMU:");
+    M5.Display.println(name);
+    M5.Display.endWrite();
+    ESP_LOGI("setup", "imu:%s", name);
     delay(1000);
 
+
     M5.Lcd.setCursor(0, 0);
     M5.Lcd.println("wifi test:");
     M5.Lcd.fillScreen(BLACK);
On This Page