M5Stack Core2 を買ったのでとりあえずボタンでLEDを点灯してみた(その1)

M5Stack は、GRAYを持っていたけど、買って早々になぜかディスプレーがつかなくなってしまった。
表示なしでは、問題無く動いているので、まぁ使えなくもないのだけれど、この度、Core2を買ってみた。

Core2は、タッチパネル式でボタンもなく、I/OもGROVEコネクタのピンが4本出ているだけで、それ以外は、ケースの中にあって蓋をはずさないと使えない構造になっています。
とりあえず、タッチパネルにボタンを表示してLEDをON/OFF してみました。
ボタンの作り方は、いろいろあるみたいでライブラリも新旧あるみたいだし、どれが正解なのかよくわからないけど、その時の気分で適当にやることにしてます。
今回は、BMPファイルを使って、ボタンのONの画像とOFFの画像を用意して、LEDをON/OFFしてみました。
LEDは、GROVE端子にでているG32のピンに1Kの抵抗を直列に入れてGNDとの間に入れてます。
M5StackにBMP画像を表示するにあたって、以下のサイトを参考にさせていただきました。
ねこめも
ここによると、LCD-image-converter と言うソフトを使えば、BMPのデータが作れるらしい。
データの作り方も詳しく説明してくれています。…たすかります!

以下、スケッチ

// Manpukukoji 2022/05/01

#include <M5Core2.h>
#include "pb80x80_16.h"

#define LED 32

unsigned int F_LED = 0;

void B_Button() {
  if (F_LED == 1) digitalWrite(LED,HIGH);
  else digitalWrite(LED,LOW); 
}

HotZone B_Btn(120,80,200,160);

void setup() {
  M5.begin();  //Init M5Core2.

  pinMode(LED,OUTPUT);
  digitalWrite(LED,LOW);
  M5.Lcd.setTextColor(YELLOW);  //Set the font color to yellow.
  M5.Lcd.setTextSize(1);  //Set the font size.
  M5.Lcd.drawBitmap(120,80,80,80,BB_OFF,0x2608);
}

void loop() {
  M5.update();
      TouchPoint_t pos = M5.Touch.getPressPoint();
      if(M5.Touch.ispressed()) {
        M5.Lcd.fillRect(290,10,30,30,BLACK);
        M5.Lcd.setCursor(290,10);
        M5.Lcd.print(pos.x);
        M5.Lcd.setCursor(290,20);
        M5.Lcd.print(pos.y);
      }
    if(B_Btn.inHotZone(pos)) {
        if(F_LED == 0) {    //Turn ON the LED and change button color when LED is OFF
          F_LED = 1;
          B_Button();
        M5.Lcd.drawBitmap(120,80,80,80,BB_ON,0x2608);
        delay(100);
        }
        else {             //Turn OFF the LED and change button color when LED is ON
          F_LED = 0;
          B_Button();          
        M5.Lcd.drawBitmap(120,80,80,80,BB_OFF,0x2608);
        delay(100);
        }
    }
 
}

ボタンを表示するためにBMPのデータが必要です。
データをこのページに載せたのですが、どうも、1ページのサイズに上限があるのか保存できないようですのでデータの前半部分をこのページに載せて、後半部分は、次のページに乗せることにします。

ボタンのデータの前半部分の以下のデータと、次のページの後半部分を一つにして、”pb80x80_16.h" というファイル名でスケッチと同じフォルダに保存しておく必要があります。
画像を変更したい場合には、上記の参考サイトを参考に、データを作成してみてください。
なんか、大したスケッチでもないのに、大げさなことになっちゃったな…。

#include <stdint.h>

static const uint16_t BB_OFF[6400] = {
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x4510, 0x6510, 0x8410, 0x8410, 0xa410, 0x8410, 0x8410, 0x8410, 0x8410, 0xa410, 0x8410, 0x8410, 0x6510, 0x4510, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x4508, 0x6510, 0x8410, 0x8410, 0x8410, 0x8310, 0x8410, 0x8410, 0xa514, 0xa514, 0xa514, 0xa514, 0xa514, 0xa514, 0x8410, 0x8410, 0x8310, 0x8410, 0x8410, 0x8410, 0x6510, 0x4508, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x6510, 0x8410, 0x8410, 0x8310, 0x8410, 0xc618, 0xc6f8, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xc6f8, 0xc618, 0x8410, 0x8310, 0x8410, 0x8410, 0x6510, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x6510, 0x8410, 0x8310, 0x8410, 0xc618, 0xffde, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffde, 0xc618, 0x8410, 0x8310, 0x8410, 0x6510, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x6510, 0x8410, 0x8310, 0x8410, 0xc6f8, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xc6f8, 0x8410, 0x8310, 0x8410, 0x6510, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x8410, 0x8410, 0x8410, 0xc6f8, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffde, 0x8410, 0x8410, 0x8410, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x4510, 0x8410, 0x8310, 0xc618, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xc618, 0x8310, 0x8410, 0x4510, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x6510, 0x8410, 0x8410, 0xffde, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffde, 0x8410, 0x8410, 0x6510, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x8410, 0x8410, 0xa514, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffde, 0xc6f8, 0xc618, 0xc618, 0xa514, 0xa514, 0xc618, 0xc618, 0xc6f8, 0xffde, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xa514, 0x8410, 0x8410, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x8410, 0x8310, 0xa514, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xc6f8, 0xa514, 0x8410, 0x8410, 0x8410, 0x8410, 0x8410, 0x8410, 0x8410, 0x8410, 0x8410, 0x8410, 0x8410, 0x8410, 0xa514, 0xc6f8, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xa514, 0x8310, 0x8410, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x8410, 0x8310, 0xc618, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xa514, 0x8410, 0x8410, 0x8410, 0x8410, 0x6318, 0x6318, 0x4318, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4318, 0x6318, 0x8410, 0x8410, 0x8410, 0x8410, 0xa514, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xc618, 0x8310, 0x8410, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x6510, 0x8410, 0xa514, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xa514, 0x8410, 0x8410, 0x8410, 0x6318, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x2218, 0x8418, 0xa518, 0x8418, 0x8418, 0x4318, 0x2118, 0x2218, 0x4218, 0x6318, 0x8410, 0x8410, 0x8410, 0xa514, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xa514, 0x8410, 0x6510, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x4510, 0x8410, 0xa514, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xc6f8, 0x8410, 0x8410, 0x8410, 0x4318, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0xa518, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xa65e, 0x8418, 0x4218, 0x2218, 0x4218, 0x8410, 0x8410, 0x8410, 0xc6f8, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xa514, 0x8410, 0x4510, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x8410, 0x8410, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xa514, 0x8410, 0x8410, 0x4318, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0xa518, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xa65e, 0x4218, 0x2218, 0x4318, 0x8410, 0x8410, 0xa514, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x8410, 0x8410, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x8410, 0x8310, 0xffde, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xa514, 0x8410, 0x8410, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0xa65e, 0xc618, 0xa65e, 0xffde, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xa65e, 0x2218, 0x4218, 0x8410, 0x8410, 0x8410, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffde, 0x8310, 0x8410, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x6510, 0x8410, 0xc618, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x8410, 0x8410, 0x6318, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x2218, 0x2218, 0x2218, 0x2218, 0x6318, 0xa518, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffde, 0x6318, 0x2218, 0x6318, 0x8410, 0x8410, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xc618, 0x8410, 0x6510, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x8410, 0x8410, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x8410, 0x8410, 0x6318, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x2218, 0x8418, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x8418, 0x2118, 0x6318, 0x8410, 0x8410, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x8410, 0x8410, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x6510, 0x8310, 0xffde, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xa514, 0x8410, 0x6318, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x2218, 0xa518, 0xffff, 0xffff, 0xffff, 0xffff, 0x8518, 0x2118, 0x6318, 0x8410, 0xa514, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xc6f8, 0x8310, 0x6510, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x8410, 0x8410, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xc6f8, 0x8410, 0x8410, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x2218, 0x6318, 0xffff, 0xffff, 0xffff, 0xffff, 0x8418, 0x2218, 0x8410, 0x8410, 0xc6f8, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x8410, 0x8410, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x6510, 0x8310, 0xc6f8, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x8410, 0x8410, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0xffde, 0xffff, 0xffff, 0xffff, 0x6318, 0x4218, 0x8410, 0x8410, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xc6f8, 0x8310, 0x6510, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x8410, 0x8410, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xa514, 0x8410, 0x4318, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0xffff, 0xffff, 0xffff, 0xffff, 0x2218, 0x4318, 0x8410, 0xa514, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x8410, 0x8410, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x4508, 0x8410, 0xc618, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x8410, 0x8410, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x6318, 0xffff, 0xffff, 0xffff, 0xa65e, 0x2218, 0x8410, 0x8410, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xc618, 0x8410, 0x4508, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x6510, 0x8310, 0xffde, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xa514, 0x8410, 0x4318, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x2218, 0xa518, 0xffff, 0xffff, 0xffff, 0x4218, 0x4218, 0x8410, 0xa514, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffde, 0x8310, 0x6510, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x8410, 0x8410, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x8410, 0x8410, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x2218, 0xffde, 0xffff, 0xffff, 0xa65e, 0x2218, 0x8410, 0x8410, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x8410, 0x8410, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x8410, 0xc618, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xc6f8, 0x8410, 0x6318, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x8418, 0xffff, 0xffff, 0xffff, 0x4218, 0x6318, 0x8410, 0xc6f8, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xc618, 0x8410, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x4510, 0x8410, 0xc6f8, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xa514, 0x8410, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x2218, 0xffff, 0xffff, 0xffff, 0x8418, 0x4218, 0x8410, 0xa514, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xc6f8, 0x8410, 0x4510, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x6510, 0x8310, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x8410, 0x8410, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0xa518, 0xffff, 0xffff, 0xa65e, 0x2218, 0x8410, 0x8410, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x8310, 0x6510, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x8410, 0x8410, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffde, 0x8410, 0x6318, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x6318, 0xffff, 0xffff, 0xffff, 0x2118, 0x6318, 0x8410, 0xffde, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x8410, 0x8410, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x8410, 0x8410, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xc6f8, 0x8410, 0x6318, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0xffff, 0xffff, 0xffff, 0x4318, 0x6318, 0x8410, 0xc6f8, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x8410, 0x8410, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0xa410, 0xa514, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xc618, 0x8410, 0x4318, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x2218, 0xffde, 0xffff, 0xffff, 0x6418, 0x4218, 0x8410, 0xc618, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xa514, 0xa410, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x8410, 0xa514, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xc618, 0x8410, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x2218, 0xa65e, 0xffff, 0xffff, 0x8418, 0x4218, 0x8410, 0xc618, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xa514, 0x8410, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x8410, 0xa514, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xa514, 0x8410, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x2218, 0xc618, 0xffff, 0xffff, 0xa518, 0x4218, 0x8410, 0xa514, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xa514, 0x8410, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x8410, 0xa514, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xa514, 0x8410, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0xa65e, 0xffff, 0xffff, 0x8418, 0x4218, 0x8410, 0xa514, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xa514, 0x8410, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x8410, 0xa514, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xc618, 0x8410, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0xa65e, 0xa518, 0x2218, 0x4218, 0x8410, 0xc618, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xa514, 0x8410, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0xa410, 0xa514, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xc618, 0x8410, 0x4318, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4318, 0x8410, 0xc618, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xa514, 0xa410, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x8410, 0x8410, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xc6f8, 0x8410, 0x6318, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x6318, 0x8410, 0xc6f8, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x8410, 0x8410, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x8410, 0x8410, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffde, 0x8410, 0x6318, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x6318, 0x8410, 0xffde, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x8410, 0x8410, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x6510, 0x8310, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x8410, 0x8410, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x8410, 0x8410, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x8310, 0x6510, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x4510, 0x8410, 0xc6f8, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xa514, 0x8410, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x8410, 0xa514, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xc6f8, 0x8410, 0x4510, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x8410, 0xc618, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xc6f8, 0x8410, 0x6318, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x6318, 0x8410, 0xc6f8, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xc618, 0x8410, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x8410, 0x8410, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x8410, 0x8410, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x8410, 0x8410, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x8410, 0x8410, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x6510, 0x8310, 0xffde, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xa514, 0x8410, 0x4318, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4318, 0x8410, 0xa514, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffde, 0x8310, 0x6510, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x4508, 0x8410, 0xc618, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x8410, 0x8410, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x8410, 0x8410, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xc618, 0x8410, 0x4508, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x8410, 0x8410, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xa514, 0x8410, 0x4318, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4318, 0x8410, 0xa514, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x8410, 0x8410, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x6510, 0x8310, 0xc6f8, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x8410, 0x8410, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x8410, 0x8410, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xc6f8, 0x8310, 0x6510, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x8410, 0x8410, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xc6f8, 0x8410, 0x8410, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x8410, 0x8410, 0xc6f8, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x8410, 0x8410, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x6510, 0x8310, 0xc6f8, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xa514, 0x8410, 0x6318, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x6318, 0x8410, 0xa514, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xc6f8, 0x8310, 0x6510, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x8410, 0x8410, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x8410, 0x8410, 0x6318, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x6318, 0x8410, 0xa514, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x8410, 0x8410, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x6510, 0x8410, 0xc618, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x8410, 0x8410, 0x6318, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x6318, 0x8410, 0x8410, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xc618, 0x8410, 0x6510, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x8410, 0x8310, 0xffde, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xa514, 0x8410, 0x8410, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x8410, 0x8410, 0x8410, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffde, 0x8310, 0x8410, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x8410, 0x8410, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xa514, 0x8410, 0x8410, 0x4318, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4318, 0x8410, 0x8410, 0xa514, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x8410, 0x8410, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x4510, 0x8410, 0xa514, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xc6f8, 0x8410, 0x8410, 0x8410, 0x4318, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4318, 0x8410, 0x8410, 0x8410, 0xc6f8, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xa514, 0x8410, 0x4510, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x6510, 0x8410, 0xa514, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xa514, 0x8410, 0x8410, 0x8410, 0x6318, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x4218, 0x6318, 0x8410, 0x8410, 0x8410, 0xa514, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xa514, 0x8410, 0x6510, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x8410, 0x8310, 0xc618, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xa514, 0x8410, 0x8410, 0x8410, 0x8410, 0x6318, 0x6318, 0x4318, 0x4218, 0x4218, 0x4218, 0x4218, 0x4318, 0x6318, 0x6318, 0x8410, 0x8410, 0x8410, 0x8410, 0xa514, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xc618, 0x8310, 0x8410, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x8410, 0x8310, 0xa514, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xc6f8, 0xa514, 0x8410, 0x8410, 0x8410, 0x8410, 0x8410, 0x8410, 0x8410, 0x8410, 0x8410, 0x8410, 0x8410, 0x8410, 0xa514, 0xc6f8, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xa514, 0x8310, 0x8410, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x8410, 0x8410, 0xa514, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffde, 0xc6f8, 0xc618, 0xc618, 0xa514, 0xa514, 0xc618, 0xc618, 0xc6f8, 0xffde, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xa514, 0x8410, 0x8410, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x6510, 0x8410, 0x8410, 0xffde, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffde, 0x8410, 0x8410, 0x6510, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x4510, 0x8410, 0x8310, 0xc618, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xc618, 0x8310, 0x8410, 0x4510, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x8410, 0x8410, 0x8410, 0xc6f8, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffde, 0x8410, 0x8410, 0x8410, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x6510, 0x8410, 0x8310, 0x8410, 0xc6f8, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xc6f8, 0x8410, 0x8310, 0x8410, 0x6510, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x6510, 0x8410, 0x8310, 0x8410, 0xc618, 0xffde, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffde, 0xc618, 0x8410, 0x8310, 0x8410, 0x6510, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x6510, 0x8410, 0x8410, 0x8310, 0x8410, 0xc618, 0xc6f8, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xc6f8, 0xc618, 0x8410, 0x8310, 0x8410, 0x8410, 0x6510, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x4508, 0x6510, 0x8410, 0x8410, 0x8410, 0x8310, 0x8410, 0x8410, 0xa514, 0xa514, 0xa514, 0xa514, 0xa514, 0xa514, 0x8410, 0x8410, 0x8310, 0x8410, 0x8410, 0x8410, 0x6510, 0x4508, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x4510, 0x6510, 0x8410, 0x8410, 0xa410, 0x8410, 0x8410, 0x8410, 0x8410, 0xa410, 0x8410, 0x8410, 0x6510, 0x4510, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 
    0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608, 0x2608
};

//**********************************************************************

リチウムイオン電池の充電器を作った

MCP73831というICを使って、リチウムイオン電池の充電器を作ってみた。

リチウムイオン電池充電器

リチウムイオン電池の充電は、コントロールが難しく、へたをすれば発火したり、爆発したりするので、やはり、専用ICに頼るしかない。
とは、いうものの、それでも素人工作なので、この記事を見て、真似してみようとか思わない方が良いです。
あくまでも、自己責任で…。
MCP73831を使った充電器の例は、あちこちのサイトに結構たくさん出ていて、説明されています。
ここで、作成したのも同じような回路で、データーシートのサンプルの回路とほぼ同じです。


ICも小さく、外付け部品も少ないので、フリスクのケースに組み込んでみました。
充電電流は、手持ちの電池に合わせて、ジャンパーピンで500mAと100mAの切り替えができるようにしています。
作ってから少し経つと、自分でもどんな仕様でどう使うのかすぐ忘れてしまうので、後でわかるように、ICの仕様を以下にメモしておきます。(間違いがあるかもしれませんが…。)

シャットダウンモード (UVLO : UnderVoltageLockOut)

  入力電圧がバッテリーの電圧+50mVより低くなると、シャットダウン。
  動作開始には、入力電圧がバッテリ電圧+150mV以上でないと動かない。

予備充電モード

  バッテリ電圧が4.2X71.5%=3.00Vより低い時には、予備充電モード(トリクル充電モード)になり設定電流の10%、つまり、設定した充電電流が500mAの時には、50mA、100mAのときには、10mAで充電される。

高速充電モード(定電流モード)

  バッテリー電圧が3.00Vよりも高くなると設定した充電電流で定電流充電される
  充電電流は、1000/PROGの抵抗値 で決まる

低電圧モード

  バッテリ電圧が4.2Vに達したら低電圧モードが開始される。

充電終了

  低電圧モードでの充電電流が設定充電電流(500mAと100mA)の20%以下になったら充電終了。

再充電モード

  バッテリ電圧が4.2VX94%=3.95V より低くなると再充電が開始される。

と、言うことのようです。

この通りだと、適当につないで充電しておけば、勝手に充電開始して、終了してくれるみたいですね。
こりゃ、なかなか良いかも…。

Wio TerminalをWiFi メッセージボードにしてみた

f:id:manpukukoji:20200929094429j:plain
普段、2階の自室にいる時、階下から ”ごはんできたよー!”とか、”お風呂沸いたよー!” とか知らせてくれてるんだけど、毎回、大声上げさせるのも申し訳ない。
と、言うわけで、キッチンからボタンをピッと押したら、2階のWioにパッとメッセージが表示されれば良いなと、思って、メッセージボードみたいなものを作ってみた。
仕組みは、ただのTCPのソケット通信でWioは、受信を待っていて、メッセージが入ったら、LEDを点灯してメッセージを表示するだけ。
今回は、M5Stackで送信し、Wioでメッセージを受信、表示しています。
メッセージは、”ごはんできたよー!” と、”おふろわいたよー!” の2つですが、いくらでも増やせます。 もちろん、送信側の送り方を工夫する必要がありますけど…。
スケッチは、ほとんど、サンプルプログラムのコピペでできちゃいますね。
このあたりが、Arduinoの開発環境のありがたいところで、たくさんの人がライブラリやサンプルを作ってくれているので、こちらは、ありがたく使わせていただくばかり。
恐悦至極でございます…。

Wio側のスケッチは、以下
Cボタンを押すとメッセージをクリアします。
今回も、LovyanGFXを使わせていただいています。
日本語を表示するのに、フォントの準備が必要です。
GitHub - Tamakichi/Arduino-misakiUTF16: Arduino用 美咲フォントライブラリ 教育漢字・内部フラッシュメモリ乗せ版
スケッチと同じフォルダに"mmisakiUTF16FontData.h" を置いておきます。

Wifi接続は、ご自分の環境にあわせて設定が必要です。 portは、とりあえず、5000でやってます。

#include <AtWiFi.h>
#include <LovyanGFX.hpp>
#include "misakiUTF16FontData.h"

static LGFX lcd;

// lgfx::BDFfontクラスを使って、Arduino-misakiUTF16を使用できるように設定します。
static constexpr lgfx::BDFfont misaki_font = 
  { fdata             // 第1引数 フォントのビットマップデータ
  , ftable            // 第2引数 unicodeフォントテーブル
  , sizeof(ftable)>>1 // 第3引数 フォントテーブルのサイズ
  , 8                 // 第4引数 フォント幅
  , 4                 // 第5引数 フォント幅 (半角)
  , 7                 // 第6引数 フォント高さ
  , 6                 // 第7引数 ベースライン高さ
  , 8                 // 第8引数 改行時の縦方向カーソル移動量
  };
 
const char* ssid = "Your SSID";
const char* password =  "Your Password";

WiFiServer server(5000);

String R_data;

void pipipi() {
  for (int i = 0; i<3; i++) { 
        analogWrite(WIO_BUZZER, 128);
        delay(700);
        analogWrite(WIO_BUZZER, 0);
        delay(100);
  }
}


void setup() {
    Serial.begin(115200);
    //while(!Serial); // Wait for Serial to be ready
    delay(10);
    
    pinMode(D2, OUTPUT);
    pinMode(WIO_KEY_C, INPUT_PULLUP);
    pinMode(WIO_BUZZER, OUTPUT);
    
    lcd.init();
    lcd.setFont(&misaki_font);
    lcd.setTextWrap(true, true);
    lcd.setTextColor(0xFFFF00U, 0x000000);
    lcd.setTextSize(3, 3);
 
    lcd.fillScreen(TFT_BLACK); //Red background
    
 
    // Set WiFi to station mode and disconnect from an AP if it was previously connected
    WiFi.mode(WIFI_STA);
    WiFi.disconnect();
    delay(2000);
 
    WiFi.begin(ssid, password);
 
    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.println("Connecting to WiFi..");
    }
    Serial.println("Connected to the WiFi network");
    Serial.print("IP Address: ");
    Serial.println (WiFi.localIP()); // prints out the device's IP address

    server.begin();

}
 
 
void loop() {
    WiFiClient client = server.available();
  if (client) {                             // if you get a client,
    Serial.println("New Client.");           // print a message out the serial port
    while (client.connected()) {            // loop while the client's connected
      while (client.available()) {             // if there's bytes to read from the client,
        String currentLine =client.readStringUntil('\n');  
        Serial.println(currentLine);  
        R_data = currentLine;  
        currentLine = "";                
          
          client.print(R_data);
    
        if (R_data=="AA") {
          lcd.drawString("ごはんできたよー! ", 10, 80);
          pipipi();
          digitalWrite(D2, HIGH);               
        }
        if (R_data==("BB")) {
          lcd.drawString("おふろ わいたよー!", 10, 80);
          pipipi();
          digitalWrite(D2, HIGH);               
        }
       R_data = "";
    }
    if (digitalRead(WIO_KEY_C) == LOW) {
      lcd.clear();
      digitalWrite(D2, LOW);
   }

    }
    // close the connection:
    client.stop();
    Serial.println("Client Disconnected.");
  }    
}    
    

そして、M5Stack側のスケッチは、以下

#include <M5Stack.h>
#include <WiFi.h>

const char* ssid     = "Your SSID";                   //Wifi のSSIDを設定
const char* password = "Your Password";     //Wifi のパスワード

String R_data;

void setup()
{
    M5.begin(true, false, true);
    
    Serial.begin(115200);

    delay(10);

    Serial.println();
    Serial.print("Connecting to ");
    Serial.println(ssid);

    WiFi.begin(ssid, password);

    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }

    Serial.println("");
    Serial.println("WiFi connected.");
    Serial.println("IP address: ");
    Serial.println(WiFi.localIP());
    
}

void loop(){
    const uint16_t port = 5000; // Default port
    const char* host = "xxx.xxx.xxx.xxx";  // Target Server IP Address

    Serial.print("Connecting to ");
    Serial.println(host);

    WiFiClient client;
    client.connect(host, port);

    while ( client.connected() ) {
      M5.update();
      if (M5.BtnA.wasReleased()) {
        client.print("AA\n");
        Serial.println("AA sent");
      }
      if (M5.BtnB.wasReleased()) {
        client.print("BB\n");
        Serial.println("BB sent");
      }

    }
 
    Serial.println("Closing connection.");
    client.stop();
 
    Serial.println("Waiting 5 seconds before restarting...");
    delay(5000);
}
 

Wio Terminal のIMUでProcessingのモデルをぐりぐりしてみた。

f:id:manpukukoji:20200928183049j:plain
前回、M5Stackで3Dモデルをグリグリしたのに味を占めて、Wio terminal でもやってみました。
M5では、Bluetoothのシリアル接続でIMUのデータをProcessingにアップしていましたけど、今回は、WiFiを通して、TCPのソケット通信で加速度センサーのデータをアップしています。
また、Wio terminalには、ジャイロセンサーは、ついていないので、加速度センサーのみでのグリグリになります。
したがって、Pitch方向とRoll方向には、動かせるけど、Yaw方向は動かせません。
また、ぐるっと180度反転したときに、Z軸の富豪の反転で、180度反転したことはわかるのですが、Pitch方向で反転したのか、Roll方向で反転したのか判別できないように思います。
このあたり、何かやり方があるのかな…?
なんか、手探り状態ですが、一応、グリグリは、できたので、記録代わりに置いておきます。

WioTerminal側のスケッチは、以下
もし、追試される方があるようでしたら、ご自分の環境に合わせて、WiFiSSIDとPassword を設定してください。 また、サーバーとなるPCのIPアドレスも設定が必要です。Portは、とりあえず、20000にしていますが、これも、必要に応じて好きなポートに設定してくださいね。
お約束ですが、何かあっても責任はとれませんので、あくまでも自己責任で…。
と、いうのも、先日、M5Stackででっかい画像データを転送して、表示させようとしたら、いきなり、TFTが壊れてしまったようで、何も表示されなくなってしまいました。
なにも、ハード的に何か触ったわけでもないので、まさか、そんなことで壊れるわけはないと思っていたのですが、まぁ、そんなことも起こったりするので、念のため、リスクは、ご自分で管理ください。

#include <AtWiFi.h>
#include"LIS3DHTR.h"
#include "TFT_eSPI.h"
#include <math.h>

LIS3DHTR<TwoWire> lis;
TFT_eSPI tft;

const char* ssid = "your SSID";
const char* password =  "your password";
 
void setup() {
    Serial.begin(115200);
    //while(!Serial); // Wait for Serial to be ready
    delay(1000);
    //Display setup
    tft.begin();
    tft.setRotation(3);
    tft.setTextColor(TFT_YELLOW);
    tft.setTextSize(2);
    tft.fillScreen(TFT_BLACK);
    
    //Accerometer setup
    lis.begin(Wire1);
 
    if (!lis) {
      Serial.println("ERROR");
      while(1);
    }
    lis.setOutputDataRate(LIS3DHTR_DATARATE_25HZ); //Data output rate
    lis.setFullScaleRange(LIS3DHTR_RANGE_2G); //Scale range set to 2g

    // Set WiFi to station mode and disconnect from an AP if it was previously connected
    WiFi.mode(WIFI_STA);
    WiFi.disconnect();
    delay(2000);
 
    WiFi.begin(ssid, password);
 
    tft.println("Connecting to WiFi");
    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.println("Connecting to WiFi..");
        tft.print(".");
    }
    Serial.println("Connected to the WiFi network");
    Serial.print("IP Address: ");
    Serial.println (WiFi.localIP()); // prints out the device's IP address
    tft.print("\n");
    tft.println(WiFi.localIP());
}
 
 
void loop() {
    const uint16_t port = 20000;  // Default port
    const char* host = "XXX.XXX.XX.XX";  // Target Server IP Address

    String ss;
    
    Serial.print("Connecting to ");
    Serial.println(host);
 
    // Use WiFiClient class to create TCP connections
    WiFiClient client;
    Serial.println("client created");
    tft.println("client created");
    
    client.connect(host, port);
    Serial.println("client connected");
    tft.println("client connected");
    while ( client.connected() ) {

      // Get acceleration data
      float x_values, y_values, z_values, x_angle, y_angle;
      
      x_values = lis.getAccelerationX();
      y_values = lis.getAccelerationY();
      z_values = lis.getAccelerationZ();

      x_angle = asin(x_values);
      y_angle = asin(y_values);
      
      ss=String(x_angle) + " " + String(y_angle) + " " + String(z_values) + "\n" ;
      client.print(ss);
      delay(100);
    }
 
    Serial.println("Closing connection.");
    client.stop();
 
    Serial.println("Waiting 5 seconds before restarting...");
    delay(5000);
}

Processing 側のプログラムは、以下です。
600X480X100の直方体に6面の画像を張り付けています。 画像は、プログラムと同じフォルダに別途用意する必要があります。クオリティは、悪いですが、自前で用意するのが面倒な方は、以下の画像をどうぞ。
front.jpg
back.jpg
top.jpg
bottom.jpg
right.jpg
left.jpg

import processing.net.*;

Server server;
PImage front, back, right, left, top, bottom;

float PI = 3.1415;
float rotationY = 0.0;

void setup() {
  server = new Server(this, 20000);
  
  size(800, 600, P3D);
  front = loadImage("front.jpg");
  back = loadImage("back.jpg");
  right = loadImage("right.jpg");
  left = loadImage("left.jpg");
  top = loadImage("top.jpg");
  bottom = loadImage("bottom.jpg");
  textureMode(IMAGE);
}
  //float rotationZ=0;

void draw() {
  
  // TCP comm and IMU data
  Client c = server.available();
    if (c != null) {
      String s = c.readStringUntil('\n'); 
      println("server received: " + s);
      String[] ss = splitTokens(s);
      float pitch = float(ss[0]);
      if(Float.isNaN(pitch)) pitch = 1.57;
      float roll = float(ss[1]);
      if(Float.isNaN(roll)) roll = -1.57;
      float z_value = float(ss[2]);
      println("x=" + pitch);
      println("y=" + roll);
      println("z=" + z_value);
      if(z_value>0) {
        pitch = -PI/2-(PI/2 + pitch); 
        //roll = -PI/2-(PI/2 + roll); 
      }    

  // Graphic
  background(0);
  translate(width / 2, height / 2);
  scale(0.4);

  pushMatrix();
  if(mousePressed) {rotationY = map(mouseX, 0, width, -PI, PI); }
  
  rotateX(-1*pitch);
  rotateY(rotationY);
  rotateZ(-1*roll);
  drawWio();
  popMatrix();
    }
}

void drawWio() {
  
  beginShape();
  texture(front);
  vertex(-300, -50, -240,   0,   0); //V1
  vertex( 300, -50, -240, 600,   0); //V2
  vertex( 300, -50,  240, 600, 480); //V3
  vertex(-300, -50,  240,   0, 480); //V4
  endShape();

  beginShape();
  texture(back);
  vertex( 300,  50, -240,   0,   0); //V1
  vertex(-300,  50, -240, 600,   0); //V2
  vertex(-300,  50,  240, 600, 480); //V3
  vertex( 300,  50,  240,   0, 480); //V4
  endShape();

  beginShape();
  texture(right);
  vertex( 300,  -50,  240,   0,   0); //V1
  vertex( 300,   50,  240,   0, 100); //V2
  vertex( 300,   50, -240, 480, 100); //V3
  vertex( 300,  -50, -240, 480,   0); //V4
  endShape();

  beginShape();
  texture(left);
  vertex(-300,  -50, -240,   0,   0); //V1
  vertex(-300,  -50,  240, 480,   0); //V2
  vertex(-300,   50,  240, 480, 100); //V3
  vertex(-300,   50, -240,   0, 100); //V4
  endShape();

  beginShape();
  texture(top);
  vertex( 300,   50, -240,   0,   0); //V1
  vertex(-300,   50, -240, 600,   0); //V2
  vertex(-300,  -50, -240, 600, 100); //V3
  vertex( 300,  -50, -240,   0, 100); //V4
  endShape();

  beginShape();
  texture(bottom);
  vertex(-300,  -50,  240,   0,   0); //V1
  vertex( 300,  -50,  240, 600,   0); //V2
  vertex( 300,   50,  240, 600, 100); //V3
  vertex(-300,   50,  240,   0, 100); //V4
  endShape();
  
}

実行する際は、先にProcessing の方を実行してからWioTerminalを立ち上げると行けると思います。

M5Stack のIMUでProcessingのモデルをぐりぐりしてみた。

f:id:manpukukoji:20200928124118j:plain
スイッチサイエンスのサイトにM5Stackの3DモデルをM5の動きに合わせて動かすサイトがあって、
pages.switch-science.com

面白いなぁ~と思い、自分もグリグリやってみたいなぁと思ったんですが、あいにく、IMUのチップがサイトのものと違っていました。
自分のは、IMU6886+BMM150のようで、サイトのスケッチそのままでは、動かないみたいです。
幸い、BMM150のサンプルプログラムも出ていたので、これと組み合わせて同じことをやってみました。
なんとか、同じようにできることはできたのですが、どうも、ジャイロの値が安定しない。
キャリブレーションもやってみたのだけど、いまいち。
何か、プログラムが悪いのかなぁ~? あるいは、こんなもん? またまた、はずれセンサーを引いちゃった?
まぁ、今後の参考までに、とりあえず、スケッチを置いておこう。
M5側のスケッチを置き換えるだけで、後は、Processingなどの部分は、上記のサイトと全く同じでグリグリできるようになると思います。
ちなみに、表示部分は、自分のM5のTFTがある日突然オシャカになってしまったので、ちゃんと確認できてませんので、なんか、変かも…。

#define M5STACK_MPU6886 

#include <Arduino.h>
#include <Wire.h>
#include "Preferences.h"
#include "M5Stack.h"
#include "math.h"
#include "bmm150.h"
#include "bmm150_defs.h"
#include <MadgwickAHRS.h>
#include "BluetoothSerial.h"

Preferences prefs;
BluetoothSerial SerialBT;
Madgwick filter;
unsigned long microsPerReading, microsPrevious;

struct bmm150_dev dev;
bmm150_mag_data mag_offset;
bmm150_mag_data mag_max;
bmm150_mag_data mag_min;
TFT_eSprite img = TFT_eSprite(&M5.Lcd);

float accX = 0.0F, accY = 0.0F, accZ = 0.0F;
float gyroX = 0.0F, gyroY = 0.0F, gyroZ = 0.0F;
float pitch = 0.0F, roll = 0.0F, yaw = 0.0F;

float accOffset[3];
float gyroOffset[3];

#define INTERVAL  5
float rolls[INTERVAL], pitchs[INTERVAL], yaws[INTERVAL];
int ma_idx = 0; // moving average index


int8_t i2c_read(uint8_t dev_id, uint8_t reg_addr, uint8_t *read_data, uint16_t len)
{
    if(M5.I2C.readBytes(dev_id, reg_addr, len, read_data))
    {
        return BMM150_OK;
    }
    else
    {
        return BMM150_E_DEV_NOT_FOUND;
    }
}

int8_t i2c_write(uint8_t dev_id, uint8_t reg_addr, uint8_t *read_data, uint16_t len)
{
    if(M5.I2C.writeBytes(dev_id, reg_addr, read_data, len))
    {
        return BMM150_OK;
    }
    else
    {
        return BMM150_E_DEV_NOT_FOUND;
    }
}

int8_t bmm150_initialization()
{
    int8_t rslt = BMM150_OK;

    /* Sensor interface over SPI with native chip select line */
    dev.dev_id = 0x10;
    dev.intf = BMM150_I2C_INTF;
    dev.read = i2c_read;
    dev.write = i2c_write;
    dev.delay_ms = delay;

    /* make sure max < mag data first  */
    mag_max.x = -2000;
    mag_max.y = -2000;
    mag_max.z = -2000;

    /* make sure min > mag data first  */
    mag_min.x = 2000;
    mag_min.y = 2000;
    mag_min.z = 2000;

    rslt = bmm150_init(&dev);
    dev.settings.pwr_mode = BMM150_NORMAL_MODE;
    rslt |= bmm150_set_op_mode(&dev);
    dev.settings.preset_mode = BMM150_PRESETMODE_ENHANCED;
    rslt |= bmm150_set_presetmode(&dev);
    return rslt;
}

void bmm150_offset_save()
{
    prefs.begin("bmm150", false);
    prefs.putBytes("offset", (uint8_t *)&mag_offset, sizeof(bmm150_mag_data));
    prefs.end();
}

void bmm150_offset_load()
{
    if(prefs.begin("bmm150", true))
    {
        prefs.getBytes("offset", (uint8_t *)&mag_offset, sizeof(bmm150_mag_data));
        prefs.end();
        Serial.printf("bmm150 load offset finish.... \r\n");
    }
    else
    {
        Serial.printf("bmm150 load offset failed.... \r\n");
    }
}

void setup() 
{
    M5.begin(true, false, true, false);
    M5.Power.begin();
    
    M5.IMU.Init();
    Serial.begin(115200);
    Wire.begin(21, 22, 400000);
    SerialBT.begin("M5Stack");

    filter.begin(10); // 10Hz filterを初期化する
    microsPerReading = 1000000 / 10;
    microsPrevious = micros();
    
    img.setColorDepth(1);
    img.setTextColor(TFT_WHITE);
    img.createSprite(320, 240);
    img.setBitmapColor(TFT_WHITE, 0);

    if(bmm150_initialization() != BMM150_OK)
    {
        img.fillSprite(0);
        img.drawCentreString("BMM150 init failed", 160, 110, 4);
        img.pushSprite(0, 0);
        for(;;)
        {
            delay(100);
        }
    }

    bmm150_offset_load();

    for (int i = 0; i<INTERVAL; i++) {
      rolls[i] = 0;
      pitchs[i] = 0;
      yaws[i] = 0;
    }

}

void bmm150_calibrate(uint32_t calibrate_time)
{

        img.fillSprite(0);
        img.drawCentreString("Flip + rotate core calibration", 160, 110, 4);
        img.pushSprite(0, 0);

    uint32_t calibrate_timeout = 0;

    calibrate_timeout = millis() + calibrate_time;
    Serial.printf("Go calibrate, use %d ms \r\n", calibrate_time);
    Serial.printf("running ...");

    while (calibrate_timeout > millis())
    {
        bmm150_read_mag_data(&dev);
        if(dev.data.x)
        {
            mag_min.x = (dev.data.x < mag_min.x) ? dev.data.x : mag_min.x;
            mag_max.x = (dev.data.x > mag_max.x) ? dev.data.x : mag_max.x;
        }

        if(dev.data.y)
        {
            mag_max.y = (dev.data.y > mag_max.y) ? dev.data.y : mag_max.y;
            mag_min.y = (dev.data.y < mag_min.y) ? dev.data.y : mag_min.y;
        }

        if(dev.data.z)
        {
            mag_min.z = (dev.data.z < mag_min.z) ? dev.data.z : mag_min.z;
            mag_max.z = (dev.data.z > mag_max.z) ? dev.data.z : mag_max.z;
        }
        delay(100);
    }

    mag_offset.x = (mag_max.x + mag_min.x) / 2;
    mag_offset.y = (mag_max.y + mag_min.y) / 2;
    mag_offset.z = (mag_max.z + mag_min.z) / 2;
    bmm150_offset_save();

    Serial.printf("\n calibrate finish ... \r\n");
    Serial.printf("mag_max.x: %.2f x_min: %.2f \t", mag_max.x, mag_min.x);
    Serial.printf("y_max: %.2f y_min: %.2f \t", mag_max.y, mag_min.y);
    Serial.printf("z_max: %.2f z_min: %.2f \r\n", mag_max.z, mag_min.z);
}

void calibrate6886(){
  M5.Lcd.println("calibrate6886");
  float gyroSum[3];
  float accSum[3];
  int counter = 500;
  for(int i = 0; i < counter; i++){
    M5.IMU.getGyroData(&gyroX,&gyroY,&gyroZ);
    M5.IMU.getAccelData(&accX,&accY,&accZ);
    gyroSum[0] += gyroX;
    gyroSum[1] += gyroY;
    gyroSum[2] += gyroZ;
    accSum[0] += accX;
    accSum[1] += accY;
    accSum[2] += accZ;
    delay(2);
  }
  gyroOffset[0] = gyroSum[0]/counter;
  gyroOffset[1] = gyroSum[1]/counter;
  gyroOffset[2] = gyroSum[2]/counter;
  accOffset[0] = accSum[0]/counter;
  accOffset[1] = accSum[1]/counter;
  accOffset[2] = (accSum[2]/counter);
}



void loop() 
{
  if (micros() - microsPrevious >= microsPerReading) {
// ----------------- Accl / Gyro -------------------
    M5.IMU.getGyroData(&gyroX,&gyroY,&gyroZ);
    M5.IMU.getAccelData(&accX,&accY,&accZ);
    //M5.IMU.getAhrsData(&pitch,&roll,&yaw);

    gyroX -= gyroOffset[0];
    gyroY -= gyroOffset[1];
    gyroZ -= gyroOffset[2];
  
    accX -= accOffset[0];
    accY -= accOffset[1];
    accZ -= accOffset[2]-1.0;
  
    filter.updateIMU(gyroX, gyroY, gyroZ, accX, accY, accZ );
        rolls[ma_idx % INTERVAL] = filter.getRoll();
        pitchs[ma_idx % INTERVAL] = filter.getPitch();
        yaws[ma_idx % INTERVAL] = filter.getYaw();
        ma_idx++;
        if((ma_idx % INTERVAL) == 0) ma_idx = 0;

        float roll = 0.0;
        float pitch = 0.0;
        float yaw = 0.0;
        for (int i = 0; i < INTERVAL; i++) {
            roll += rolls[i];
            pitch += pitchs[i];
            yaw += yaws[i];
        }
        roll /= INTERVAL;
        pitch /= INTERVAL;
        yaw /= INTERVAL;

// ----------------- magnet ------------------------  
      char text_string[100];
      M5.update();
      bmm150_read_mag_data(&dev);
      float head_dir = atan2(dev.data.x -  mag_offset.x, dev.data.y - mag_offset.y) * 180.0 / M_PI;

      
        img.fillSprite(0);
    
        sprintf(text_string, "Gyro: %.2f  %.2f  %.2f", gyroX, gyroY, gyroZ);
        img.drawString(text_string, 10, 20, 4);
        sprintf(text_string, "Accel: %.2f  %.2f  %.2f", accX, accY, accZ);
        img.drawString(text_string, 10, 50, 4);
        sprintf(text_string, "P/R/Y: %.2f  %.2f  %.2f",pitch, roll, yaw);
        img.drawString(text_string, 10, 80, 4); 
        Serial.printf("%6.2f, %6.2f, %6.2f\r\n", roll, pitch, yaw);
        SerialBT.printf("%6.2f, %6.2f, %6.2f\r\n", roll, pitch, yaw);
        sprintf(text_string, "HEAD Angle: %.2f", head_dir);
        img.drawString(text_string, 10, 110, 4);
    
        img.drawCentreString("Press BtnA enter calibrate", 160, 150, 4);
        img.pushSprite(0, 0);
      
      if(M5.BtnA.wasPressed())
      {
          img.fillSprite(0);
          img.drawCentreString("Keep Stable - Gyro Accel calibration", 160, 110, 4);
          img.pushSprite(0, 0);
          calibrate6886();
          bmm150_calibrate(10000);
      }

      microsPrevious = microsPrevious + microsPerReading;
  }  
}

WioTerminalでドーナツをぐりぐりしてみた。

Wio Terminal でドーナツの形を立体表示させて、グリグリと動かしてみた。
f:id:manpukukoji:20200903142549j:plain
ドーナツの形は、トーラスと言って、平面に描いた円を軸の周りにぐるっと一周させるとできます。
これを数式で表すと以下のように書けます。

     x = (a + r*cos(θ) ) * cos(φ)
     y = (a + r*cos(θ) ) * sin(φ)
     z = r*sin(θ)

とりあえず、どんな形になるか見てみるには、Pythonでちゃちゃっとやると確認できます。
こんな感じですね。
f:id:manpukukoji:20200903142629j:plain

from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np

fig = plt.figure(figsize=(6,6))
ax = fig.add_subplot(111, projection='3d')

u=np.linspace(0,2*np.pi,100)
v=np.linspace(0,2*np.pi,100)
u,v=np.meshgrid(u,v)
a = 2
b = 9
X = (b + a*np.cos(u)) * np.cos(v)
Y = (b + a*np.cos(u)) * np.sin(v)
Z = a * np.sin(u)

ax.set_xlim(-7,7)
ax.set_ylim(-7,7)
ax.set_zlim(-7,7)

ax.plot_surface(X, Y, Z,alpha=0.8, cmap=cm.Wistia)

plt.show()

グリグリするだけなら、このままマウスで動かせば、これで十分ですが、せっかくなので、Wio Terminalでやってみました。
Pythonですと、matprotlib や、numpy がちゃんと処理してくれるのですが、Wioでやるには、視点を設定したり、3D座標から2D座標に投影したり、ちょっと、手間をかけなければなりません。
で、いろいろ、調べながら、以下のように仕上がりました。
Wioでグリグリするには、
A, B, C, ボタンを押しながら、5ボタンの上下を押すと、X軸、Y軸、Z軸、まわりにドーナツが回転します。
A, B, C, ボタンを押さずに、5ボタンの上下を押すと、視点の仰角が変わります。また、この時、左右を押すと視点が回ります。
また、5ボタンを押すと視点がドーナツに近づいていきます。そのまま、ドーナツを通り過ぎると、遠ざかっていきます。
Cボタンを押しながら、5ボタンを押すと、逆に、ズーム、パンします。
ま、説明するよりやってみた方が早いですね。

#include <LovyanGFX.hpp>
#include <math.h>

static LGFX lcd;
static LGFX_Sprite torus(&lcd);

float pi=3.141592;
static auto transpalette = 0;          

float r = 2.0;    // ドーナツの太さ
float a = 5.0;    // ドーナツの大きさ
float x, y, z, x01, y01, z01, x02, y02, xv, yv,zv;
float xa,ya,za,xb,yb,zb,xg,yg,zg;
float phi = 0.0 / 180.0 * pi;   // 仰角
float theta = 0.0 / 180.0 * pi; // 回転角
float distance = 100.0;         // 視点までの距離
float alpha = 0.0, beta = 0.0, gmma = 0.0;   //ドーナツの傾き
float dg_p = 0.0, dg_t = 0.0;   // 仰角と回転角の度数(deg)

void disp_shape() {
  xv = distance * cos(phi) * cos(theta);
  yv = distance * cos(phi) * sin(theta);
  zv = distance * sin(phi) ;

  //Serial.printf("xv:%3.2f, yv:%3.2f, zv:%3.2f \n", xv,yv,zv);
  torus.clear(); 
  for (float i = 0.0; i<5*pi; i+=0.1) {    
    for (float j = 0.0; j<2*pi; j+=0.1) {

      //torus
    x = (a + r*cos(j) ) * cos(i)+2;
    y = (a + r*cos(j) ) * sin(i);
    z = r*sin(j);

      //x軸傾き
      xa = x;
      ya = y*cos(alpha) - z*sin(alpha);
      za = y*sin(alpha) + z*cos(alpha);

      //y軸傾き
      xb = xa*cos(beta) + za*sin(beta);
      yb = ya;
      zb = -xa*sin(beta) + za*cos(beta);

      //z軸傾き
      xg = xb*cos(gmma) - yb*sin(gmma);
      yg = xb*sin(gmma) + yb*cos(gmma);
      zg = zb;

      //
      x = xg;
      y = yg;
      z = zg;
      
      x01 = -sin(theta)*(x-xv) + cos(theta)*(y-yv);
      y01 = -sin(phi)*cos(theta)*(x-xv) - sin(phi)*sin(theta)*(y-yv) + cos(phi)*(z-zv);
      z01 = -cos(phi)*cos(theta)*(x-xv) - cos(phi)*sin(theta)*(y-yv) - sin(phi)*(z-zv);
      x02 = x01*100.0/z01;
      y02 = y01*100.0/z01;
     
      torus.drawPixel(x02*10+160,y02*10+120,1);
    }
  }
  
  torus.pushSprite(0,0);

  
}

void setup() {
  lcd.init();
  lcd.setRotation(1);
  lcd.setBrightness(64);
  lcd.setColorDepth(16);
  lcd.clear(); 

  torus.setColorDepth(lgfx::palette_4bit);
  torus.createSprite(lcd.width(), lcd.height());
  torus.setPaletteColor(1, 0, 0, 255);
  
  pinMode(WIO_5S_UP, INPUT_PULLUP);
  pinMode(WIO_5S_DOWN, INPUT_PULLUP);
  pinMode(WIO_5S_LEFT, INPUT_PULLUP);
  pinMode(WIO_5S_RIGHT, INPUT_PULLUP);
  pinMode(WIO_5S_PRESS, INPUT_PULLUP);
  pinMode(WIO_KEY_A, INPUT_PULLUP);
  pinMode(WIO_KEY_B, INPUT_PULLUP);
  pinMode(WIO_KEY_C, INPUT_PULLUP);

  disp_shape();
}

void loop() {

   if ((digitalRead(WIO_5S_PRESS) == LOW)and (digitalRead(WIO_KEY_C) == HIGH)) {
    distance -= 10.0;
    disp_shape();   
   }

   else if ((digitalRead(WIO_5S_PRESS) == LOW) and (digitalRead(WIO_KEY_C) == LOW)) {
    distance += 10.0;
    disp_shape();   
   }

   else if ((digitalRead(WIO_5S_UP) == LOW) and (digitalRead(WIO_KEY_C) == LOW)) {
    alpha = alpha+5.0/180.0*pi;
    disp_shape();
   }

   else if ((digitalRead(WIO_5S_DOWN) == LOW) and (digitalRead(WIO_KEY_C) == LOW)) {
    alpha -= 5.0/180.0*pi;
    disp_shape();
   }

   else if ((digitalRead(WIO_5S_UP) == LOW) and (digitalRead(WIO_KEY_B) == LOW)) {
    beta += 5.0/180.0*pi;
    disp_shape();
   }

   else if ((digitalRead(WIO_5S_DOWN) == LOW) and (digitalRead(WIO_KEY_B) == LOW)) {
    beta -= 5.0/180.0*pi;
    disp_shape();
   }

   else if ((digitalRead(WIO_5S_UP) == LOW) and (digitalRead(WIO_KEY_A) == LOW)) {
    gmma += 5.0/180.0*pi;
    disp_shape();
   }

   else if ((digitalRead(WIO_5S_DOWN) == LOW) and (digitalRead(WIO_KEY_A) == LOW)) {
    gmma -= 5.0/180.0*pi;
    disp_shape();
   }
   else if ((digitalRead(WIO_5S_UP) == LOW) and (digitalRead(WIO_KEY_A) == HIGH) and (digitalRead(WIO_KEY_B) == HIGH) and (digitalRead(WIO_KEY_C) == HIGH)) {
    phi = float(dg_p+=10.0) / 180.0 * pi;
    if(dg_p>360)dg_p-=360;
    disp_shape();
   }
   
   else if ((digitalRead(WIO_5S_DOWN) == LOW) and (digitalRead(WIO_KEY_A) == HIGH) and (digitalRead(WIO_KEY_B) == HIGH) and (digitalRead(WIO_KEY_C) == HIGH)) {
    phi = float(dg_p-=10.0) / 180.0 * pi;
    disp_shape();
   }
   
   else if (digitalRead(WIO_5S_LEFT) == LOW) {
    theta = float(dg_t+=10.0) / 180.0 * pi;
    if(dg_t>360)dg_t-=360;
    disp_shape();
   }
   
   else if (digitalRead(WIO_5S_RIGHT) == LOW) {
    theta = float(dg_t-=10.0) / 180.0 * pi;
    disp_shape();
   }

}

WioTerminal と DHT11 で温湿度計 その2

前回記事であまりにも、ちゃちゃっと済ましてしまったので、もう少し、時間をかけてみた。
f:id:manpukukoji:20200821161526j:plain
簡単にできることは、簡単に済ましてしまえば、良いと思いますが、まぁ、勉強も兼ねて、DHT11のセンサのデータシート片手にプログラムやり直してみました。
ほとんど、自己満足の世界です。
せっかくなので、表示画面ももう少しそれっぽく改良?
画面は、LovyanGFX のライブラリを使って、ライブラリのサンプルのメータを参考にさせていただいています。

DHT11

DHT11は、Arduino用のライブラリもあり、比較的安価なので、広く利用されているようで、ラズパイの例も含めて、使用例のサイトも沢山見かけます。
秋月の販売サイトからデータシートが見れたので、これをもとに自前で通信を試みてみました。
と、言ってもたいしたことではなく、通信ピンのHIGH / LOW の時間をみて、ビットの 0/1 を決めるだけです。
データシートによると、
約20msecの間、マイコン側でLOWにしてやると、センサからレスポンスがあった後、40ビットのデータが返ってきます。
40ビットは、8ビットずつの5つのデータに分けられていて、それぞれ、
湿度データHigh + 湿度データLow + 温度データHigh + 温度データLow + チェックサム
の構成で、データシートには、以下のように
8bit humidity integer data + 8bit humidity decimal data + 8bit temperature integer data + 8bit temperature decimal data + 8bit check bit.
と書いてあったので、Low のデータには、小数部分がくるのかと思ったのですが、
どうも、ここは、常にゼロのようで、このセンサでは、温度も、湿度も、小数部分は、測定できないのではないかと思います。
温度データLowの部分は、氷点下の場合に何か、ビットが立つようなことも書いてありましたが、氷点下のテストは、やっていませんので、定かではありません。
データビットの判定は、High の時間が、23マイクロ秒から27マイクロ秒のときは、ゼロ。
Highの時間が、68マイクロ秒から74マイクロ秒のときが、1 になります。
が、チェックサムエラーが何度か起きたので、調べてみたら、”1” なのに、67マイクロ秒とか、66マイクロ秒のときがあったので、”1” の判定の範囲を少し広めにして、エラーを回避しています。

表示部分

今回もLovyanGFXのライブラリにお世話になっています。
ライブラリのサンプルにメータがあったので、それを参考に(結構コピペしてます)温度、湿度の表示をしてみました。
センサからは、整数値が2つ出てくるだけですが、表示部をそれなりに手間をかけてやると、少ない情報量でもそれっぽくなりますね。

と、言うわけで、以下スケッチです。

#include <LovyanGFX.hpp>

static LGFX lcd;
static LGFX_Sprite canvas(&lcd);       // オフスクリーン描画用バッファ
static LGFX_Sprite base(&canvas);      // 文字盤パーツ
static LGFX_Sprite needle(&canvas);    // 針パーツ

static auto transpalette = 0;           // 透過色パレット番号


const int PIN_DHT = D2;
const char c=0xF7;

unsigned long  p_millis, p_micros;
unsigned long  dT = 0;
int bt = 0;
int data[40];
int humid_H, humid_L, temp_H, temp_L, chk; 
int mp[] = {128, 64, 32, 16, 8, 4, 2, 1}; 
int tm[90];

void read_DHT11() {
  pinMode(D2, OUTPUT);
  digitalWrite(D2,LOW);
  p_millis = millis();
  while((millis() - p_millis)<20) {;}
  tm[0] = millis()-p_millis;
  digitalWrite(D2,HIGH);
  pinMode(D2,INPUT);
  p_micros=micros();
  while(digitalRead(D2) == HIGH) {;}
  tm[1]=micros()-p_micros;
  p_micros=micros();
  while(digitalRead(D2) == LOW) {;}
  tm[2]=micros()-p_micros;
  p_micros=micros();
  while(digitalRead(D2) == HIGH) {;}
  tm[3]=micros()-p_micros;

  for(bt = 0;bt < 40;bt++){
    p_micros=micros();
    while(digitalRead(D2) == LOW) {;}
    tm[bt*2+4]=micros()-p_micros;
    
    p_micros = micros();
    while(digitalRead(D2) == HIGH) {;}
    dT = micros() - p_micros;
    tm[bt*2+5]=dT;
    if ((dT > 65) and (dT < 75)) {
      data[bt] = 1;
    }
    else {
      data[bt] = 0;
    }
  }
  while(digitalRead(D2) == LOW) {;}
  humid_H = 0;
  humid_L = 0;
  temp_H = 0;
  temp_L = 0;
  chk = 0;
  for (int i=0; i<8; i++) {
    humid_H += data[i]*mp[i];
    humid_L += data[i+8]*mp[i];
    temp_H += data[i+16]*mp[i];
    temp_L += data[i+24]*mp[i];
    chk += data[i+32]*mp[i];
  }
  
  Serial.println(humid_H);
  Serial.println(humid_L);
  Serial.println(temp_H);
  Serial.println(temp_L);
  
  if ((humid_H + humid_L + temp_H + temp_L) != chk )
    Serial.println("Parity Error");
  /*
  for(bt = 0;bt < 40;bt++){
    Serial.print(data[bt]);
    //Serial.print(" / ");
  }
  Serial.println(" ");
  for(bt = 0;bt < 40;bt++){
    Serial.print(tm[bt*2+4]);
    Serial.print(" / ");
    Serial.print(tm[bt*2+5]);
    Serial.print(" / ");
  }
  Serial.println(" ");
 */
}


void setup() {
  pinMode(D2, INPUT);
  Serial.begin(115200);
  Serial.println("DHT11");

  float rad;
  float ty;
  float tx;

  lcd.init();
  lcd.setRotation(1);
  lcd.setBrightness(128);
  lcd.setColorDepth(16);
  lcd.clear(); 
  
  lcd.setPivot(159, 119);

  lcd.setColorDepth(24);
  for (int i = 0; i < 180; i+=2) { // 外周を描画する
    lcd.setColor(lcd.color888(i*1.4,i*1.4+2,i*1.4+4));
    lcd.fillArc(160, 120, 120       , 120-3,  90+i,  92+i);
    lcd.fillArc(160, 120, 120       , 120-3,  88-i,  90-i);
  }
  for (int i = 0; i < 180; i+=2) { // 外周を描画する
    lcd.setColor(lcd.color888(i*1.4,i*1.4+2,i*1.4+4));
    lcd.fillArc(160, 120, 120-4, 120-7, 270+i, 272+i);
    lcd.fillArc(160, 120, 120-4, 120-7, 268-i, 270-i);
  }
  lcd.setColorDepth(16);

  canvas.setColorDepth(lgfx::palette_4bit);  
  base  .setColorDepth(lgfx::palette_4bit);
  needle.setColorDepth(lgfx::palette_2bit);

  canvas.createSprite(240, 240); // メモリ確保
  base  .createSprite(240, 240);
  needle.createSprite(11, 109);

  //base.setFont(&fonts::Orbitron_Light_24);
  base.setTextSize(1.5);
  base.setTextDatum(lgfx::middle_center);

  base.fillCircle(120, 120, 120 - 8, 1);
  base.drawCircle(120, 120, 120 - 10,  3);
  base.setTextColor(4);

  for (int i=10; i<100; i+=10) {  //湿度計部分
    if ( (i%10) == 0 ) {  
      base.fillArc(120, 120, 120 - 10, 120 - 24, -0.2 + i*1.8, 0.2 + i*1.8, 3);
    }
      rad = i * 1.8 * 0.0174532925;
      ty =  sin(rad) * (120 * 10 / 15);
      tx =  cos(rad) * (120 * 10 / 17);
      base.drawNumber(i, 120 + tx, 120 + ty); // 数値描画

  }

  for (int i=0; i<51; i+=5) {   //温度計部分
    
      base.fillArc(120, 120, 120 - 10, 120 - 24, 195-0.2 + i*3, 195+0.2 + i*3, 3);
    
    if ( (i%10) == 0 ) {
      rad = (i+5) * 3 * 0.0174532925;
      ty =  -sin(rad) * (125 * 10 / 15);
      tx =  -cos(rad) * (125 * 10 / 15);
      base.drawNumber(i, 120 + tx, 120 + ty); // 数値描画
    }
  }

  needle.setPivot(5, 100);  // 針パーツの回転中心座標を設定する
  needle.fillRect(3, 20, 5, 80, 2);
  needle.fillCircle(5, 100, 4, 1);
  needle.drawCircle(5, 100, 4, 3);

  canvas.setPaletteColor(1, 0, 0, 15);
  canvas.setPaletteColor(2, 255, 31, 31);
  canvas.setPaletteColor(3, 255, 255, 191);
  canvas.setPaletteColor(4, 255, 255, 0);
  canvas.setPaletteColor(5, 0, 0, 255);

 
  draw(0,0);


}

void draw(int value_H,int value_T)
{
  float angle_H = 90+1.8*value_H;
  float angle_T = 285+3*value_T;
  
  base.setTextSize(2.5);
  base.fillRect(80,75,80,40,1); 
  base.drawString(String(value_T)+c+'C',120,90); 
  base.fillRect(80,135,80,40,1); 
  base.drawString(String(value_H)+'%',120,150); 
  base.fillArc(120,120,109,100,0,180,1);
  for (int i=10; i<100; i+=10) {   
      base.fillArc(120, 120, 120 - 10, 120 - 24, -0.2 + i*1.8, 0.2 + i*1.8, 3);
  }
  base.fillArc(120,120,109,100,0,1.8*value_H,5);
  base.pushSprite(0, 0);  // 描画用バッファに盤の画像を上書き

  //Serial.println(angle_H);
  //needle.pushRotateZoom( angle_H, 1.0, 1.0, transpalette); // 針をバッファに描画する
  //Serial.println(angle_T);
  needle.pushRotateZoom( angle_T, 1.0, 1.0, transpalette); // 針をバッファに描画する
  canvas.pushRotateZoom(0, 1.0, 1.0, transpalette);    // 完了した盤をLCDに描画する
}


void loop() {

  delay(3000);
  read_DHT11();
  draw(humid_H,temp_H);

}