【Arduino】Seeeduino XIAO Expansionボードを使う

it

SeeedStudioから発売されているXIAOシリーズをスタックすることで多くの機能を使用できるXIAO Expansionボードを使ってみました。

Seeeduino XIAO Expansionボード

簡単紹介

SeeedStudio XIAOシリーズをマウントすることで使える拡張ボード。
バッテリー、Groveモジュール接続、RTC用バックアップ電池ホルダ、
OLED, RTC, TFカードスロット, ブザーなど機能豊富。

メーカー商品ページ : Expansion Board Base for XIAO | Seeed Studio Wiki

ピン配置

外観

使ってみた

◆XIAOと合体

XIAO規格で使えるように設計されているので、ピンソケットにはめ込むだけ。
XIAO規格は画像に載せている10種所有していますが、すべて使うことができます。

他にAdafruitのQT-PY規格も使用できますが、GPIOピン配置が違うので基板に合ったピン設定をすることで使うことができます。
(画像下部の左側の基板がQT-PY SAMD21, 右側が QT-PY ESP32S2です。)


基板の背面は、ピンソケットのピンやボタン電池のケースの出っ張りがあります。
机上に直置きするとグラつくので、樹脂のHexスペーサを使って足を付けました。

専用のアクリルカバーキットも販売されています。
今回購入していないのでスペーサを取りました。

◆電源

バッテリーを接続しました。
バッテリー電圧は3.7V、コネクタはJST PH2.0です。

バッテリー給電の場合は基板側面のスライドスイッチを使ってOff/Onを切り替えます。
(USB給電の場合はスライドスイッチがOnになっているとバッテリーを充電します)

◆Grove

Groveモジュール超音波距離測定(Ultrasonic Ranger)を使いました。
測った距離をOLEDに表示している様子です。


Grove配線は複雑な配線が無くロック機構のついたコネクタで安心して着脱ができます。
十分な大きさで作業性が良いと思います。

コシの強いワイヤーが4本なので軽量な基板やモジュールではワイヤーの弾性に負けて設置が落ち着かない問題もありました。

◆いろんな実装モジュール

OLED

XIAOのI2Cを使って制御できます。
白色発色でI2Cアドレスは3c(h)です。

配線不要でOLEDモニタが使えるので作業がはかどります。


Buzzer

小型の圧電ブザーです。
PWM制御により任意の音階を設定できます。
サンプルでは、「ドレミファソラシド」の音階を鳴らしてみました。
レトロ感漂う電子音のメロディーが流れました。

RTC(PCF8563) & バックアップバッテリー

NTPが使えないXIAOシリーズや環境でもバックアップバッテリーがあることでそれなりに精度ある日時を利用できました。
短期間の調査ですが十分な時間精度だと思います。
TFカードリーダと組み合わせてデータ保存するときなどに重宝します。

バックアップバッテリーにはCR1220を使用します。
一度取り付けたバッテリーを取り外すのは少し難度が高めです。

TFカードリーダ(マイクロSDカードリーダ)

マイクロSDカードが使えることで、スケッチのパラメータやモジュール類の校正データを保存できます。
センサーモジュールなどから読み取ったデータをマイクロSDカードにファイル保存することもできるので、データの読み出しも手軽にできます。

今回はXIAO RP2040の内蔵温度モニタを読み出し、TFカード(マイクロSDカード)に保存しました。
使った様子はこちら

まとめ

拡張機能が多くXIAO規格の基板を手軽に開発できる基板です。
配線作業もGroveでワンタッチ接続をすることで、作業時間の短縮や配線間違いもなくなります。

基板の価格やGroveコネクタ対応モジュールは決して安くなく、Groveに対応するモジュールの種類も有限なのでやりたいことすべてをまかなうのは厳しいです。

準備

Arduino環境の作成

◆開発環境

Arduino環境の準備はこちらの記事で紹介しています。

◆ボードライブラリ

今回使用したサンプルは適切なボードライブラリを選択することで、ボードごとのカスタマイズ不要で動作します。

確認に使用したボードとボードライブラリの組み合わせは以下の表のとおりです。

ボード名選択するボード
XIAO SAMD21Seeed SAMD Boards > Seeed XIAO
XIAO RP2040Raspberry Pi Pico/RP2040/RP2350 >Seeed XIAO RP2040
XIAO RP2350Raspberry Pi Pico/RP2040/RP2350 >Seeed XIAO RP2350
XIAO ESP32C3esp32 > XIAO_ESP32C3
XIAO ESP32C6esp32 > XIAO_ESP32C6
XIAO ESP32S3esp32 > XIAO_ESP32S3
XIAO nRF52840Seeed nRF52 Boards > Seeed XIAO nRF52840
Seeed nRF52 Boards > Seeed XIAO nRF52840 Sense
XIAO RA4M1Seeed Renesas Board > XIAO RA4M1

◆モジュールライブラリ

OLED(SSD1306)

ライブラリ名検索確認時のバージョン
Adafruit SSD1306 by AdafruitSSD13062.5.11
Adafruit GFX Library by AdafruitGFX1.11.10

RTC(PCF8563)

ライブラリ名検索確認時のバージョン
RTClib by Adafruitpcf85632.1.4

超音波測定センサー

モジュールライブラリをこちらのサイトからダウンロードします(外部サイト)
Grove – Ultrasonic Ranger | Seeed Studio Wiki

以下の手順でモジュールライブラリをArduino環境にインストールします。
1.Seeed Studioダウンロードサイトからモジュールライブラリをダウンロード
2.ArduinoIDEの[Sketch > Include Library > Add .ZIP Library …]からダウンロードしたモジュールライブラリを選択する。

スケッチサンプル

Buzzer(A3)

説明

GPIO A3に接続されているBuzzer(圧電ブザー)を鳴らします。
PWM周波数設定により音階が変化します。

音階を変化させる関数にtone()を使い、音階「ドレミファソラシド」の順に発音します。

配線

配線不要

スケッチ

const int buzzerPin = A3;

// ドレミファソラシドの周波数(Hz)
const int notes[] = {262, 294, 330, 349, 392, 440, 494, 523};

void setup()
{
  for (int i = 0; i < 8; i++)
  {
    tone(buzzerPin, notes[i]);
    delay(500);
    noTone(buzzerPin);
    delay(100);
  }
}

void loop()
{  
}

結果

音階が流れました。
電子音のレトロゲームの音そのものです。
音は小さめなのでスピーカー出力を大きくしないとあまり聞こえません。

OLED 0.96inch(SSD1306)

説明

OLED を使います。
当サイトロゴのBMP配列を画面に表示します。

OLEDは白発色で、I2Cアドレスは3c(h)です。

実行結果は代表でXIAO SAMD21を載せていますが、同じスケッチをXIAOシリーズの動作を確認しました。
スケッチをすべてのXIAOで動作させるためには、各ボードの専用ボードライブラリの選択が必要です。

配線

配線不要

スケッチ

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH    (128)
#define SCREEN_HEIGHT   (64)

#define OLED_RESET      (-1)
#define SCREEN_ADDRESS  (0x3C)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

#define LOGO_HEIGHT     (32)
#define LOGO_WIDTH      (32)

static const unsigned char PROGMEM logo_bmp[] =
{
0x00, 0x00, 0x00, 0x00,    //0
0x00, 0x00, 0x00, 0x00,    //1
0x00, 0x00, 0x00, 0x00,    //2
0x00, 0x00, 0x00, 0x00,    //3
0x00, 0x00, 0x06, 0x00,    //4
0x00, 0x00, 0x1B, 0xA0,    //5
0x00, 0x00, 0x30, 0x70,    //6
0x00, 0x00, 0xE0, 0x30,    //7
0x00, 0x7F, 0x80, 0x30,    //8
0x01, 0xC0, 0x00, 0x10,    //9
0x03, 0x70, 0x07, 0x98,    //10
0x0F, 0xFC, 0x1C, 0x8C,    //11
0x19, 0x3C, 0x30, 0x44,    //12
0x12, 0x7E, 0x78, 0x46,    //13
0x32, 0xF2, 0xF8, 0x42,    //14
0x23, 0xA2, 0xCC, 0x83,    //15
0x21, 0xF6, 0xDD, 0x81,    //16
0xE0, 0x7E, 0xFF, 0x01,    //17
0x70, 0x38, 0xFC, 0x71,    //18
0x4F, 0x00, 0x07, 0xF1,    //19
0x61, 0xFF, 0xFC, 0x21,    //20
0x20, 0x00, 0x00, 0x61,    //21
0x30, 0xE0, 0x01, 0x83,    //22
0x18, 0x3F, 0xFE, 0x06,    //23
0x0C, 0x00, 0x00, 0x0C,    //24
0x03, 0xF8, 0x00, 0xF0,    //25
0x00, 0x0F, 0x7F, 0xC0,    //26
0x00, 0x00, 0x00, 0x00,    //27
0x00, 0x00, 0x00, 0x00,    //28
0x00, 0x00, 0x00, 0x00,    //29
0x00, 0x00, 0x00, 0x00,    //30
0x00, 0x00, 0x00, 0x00,    //31
0x00, 0x00, 0x00, 0x00,    //32
};

void testdrawbitmap(void);
long pattern = 0;

void setup()
{
  if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    for(;;);
  }

  display.clearDisplay();

  display.drawBitmap(0, 0, logo_bmp, LOGO_WIDTH, LOGO_HEIGHT, 1);
  display.display();
  delay(1000);
}

void loop()
{
}

結果

配線不要でOLEDが使えます。
XIAOシリーズでは専用ボードライブラリを使用することでスケッチの変更なく同じ動作をしてくれます。

Groveを使った距離測定(UltrasonicRanger)

説明

Groveコネクタで接続する超音波測定モジュール(UltrasonicRanger)を使います。
ライブラリは「準備-ボードライブラリ」にてインストールします。

距離を計測し、結果をOLEDにグラフ表示します。
画面右端に距離をプロットするごとに左へスクロールします。

配線

Grove配線をします。

スケッチ

#include "Ultrasonic.h"

Ultrasonic ultrasonic(D0);

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH    (128)
#define SCREEN_HEIGHT   (64)

#define OLED_RESET      (-1)
#define SCREEN_ADDRESS  (0x3C)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

void setup() 
{
  Serial.begin(115200);

  if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    for(;;);
  }

  display.clearDisplay();
}

void loop()
{
  const int16_t BufferSize = SCREEN_WIDTH;
  int16_t distance_array[BufferSize];
  int16_t distanceIndex = 0;
  
  for(int16_t i = 0; i < BufferSize; i ++)
  {
    distance_array[i] = -1;
  }

  while(1)
  {
    distance_array[distanceIndex] = ultrasonic.MeasureInCentimeters();

    distanceIndex ++;
    if(distanceIndex >= BufferSize) distanceIndex = 0;

    display.clearDisplay();
    int16_t viewIndex = distanceIndex;
    for(int16_t i = 0; i < BufferSize; i ++)
    {
      display.drawPixel(i, SCREEN_HEIGHT - distance_array[viewIndex], SSD1306_WHITE);
      viewIndex ++;
      if(viewIndex >= BufferSize) viewIndex = 0;
    }
    display.display();
  }
}

結果

距離の測定結果をOLEDに記録しました。
右から左へグラフが流れていきます。
対象物との距離が近いほど下部へ、遠いほど上部へプロットします。

RTC(PCF8563)

説明

リアルタイムクロックを使います。
ライブラリはAdafruit の「RTClib by Adafruit」を使用します。
時間結果をOLEDに表示するために Adafruitの「Adafruit SSD1306 by Adafruit」を使用します。

バックアップバッテリー効果を確認するためNTPは使わないで手動で時間設定をします。

XIAO expansionボードのユーザボタン(D1)が押された状態で起動するとRTCを初期化します。
初期化時間は 2025/12/31/ 00:00:00です。

電源を切断して次回起動時にバックアップ電源が無い場合、RTCを初期化します。
初期化時間は 2025/1/1/ 00:00:00です。

電源が供給され続けた状態でリセットボタンを押すか、RTCのバックアップ電池がある場合は時間の初期化は行いません。

配線

配線不要です。

スケッチ

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#include "RTClib.h"

#define BUTTON_PIN    (D1)

#define SCREEN_WIDTH    (128)
#define SCREEN_HEIGHT   (64)

#define OLED_RESET      (-1)
#define SCREEN_ADDRESS  (0x3C)

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

RTC_PCF8563 rtc;

void setup () {

  Serial.begin(115200);

  if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS))
  {
    for(;;);
  }

  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);
  
  if (! rtc.begin())
  {
    for(;;);
  }


  pinMode(BUTTON_PIN, INPUT_PULLUP);
  if(digitalRead(BUTTON_PIN) == false)
  {
    rtc.adjust(DateTime(2025, 12, 31, 0, 0, 0));
  }

  if (rtc.lostPower()) {
    rtc.adjust(DateTime(2025, 1 ,1 ,0 ,0 ,0));
  }

  rtc.start();
}

void loop ()
{

  DateTime now = rtc.now();
  char bufDate[16];
  char bufTime[16];
  sprintf(bufDate,"%d/%d/%d",
    now.year(), now.month(), now.day());

  sprintf(bufTime,"%d:%d:%d",
    now.hour(), now.minute(), now.second());

  display.clearDisplay();

  display.setTextSize(1);
  display.setCursor(0, 0);
  display.print("date");
  display.setCursor(0, 30);
  display.print("Time");

  display.setTextSize(2);
  display.setCursor(0, 10);
  display.print(bufDate);
  display.setCursor(0, 40);
  display.print(bufTime);

  display.display();
  delay(1000);
}

結果

起動するとOLEDに日時が表示されました。


RTCのバックアップ電池が無い状態でUSBケーブル(電源供給)の挿抜を行うと日時が初期化されました。
RTCのバックアップ電池をセットした状態でUSBケーブルの挿抜を行っても前回設定した時間の延長が表示されました。

TFカードリーダモジュール

前提

このサンプルでは、RP2040 / RP2350の内蔵温度モニタを読み取ります。
XIAO RP2040 / XIAO RP2350以外のXIAOシリーズでは動作しません。

説明

TFカードリーダモジュールを使います。
モジュールスロットにはFAT32フォーマット済みのTFカード(マイクロSDカード)を挿入します。

XIAO RP2040の内蔵温度モニタを読み出し、TFカードのファイルに保存します。

XIAO Extensionボードのユーザボタン(D1)の状態を読み取り、ボタンを押すごとにREC(記録)モードとSTOP(停止)モードを切り替えます。

REC(記録)の時はOLED画面左上にRECを表示し、TFカードに追記保存します。
STOP(停止)の時はOLED画面左上にSTOPを表示します。(TFカードに記録しません)

読み出した温度は常にOLED(SSD1306)に表示します。

※注意

TFカードのファイル破損予防のため、TFカードの取り出しはSTOP時に行います。

配線

配線不要です。

スケッチ

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#include <SPI.h>
#include <SD.h>

#define SCREEN_WIDTH    (128)
#define SCREEN_HEIGHT   (64)

#define OLED_RESET      (-1)
#define SCREEN_ADDRESS  (0x3C)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);


#define SD_CS           (D2)
#define BUTTON_PIN      (D1)

#define FILENAME "temperature.txt"
File myFile;

void setup()
{

  Serial.begin(115200); 
  
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  if (SD.begin(SD_CS, SPI) == false)
  {
    Serial.println("initialization failed.");
    while (1);
  }
  
  if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    for(;;);
  }
  display.clearDisplay();
   
  display.setTextSize(2);
  display.setTextColor(SSD1306_WHITE);
}

void loop()
{
  bool flagRecOn = false;
  bool flagButtonOn = false;

  while(1)
  {
    //チャタリング対策(ボタン2回の判定ともにOnでOn判定)
    bool stateButton = digitalRead(BUTTON_PIN);
    delay(10);
    stateButton &= digitalRead(BUTTON_PIN);
    
    //ボタンを押してから話したときに状態遷移
    if(stateButton == true)
    {
      flagButtonOn = true;
    }
    else
    {
      if(flagButtonOn == true)
      {
        flagRecOn = !flagRecOn;
      }
      flagButtonOn = false;
    }

    //温度サンプリング
    float Temp_degC = analogReadTemp();
    
    //モニタ表示
    display.clearDisplay();
    
    display.setTextSize(3);
    display.setCursor(30,20);
    display.printf("%2.1f", Temp_degC);
    display.setTextSize(2);
    display.setCursor(70,45);
    display.print("degC");
    display.setCursor(0,0);

    if(flagRecOn == true)
    {
      display.printf("REC");

      myFile = SD.open(FILENAME, FILE_WRITE);
      myFile.println(Temp_degC);
      myFile.close();
    }
    else
    {
      display.printf("STOP");
    }
    display.display();
    delay(100);  

  }
}

結果

赤丸のボタンを押すことでREC(記録)とSTOP(停止)を切り替えます。
画面左上のRECとSTOPが切り替わります。

温度は記録と停止の状態にかかわらず常に更新します。
画像の右下は読み取ったログファイルの内容です。

温度は読めていますが結構ばらついています。

コメント

タイトルとURLをコピーしました