Seeeduino XIAOの拡張ボードのOLEDを使用する

組み込みエンジニア

こんにちは、ENGかぴです。

Seeeduino XIAO用の拡張ボードはSDカードスロットやOLEDによる液晶画面での表示ができます。またGrove端子対応のセンサーモジュールを挿入して計測等ができます。OLEDにボタンの情報を表示して動作確認を行いました。

Seeeduino XIAO用拡張ボード(秋月電子)を使用しています。Seeeduino XIAOを使って動作確認を行ったことを下記リンクにまとめています。

Seeeduino XIAOで学べるソフト開発と標準ライブラリの使い方

Seeeduino XIAOの拡張ボード

Seeeduino XIAO専用の拡張ボードがSeeed Studioから製作されています。このボードを使用するとOLEDに文字を表示したりSDカードを使用したりGrove端子を利用してセンサーと接続することができます。Seeeduino XIAOを挿入したコネクタ横にも配線できるようにコネクタが実装されています。拡張ボードについては下記リンクに詳細が説明されています。

Seeeduino XIAO Expansion board

リンク先では言語選択で日本語が選択できるようになっていますがページが対応していないため日本語での表示はできません。日本語で表示したい場合はGoogle Chromeの翻訳機能を使うと日本語表示ができます。

上記リンクで紹介されているサンプル例を参考にしてOLEDに文字を表示する方法をまとめています。

OLED用のライブラリを追加する

OLEDに文字を表示するためにOLED用のライブラリを追加します。Seeed Wikiの使用例で追加されている「u8g2」ライブラリを追加して使用します。

ライブラリマネージャからu8g2ライブラリーを追加
ライブラリマネージャからu8g2ライブラリーを追加

Arduino IDEのツール内のライブラリを管理を選択するとライブラリマネージャ画面が表示されます。検索をフィルタに「u8g2」(大文字小文字はどちらでもよい)を入力すると表示される「U8g2」が候補として表示されます。インストールボタンを押すとライブラリが追加されます。

ライブラリの準備と初期化

#include <U8x8lib.h>
#include <Wire.h>
//U8X8_SSD1306_128X64_NONAME_SW_I2C型の変数を宣言
U8X8_SSD1306_128X64_NONAME_SW_I2C u8x8( SCL, SDA, U8X8_PIN_NONE);

void setup() {
  u8x8.begin(); //初期化
  u8x8.setFlipMode(1);   // set number from 1 to 3
  u8x8.setFont(u8x8_font_5x8_r); //フォントを選択
}

ライブラリを使用するためU8x8lib.hをインクルードします。OLEDへのアクセスはWire(I2C)を使用するためWire.hライブラリもインクルードします。

クラス宣言された型であるU8X8_SSD1306_128X64_NONAME_SW_I2Cのオブジェクト宣言としてu8x8を宣言してします。u8x8は各種メンバー関数を使用した際の管理を行う変数です。

ライブラリをインストールした際に対応するOLEDが記載されていますが、このクラス宣言を変更することで他のタイプのOLEDでもライブラリを使用することができます。

begin()関数を使用するとOLEDの初期化が行われます。setFlipMode()関数は1から3を引数に指定できます。画面の表示の向きを変更することができるようですが数値を変更しても表示が変わらなかったため未実装もしくは対応していない可能性があります。(解釈を間違っているかもしれません)

setFont()ではOLEDに表示する文字フォントを選択することができます。デフォルトではu8x8_font_5×8になっていますが、ライブラリの1文字あたり横5ドット縦8ドットの表示になります。

選択できるフォトンの種類はu8x8.hで確認できます。Arduino のライブラリが保存されているフォルダであるLibrariesからlibraries/U8g2/src/clib/u8x8.hのように階層を下っていくとファイルを見つけることができます。

テックジム-将来のためにプログラミングを学ぶ

ライブラリの使用例(文字を表示)

  u8x8.setCursor(0, 0);
  u8x8.print("Seeeduino OLED");
  u8x8.setCursor(0, 1);
  u8x8.print("       Ver1.00");

setCursor()で文字表示する座標を指定します。第1引数に行番号、第2引数に列番号を指定します。座標を指定した後はprint()関数で文字を書き込んで表示します。write()関数を使用すると配列に対して書き込むデータ数を指定することができます。

種別内容
SetCursor()データを書き込む初期位置(表示スタート位置)にカーソルを合わせます。
print()文字列を指定して書き込み(表示)ます。
clearLine()指定した列の文字をクリアします。
今回使用したメンバー関数

文字を同じ列に上書きして表示したい場合はclearLine()で上書き前の文字列を消してから表示します。

上書きする文字列が短い場合、文字が残ったまま上書きするため表示がおかしくなることがあります。文字列の長さを統一している場合はそのまま上書きしても問題になることはありません。

動作確認

動作確認用の回路図
動作確認用の回路図

Seeeduino XIAOをSeeeduino拡張ボードに挿入しSW1とSW2を実装します。DIはプルダウン付きのDIにしているためSW1/SW2を押したときにショートすることはありません。SW1/SW2を押したときOLEDにボタンが押されたことを示す「—>ON」を表示するようにします。ボタンを押していない時は「—>OFF」を表示します。

OLEDの動作結果
OLEDの動作結果

電源がONするとバージョン情報とボタンの情報が表示されました。SW2を押すとpush button:2の下の行が—>ONになることを確認しました。SW1の場合はpush button:1の下の行が—>ONになりました。

OLEDはドットが細かいので小さな文字からフォントサイズを変更して大きく見せたりと拡張性があるので複雑な表示を行いたい場合に効果を発揮しそうです。

LCDを使用した場合はフォントなどに拡張性はありませんがライブラリなどが複雑にならないため簡易的に表示したい場合は低価格のLCDの方が良いこともあります。

ソースコード全体

以下のソースコードはコンパイルして動作確認をしております。コメントなど細かな部分で間違っていたりやライブラリの更新などにより動作しなくなったりする可能性があります。参考としてお使いいただければと思います。

#include <U8x8lib.h>
#include <Wire.h>
#include <TimerTC3.h>

#define PIN_DI1 0
#define PIN_DI2 1
#define DIFILT_MAX 4
#define TIM_DIFILT 1
#define TIME_UP 0
#define TIME_OFF -1
#define BASE_CNT 10 //10msがベースタイマとなる

typedef struct DIFILT{
  uint8_t wp;
  uint8_t buf[DIFILT_MAX];
  uint8_t di;
};

int16_t timDifilter;
int8_t cnt10ms;
DIFILT diData[2];
bool flg[2];
 
U8X8_SSD1306_128X64_NONAME_SW_I2C u8x8( SCL, SDA, U8X8_PIN_NONE);

 /* Local function prototypes */
void mainTimer(void);
void DiFilter(void);
void TimerCnt();

void setup(void) {
  uint8_t i;

  u8x8.begin();
  u8x8.setFlipMode(1);   // set number from 1 to 3
  u8x8.setFont(u8x8_font_5x8_r);
  u8x8.setCursor(0, 0);
  u8x8.print("Seeeduino OLED");
  u8x8.setCursor(0, 1);
  u8x8.print("       Ver1.00");
  u8x8.setCursor(0, 3);
  u8x8.print("push button:1");
  u8x8.setCursor(0, 5);
  u8x8.print("push button:2");

  TimerTc3.initialize(1000);
  TimerTc3.attachInterrupt(TimerCnt);

  pinMode(PIN_DI1,INPUT_PULLDOWN);
  pinMode(PIN_DI2,INPUT_PULLDOWN);

  i=0;
  while( i < 10){
    mainTimer();
    DiFilter();
    delay(10);
    i++;
  }  
}
 
void loop(void) {

  mainTimer();
  DiFilter();

  if( diData[0].di == 1 ){
    if( flg[0] == false ){
      flg[0] = true;
      u8x8.setCursor(0, 4);
      u8x8.clearLine(4);
      u8x8.print("   --->ON");
    }
  }
  else{
    flg[0] = false;
    u8x8.setCursor(0, 4);
    u8x8.print("   --->OFF");
  }

  if( diData[1].di == 1 ){
    if( flg[1] == false ){
      flg[1] = true;
      u8x8.setCursor(0, 6);
      u8x8.clearLine(6);
      u8x8.print("   --->ON");
    }
  }
  else{
    flg[1] = false;
    u8x8.setCursor(0, 6);
    u8x8.print("   --->OFF");
  } 
}
/* callback function add */
void TimerCnt(){
  ++cnt10ms;
}
/* タイマ管理 */
void mainTimer(void){

  if( cnt10ms >= BASE_CNT ){
    cnt10ms -=BASE_CNT;
    //10msごとにここに遷移する
    if( timDifilter > TIME_UP ){
      timDifilter--;
    }
  }
}
/* DIフィルタ */
void DiFilter(void){
  bool boo = true;
  uint8_t i;

  if( timDifilter == TIME_UP ){
    timDifilter = TIM_DIFILT;

    diData[0].buf[diData[0].wp] = digitalRead(PIN_DI1);
    diData[1].buf[diData[1].wp] = digitalRead(PIN_DI2);

    for(uint8_t no=0; no < 2; no++){
      for( i=1; i < sizeof(diData[no].buf);i++){
        if( diData[no].buf[i - 1] != diData[no].buf[i]){
          boo = false;
        }
      }

      if(boo){ //データがすべて一致なので採用する
        diData[no].di = diData[no].buf[0];
      }
      if( ++diData[no].wp >= sizeof(diData[no].buf)){
        diData[no].wp = 0;
      }
    }
  }
}

関連リンク

Arduinoのライブラリを使って動作確認を行ったことを下記リンクにまとめています。

Arduinoで学べるマイコンのソフト開発と標準ライブラリの使い方

Seeeduino XIAOで学べるソフト開発と標準ライブラリの使い方

ESP32-WROOM-32Eで学べるソフト開発と標準ライブラリの使い方

自宅でカンタン資格取得 通信講座・通信資格の【ラーキャリ】

最後まで、読んでいただきありがとうございました。

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