🐷

【M5stackS3】QRコードスキャナーユニットの使い方

2024/08/14に公開

M5Stack用QRコードスキャナーユニット(STM32F030)を買いました。
サンプルコードで動かしてみようと思ったらエラーで動かず、半日くらい苦戦してしまった

サンプルコードについて

基本M5stackはカタログスペックは載っていますが、プログラムをどう書けばよいかを説明するドキュメントは存在しません。

なので、サンプルコードを読み解く必要があります。

https://github.com/m5stack/M5Unit-QRCode/blob/main/example/i2c_mode/i2c_mode.ino

で、この通りに書いて動けば良いんですが、動かないんですね

結論

以下2つを設定すると動くようになります。

1.Wireを初期化する

Wire.begin();を入れます。
ちなみにM5stack coreS3では、SDAは21、SCLは22です。

2.I2Cデバイスのアドレスを設定する

M5stackにM5Unit-QRCodeを繋いだ状態で、以下のコードを実行してみましょう

#include <Wire.h>

void setup() {
  Serial.begin(115200);
  Wire.begin(); // SDA, SCLはデフォルト設定で使用
  delay(1000); // これを入れることを強く勧めます
  Serial.println("I2C Scanner");
}

void loop() {
  byte count = 0;

  for (byte i = 8; i < 120; i++) {
    Wire.beginTransmission(i);
    if (Wire.endTransmission() == 0) {
      Serial.print("Found I2C Device at address (HEX): 0x");
      Serial.println(i, HEX);
      count++;
      delay(1); // small delay
    }
  }

  Serial.print("Found ");
  Serial.print(count, DEC);
  Serial.println(" device(s).");

  delay(5000); // 5秒ごとに再スキャン
}

これを実行すると、シリアルモニタに以下のように表示されるはずです。

Found I2C Device at address (HEX): 0x21

M5Unit-QRCodeのI2Cアドレスは0x21ということがわかりました。

本当に動くサンプルコード

以下の通り、公式サンプルコードに4行追加することで、ちゃんと動くようになります。

#include <M5Unified.h>
#include <M5GFX.h>
#include "M5UnitQRCode.h"

M5Canvas canvas(&M5.Display);

M5UnitQRCodeI2C qrcode;

#define I2C_AUTO_SCAN_MODE

#define UNIT_QRCODE_ADDR 0x21 //追加

void setup() {
    M5.begin();
    Serial.begin(115200); //追加
    Wire.begin(); //追加
    delay(1000);  //追加

    canvas.setColorDepth(1);  // mono color
    canvas.createSprite(M5.Display.width(), M5.Display.height());
    canvas.setTextSize((float)canvas.width() / 160);
    canvas.setTextScroll(true);

    while (!qrcode.begin(&Wire, UNIT_QRCODE_ADDR, 21, 22, 100000U)) {
        canvas.println("Unit QRCode I2C Init Fail");
        Serial.println("Unit QRCode I2C Init Fail");
        canvas.pushSprite(0, 0);
        delay(1000);
    }

    canvas.println("Unit QRCode I2C Init Success");
    Serial.println("Unit QRCode I2C Init Success");
#ifdef I2C_AUTO_SCAN_MODE
    canvas.println("Auto Scan Mode");
    canvas.pushSprite(0, 0);
    qrcode.setTriggerMode(AUTO_SCAN_MODE);
#else
    canvas.println("Manual Scan Mode");
    canvas.pushSprite(0, 0);
    qrcode.setTriggerMode(MANUAL_SCAN_MODE);
#endif
}

void loop() {
    if (qrcode.getDecodeReadyStatus() == 1) {
        uint8_t buffer[512] = {0};
        uint16_t length     = qrcode.getDecodeLength();
        Serial.printf("len:%d\r\n", length);
        qrcode.getDecodeData(buffer, length);
        Serial.printf("decode data:");
        for (int i = 0; i < length; i++) {
            Serial.printf("%c", buffer[i]);
            canvas.printf("%c", buffer[i]);
        }
        Serial.println();
        canvas.println();
        canvas.pushSprite(0, 0);
    }
#ifndef I2C_AUTO_SCAN_MODE
    M5.update();
    if (M5.BtnA.wasPressed()) {
        // start scan
        qrcode.setDecodeTrigger(1);
    }
    if (M5.BtnB.wasPressed()) {
        // stop scan
        qrcode.setDecodeTrigger(0);
    }
#endif
}

I2C_AUTO_SCAN_MODEを記述していれば、スキャナーのTRIGボタンを押さなくてもスキャンするようになります。(工場の生産ラインとかで使うかな)
反対にI2C_AUTO_SCAN_MODEをオフにすると、レジのような使い方ができます。

補足 スキャンされたデータを取得する

QRコードスキャナーがバーコードを読み取ると、
qrcode.getDecodeReadyStatus()がtrueになります。

読み取ったデータはデータを格納する領域を設けたうえで、これをqrcode.getDecodeData(buffer, length)に投げてあげるとbuffer内にデータが入ります。

bufferに格納されたデータは以下のように文字列として取り出してやるといいでしょう。

void loop(){
    if (qrcode.getDecodeReadyStatus() == 1) {
        // データを取得
        uint8_t buffer[512] = {0};
        uint16_t length     = qrcode.getDecodeLength();
        Serial.printf("len:%d\r\n", length);
        qrcode.getDecodeData(buffer, length);
        
        // bufferの内容をdataに追加
        String data;
        for (int i = 0; i < length; i++) {
            data += (char)buffer[i]; 
        }

        Serial.println("decode data:" + data);
    }
}

さいごに

基本M5stackはサンプルコードしかなく、どういうコードを書けばよいのか全くわかりません。
1から10まで説明する日本人と真逆の考え方ですね。

Discussion