macsbug

Just another WordPress.com site

Archive for the ‘ESP32’ Category

Low price Battery Module of M5STACK

leave a comment »

340円で出来る
M5STACK用 電源スイッチ付 1300mAh Battery Module を作りました。 2018.06.23

容量のあるバッテリーが 常に装備されると 何かと便利になります。
電源スイッチ付き ですので 未使用時でもバッテリーは消耗しません。
M5STACK 本体側に接続し 後部にセンサー等の配置が自由に行えます。
M5STACK Store で販売されている PROT Module をスタックする事ができます。


費用について:

中古バッテリー総計:333円 = 80 + 19 + 3 + 11 + 120 + 100。

新品バッテリー総計:883円 = 80 + 19 + 3 + 11 + 120 + 660。


バッテリーについて:

使用する バッテリは CASIO NP-40 (生産終了品)です。
規格:3.7V、 1300mAh ( or 1230mAh )、 縦 38.2 x 横 37.8 mm 。
中古のバッテリーは 100円から200円で 総計 333円 です。
新品のバッテリーは ロワジャパン製で 660円で 総計 883円 です。
_ ロワジャパン : CASIO カシオ NP-40 互換 バッテリー CNP-40 : 1300mAh
注意:バッテリーは 並列接続しては いけません。
_ M5 の Battery Module や 裏蓋内にある バッテリー との並列接続は
_ してはいけません。理由:片側のバッテリーが消耗している場合
_ バッテリーからバッテリーへ電流が流れ 発熱や焼損の原因になります。

参考:Make a battery module for M5STACK:前回の Battery Module 製作記事です。


購入リスト:

No Nomen Purchase Price
1  ロープロファイルピンソケット
(低メス) 2×15 (30P) 5.7mm
 秋月電子通商:
ロープロファイルピンソケット
(低メス) 2×15 (30P) 5.7mm
80円
2  JST 1.25mm Connector  Aliexpress:Micro JST 1.25mm 2P 2-Pin Male Connector with Wire +Female Plug 20sets 19円
3  26AWG 7.8cm Wire  Aliexpress:50pcs pcb solder cable 26AWG 7.8cm Fly jumper wire cable   3円
4  SLIDE SWITCH  Aliexpress:100pcs 3 Pin PCB 2 Position DPDT 1P2T SMD SMT Vertical Slide Switch 11円
5  BATTERY MODULE CASE  自作・材料費 120円
6  BATTERY  秋葉原:杉本ビル ガレージショップ 100円
=  =======================  ============================== ======
. 費用総計  NP-40 中古品使用 333円
. 参考  NP-40 新品使用 883円

 


部品詳細:

1. ロープロファイルピンソケット (低メス) 2×15 (30P) 5.7mm:2個 ¥80 ( 1個 ¥40 )
秋月電子通商。


_ M-BUS コネクターの高さについて:
_  M5STACK は 小型化する為に 低いコネクターを採用しました。
_  この為 他のコネクターを接続し スタック出来ない事になります。
_  M5STACK の M-BUS コネクターの高さに合わせる 方法は
_  秋月電子通商で販売の ロープロファイルピンソケット (低メス) 2×15 (30P) 5.7mm
_  を 縦に2個接続 ( 5.7 x 2 = 11.4 mm ) する方法です。
_  M5 PROT CASE の高さは 6.5mm ですが 11mm になります。

2. JST 1.25mm Connector:1個 ¥19  ( $0.17 ):M5 BAT端子へ接続するコネクターです。
Aliexpress:Micro JST 1.25mm 2P 2-Pin Male Connector with Wire +Female Plug 20sets
_ 規格:Micro JST 1.25mm。

3. 26AWG 7.8cm Wire:1個 ¥3  ( $0.0194 )
Aliexpress:50pcs pcb solder cable 26AWG 7.8cm Fly jumper wire cable

4. SLIDE SWITCH:1個 ¥11  (  $0.10 ):電源スイッチです。
Aliexpress:100pcs 3 Pin PCB 2 Position DPDT 1P2T SMD SMT Vertical Slide Switch
_ このスイッチは WEMOS LOLIN32 に使用されている 基板用スイッチです。

5. BATTERY MODULE CASE:1個 120円  ( 12g ):材料代のみ。
_ CAD 及び 3D PRINTER で製作しました。高さは 11mm です。
_ 左の隙間は M-BUS用です。右上の 凹 は スイッチを取り付けます。
_ ケースを希望される方は Yahoo LODGE や Arduino 、M5STACK 等の
_ 集まり時に お渡し出来るかと思っています。

6. BATTERY:1個 100円。
NP-40 BATTERY : 秋葉原 杉本ビル ガレージショップ:中古カメラバッテリー
_ 通常1個 ¥200 ですが 10個とか まとめ買いで お姉さんに頼むと安くなります。
_ 他にバッテリーは沢山ありますが NP-40 だけを箱にまとめて 頂いています。
_ 新品は ロワジャパン CNP-40 があります。1個 660円。


配線:配線は3本のみです。
_ ⭕ 重要 :JST 1.25mm コネクターピンの + と – を入れ替えます。
_       ピンは細いピンセットの先でコネクターのロックを外して取ります。

_ 🔴 要注意:M5STACK の BATコネクターの極性は M-BUS 側が + ( Plus ) です。
_       市販されているワイヤー付き JST 1.25mmコネクターは M5STACK
_       とは 逆の配置です。何度も確認してください。

_ JST 1.25mm Connector + の 赤線 を SLIDE SWITCHへ ハンダ付けします。
_  + 赤線は そのままの長さで配線します。
_ JST 1.25mm Connector –  の 黒線 を BATTERY – へ ハンダ付けします。
_  GND線は 適した長さに切ります。
_ 26AWG 7.8cm Wire を SLIDE SWITCH と BATTERY + に ハンダ付けします。
_  ワイヤー は そのままの長さで 配線します。


組み立て:

重要な確認事項:
_ JSTコネクター を M5 BAT コネクターに 接続する前に 必ず テスターで
_ 電圧の極性を確認してください。再確認は電源接続の基本です。
_ M5STACK 側の BAT コネクターの + と – の位置を確認してください。
_ 下の画像にある M5 BAT コネクターの左側が + ( plus ) です。
_ + – が 逆ですと 高価な M5STACK が壊れます。
_ くれぐれも 自己責任でお願い致します。

_ M5STACK M-BUS に ロープロファイルピンソケット(低メス)
_  2×15 (30P) 5.7mm を 縦に2個接続します。

_ BATTERY の取り付けは SWITCH 側に寄せて SWITCH を固定します。
_  両面テープでケースに止めます。


HEX SCREW SIZE:上記の製作では 六角スクリューの長さは 30mm となります。
_  六角スクリューが 無い場合は 秋葉原・西川電子部品に + 30mm ネジがあります。


感想:

バッテリー容量:
_ M5の裏蓋にあるバッテリーは 150mAh で容量は少ないです。
_ Battery Module ( $18.90 ) は 850mAh で これも不足気味です。
_ PROT CASE の内部で試用できる厚さは 5.7mm ( 6.5 – 0.8 mm:PCB) です。
_ このサイズに入る BATTERY は 850mAh になります。

_ 同じ縦横サイズで 1800mAh の物がありますが、厚さが 6.6mm で
_ PROT CASE には 入りません。
_ 1800mAh は ebay にて 365円で販売されています。輸送期間は 8日です。
_ このバッテリーを使用した製作は 後日 行う予定です。

国内価格:
_ スイッチサイエンスの M5Stack用電池モジュール は 2190円 と高いです。
_ 約340円で出来ますので 6個程作れる事になります。

バッテリーと配線方法:
_ バッテリーは ワイヤーをハンダ付けしました。
_ 他の方法として POD PIN を使用する方法があり、バッテリーを抜き差し
_ する事ができます。この方法は 課題として検討中です。

CAD データー:
_ CAD のデーターは 使用するプリンターによって異なります。
_ 特に M5STACK は 小型の為に 精度の低いプリンターでは 作る事が
_ 出来ない部分があります。
_ そのノウハウを踏まえ 今回のケースを作りました。


広告

Written by macsbug

6月 23, 2018 at 7:00 pm

カテゴリー: ESP32, M5STACK

M5Stack Thermal Camera with AMG8833

leave a comment »

M5STACK で AMG8833 Thermal sensor を 動かしました。         2018.06.08

AMG8833 Thermal sensor は 3942円で高価です。
AMG8833 熱センサーは 画素数 8×8ピクセルで(24×8)x(24×8)に補間されています。
hkoffer氏作成の M5Stack-Thermal-Camera- を使用しました。
ただし このリストでは 表示の向きが正しく表示しない為、スケッチを修正致しました。

機能:
1 . AMG8833 Thermal sensor 8×8 pixel を(24×8)x(24×8)に補間しています。
2 . Sight added & temperature
3 . Auto max temperature
4 . Auto min temperature
5. センスする距離は約30cm です。(仕様は 人検知が可能な距離:最長7m )

Adafruit AMG88xx Library:
1. AMG88xx GridEYE 8×8 IRカメラ用のライブラリです。
2. AMG8833 I2C 接続。address = 0x69
3. TFT FeatherWing – 2.4″ 320×240 Touchscreen For All Feathers
4. Adafruit AMG8833 Featherwingで動作します。

補足:
_ 現在、テスト領域全体の最高温度のみが示されており、最初は最大温度と
_ 最小温度の自動調整を追加し、中心視界の温度を表示することを意図しています。


.
準備:

No Nomen Link Price Transport
1 AMG8833 Matrice IR 8*8
Thermal Imager Module
Aliexpress :
Your Cee Store    $35.99
3942円 9day
2 adafruit Library Adafruit_AMG88xx  –
3 hoofer sketch & Library M5Stack-Thermal-Camera-

Your Cee Store の輸送期間は 9日 で速いです。

2018.06.08 現在:3942円 ( 1$ 109.5 円換算) $35.99

MOUSER : Pansonic AMG8833 単体1個2582円。

Panasonic 赤外線アレイセンサ Grid-EYE(AMG88)
用途:高機能家電(電子レンジ・エアコン),オフィス省エネ(空調・照明制御),
_  デジタルサイネージ,自動ドア・エレベータ。
AMG8833 : 3.3V, 高性能タイプ ハイゲイン: 0 °C ~ 80 °C
AMG8834 : 3.3V, 高性能タイプ ローゲイン:−20 °C ~ 80 °C
AMG8853 : 5.0V, 高性能タイプ ハイゲイン: 0 °C ~ 80 °C
AMG8854 : 5.0V, 高性能タイプ ローゲイン:−20 °C ~ 80 °C

スケッチ構成:
thermal_cam_interpolate
_ thermal_cam_interpolate.ino
_ interpolation.cpp


.
配線:

PROT Board に 以下の4本を配線します。

組み立て:
裏蓋ケースを作り組み上げました。


.
参考:

Adafruit:AMG88xx thermal sensor
Adafruit AMG8833 8×8 Thermal Camera Sensor:pdf
YouTube:M5Stack Thermal Imaging Camera
twitter : Offer DIYER
Thingiverse : M5Stack Thermal Imaging Camera Case:3Dプリントケース
HACKADAY:WHO SAID THERMAL CAMERAS WEREN’T ACCESSIBLE TO THE MASSES?
Pansonic 赤外線アレイセンサ Grid=EYE (AMG88)
Infrared array sensor “Grid-EYE” AMG88 * *:参考仕様書


.
スケッチ修正:現象と対策。
May 12, 2018 の M5Stack-Thermal-Camera- は 修正が必要です。
1. 画像が横向き:M5.Lcd.setRotation(0) を M5.Lcd.setRotation(1)に変更します。
2. 文字と画像の縦が逆、画像の左右が逆:
_ void drawpixels の float val = get_point(p, rows, cols, x, y); を
_ float val = get_point(p, rows, cols, cols-x, rows-y); にし 縦を逆にします。
_ これにより正常に表示しました。


.
感想:

AMG8833 の画素数は 8×8 です。そして価格は高価です。
_ 8×8 のサイズでは 荒すぎ、価格が高くて意味がありませんでした。
_ そこへ hkoffer氏 により 24×24 が可能となり 見やすくなりました。
_ 高価ですが 24×24 なら体験したく購入しました。

_ 国内 スイッチサイエンスでの価格は 今回の業者より千円程高く購入対象にならず。
_ Aliexpress の Your Cee Store からは なんと 9日で届くと言う速さでした。

_ 温度分布の表示は まずまずの感じでした。


.
スケッチ:

thermal_cam_interpolate
_ thermal_cam_interpolate.ino
_ interpolation.cpp

// M5Stack Thermal Camera with AMG8833 : 2018.06.08 Modified by macsbug
/***************************************************************************
  This is a library for the AMG88xx GridEYE 8x8 IR camera
  This sketch makes an inetrpolated pixel thermal camera with the
  GridEYE sensor and a 2.4" tft featherwing:
	 https://www.adafruit.com/product/3315
  Designed specifically to work with the Adafruit AMG8833 Featherwing
          https://www.adafruit.com/product/3622
  These sensors use I2C to communicate. The device's I2C address is 0x69
  Adafruit invests time and resources providing this open source code,
  please support Adafruit andopen-source hardware by purchasing products
  from Adafruit!
  Written by Dean Miller, James DeVito & ladyada for Adafruit Industries.
  BSD license, all text above must be included in any redistribution
 ***************************************************************************/
// AMG8833 thermal sensor : https://github.com/adafruit/Adafruit_AMG88xx
// https://github.com/hkoffer/M5Stack-Thermal-Camera-/blob/master/thermal_cam_interpolate.ino
// Github : https://macsbug.wordpress.com/2018/06/08/m5stack-thermal-camera-with-amg8833/
//==========================================================================
#include <M5Stack.h>
#include "M5StackUpdater.h"  // SD UPDATER
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_AMG88xx.h>
byte MINTEMP = 20; //low range of the sensor (this will be blue on the screen)
byte MAXTEMP = 32; //high range of the sensor (this will be red on the screen)
const uint16_t camColors[] = { 0x480F,   //the colors we will be using
 0x400F,0x400F,0x400F,0x4010,0x3810,0x3810,0x3810,0x3810,0x3010,0x3010,
 0x3010,0x2810,0x2810,0x2810,0x2810,0x2010,0x2010,0x2010,0x1810,0x1810,
 0x1811,0x1811,0x1011,0x1011,0x1011,0x0811,0x0811,0x0811,0x0011,0x0011,
 0x0011,0x0011,0x0011,0x0031,0x0031,0x0051,0x0072,0x0072,0x0092,0x00B2,
 0x00B2,0x00D2,0x00F2,0x00F2,0x0112,0x0132,0x0152,0x0152,0x0172,0x0192,
 0x0192,0x01B2,0x01D2,0x01F3,0x01F3,0x0213,0x0233,0x0253,0x0253,0x0273,
 0x0293,0x02B3,0x02D3,0x02D3,0x02F3,0x0313,0x0333,0x0333,0x0353,0x0373,
 0x0394,0x03B4,0x03D4,0x03D4,0x03F4,0x0414,0x0434,0x0454,0x0474,0x0474,
 0x0494,0x04B4,0x04D4,0x04F4,0x0514,0x0534,0x0534,0x0554,0x0554,0x0574,
 0x0574,0x0573,0x0573,0x0573,0x0572,0x0572,0x0572,0x0571,0x0591,0x0591,
 0x0590,0x0590,0x058F,0x058F,0x058F,0x058E,0x05AE,0x05AE,0x05AD,0x05AD,
 0x05AD,0x05AC,0x05AC,0x05AB,0x05CB,0x05CB,0x05CA,0x05CA,0x05CA,0x05C9,
 0x05C9,0x05C8,0x05E8,0x05E8,0x05E7,0x05E7,0x05E6,0x05E6,0x05E6,0x05E5,
 0x05E5,0x0604,0x0604,0x0604,0x0603,0x0603,0x0602,0x0602,0x0601,0x0621,
 0x0621,0x0620,0x0620,0x0620,0x0620,0x0E20,0x0E20,0x0E40,0x1640,0x1640,
 0x1E40,0x1E40,0x2640,0x2640,0x2E40,0x2E60,0x3660,0x3660,0x3E60,0x3E60,
 0x3E60,0x4660,0x4660,0x4E60,0x4E80,0x5680,0x5680,0x5E80,0x5E80,0x6680,
 0x6680,0x6E80,0x6EA0,0x76A0,0x76A0,0x7EA0,0x7EA0,0x86A0,0x86A0,0x8EA0,
 0x8EC0,0x96C0,0x96C0,0x9EC0,0x9EC0,0xA6C0,0xAEC0,0xAEC0,0xB6E0,0xB6E0,
 0xBEE0,0xBEE0,0xC6E0,0xC6E0,0xCEE0,0xCEE0,0xD6E0,0xD700,0xDF00,0xDEE0,
 0xDEC0,0xDEA0,0xDE80,0xDE80,0xE660,0xE640,0xE620,0xE600,0xE5E0,0xE5C0,
 0xE5A0,0xE580,0xE560,0xE540,0xE520,0xE500,0xE4E0,0xE4C0,0xE4A0,0xE480,
 0xE460,0xEC40,0xEC20,0xEC00,0xEBE0,0xEBC0,0xEBA0,0xEB80,0xEB60,0xEB40,
 0xEB20,0xEB00,0xEAE0,0xEAC0,0xEAA0,0xEA80,0xEA60,0xEA40,0xF220,0xF200,
 0xF1E0,0xF1C0,0xF1A0,0xF180,0xF160,0xF140,0xF100,0xF0E0,0xF0C0,0xF0A0,
 0xF080,0xF060,0xF040,0xF020,0xF800,
};
Adafruit_AMG88xx amg;
#define AMG_COLS 8
#define AMG_ROWS 8
float pixels[AMG_COLS * AMG_ROWS];
#define INTERPOLATED_COLS 24
#define INTERPOLATED_ROWS 24
int max_v =  0;
int min_v = 80;
float get_point(float *p,uint8_t rows,uint8_t cols,int8_t x,int8_t y);
void set_point(float *p,uint8_t rows,uint8_t cols,int8_t x,int8_t y,float f);
void get_adjacents_1d(float *src, float *dest, uint8_t rows, uint8_t cols, 
                      int8_t x, int8_t y);
void get_adjacents_2d(float *src, float *dest, uint8_t rows, uint8_t cols,
                      int8_t x, int8_t y);
float cubicInterpolate(float p[], float x);
float bicubicInterpolate(float p[], float x, float y);
//==========================================================================
void interpolate_image(float *src, uint8_t src_rows, uint8_t src_cols, 
                       float *dest, uint8_t dest_rows, uint8_t dest_cols);
//==========================================================================
void setup(){
  M5.begin();
  Wire.begin(); 
  if(digitalRead(BUTTON_A_PIN) == 0){updateFromFS(SD);ESP.restart();} // SD
  M5.setWakeupButton(BUTTON_B_PIN);
  M5.Lcd.begin();
  M5.Lcd.setRotation(1);  // 0 to 1 :Modified
  M5.Lcd.fillScreen(TFT_BLACK);
  int icolor = 255;
  for (int irow = 16; irow <= 223;  irow++){
    M5.Lcd.drawRect(0, 0, 35, irow, camColors[icolor]);
    icolor--;
  }
  infodisplay();
  if (!amg.begin()){ while (1){delay(1);}}
}
//==========================================================================
void loop() {
  if (M5.BtnA.pressedFor(1000)){MINTEMP = min_v;min_v = 80;infodisplay();}
  if (M5.BtnA.wasPressed()) {
    if (MINTEMP <= 0){MINTEMP = MAXTEMP - 1;infodisplay();
    }else{MINTEMP--;infodisplay();
    }
  }
  if (M5.BtnB.pressedFor(1000)){ M5.powerOFF();}
  if (M5.BtnC.pressedFor(1000)){MAXTEMP = max_v;max_v = 0;infodisplay();}
  if (M5.BtnC.wasPressed()) {
    if (MAXTEMP >= 80){MAXTEMP = MINTEMP + 1;infodisplay();
    }else{MAXTEMP++;infodisplay();
    }
  }
  M5.update();
  amg.readPixels(pixels);   //read all the pixels
  for (int i = 1; i <= AMG88xx_PIXEL_ARRAY_SIZE; i++){}
  float dest_2d[INTERPOLATED_ROWS * INTERPOLATED_COLS];
  interpolate_image(pixels, AMG_ROWS, AMG_COLS, dest_2d, 
    INTERPOLATED_ROWS, INTERPOLATED_COLS);
  uint16_t boxsize = min(M5.Lcd.width() / INTERPOLATED_COLS, 
    M5.Lcd.height() / INTERPOLATED_COLS);
  drawpixels(dest_2d, INTERPOLATED_ROWS, INTERPOLATED_COLS, 
    boxsize, boxsize, false);
  max_v = INT_MIN;
  //  int max_i = 0;
  int spot_v = pixels[28];
  for (int itemp = 0;itemp < sizeof(pixels) / sizeof(pixels[0]);itemp++){
    if ( pixels[itemp] > max_v ){max_v = pixels[itemp];//max_i = itemp;
    }
    if ( pixels[itemp] < min_v ){min_v = pixels[itemp];//max_i = itemp;
    }
  }
  M5.Lcd.setTextSize(2);
  M5.Lcd.fillRect (284,  18, 36, 16, TFT_BLACK);
  M5.Lcd.fillRect (284, 130, 36, 16, TFT_BLACK);
  M5.Lcd.setCursor(284,  18);
  M5.Lcd.setTextColor(TFT_WHITE);
  if ((max_v > 80) | (max_v < 0)) {
    M5.Lcd.setTextColor(TFT_RED);
    M5.Lcd.printf("Err");
  }else{
    M5.Lcd.printf("%dC",max_v);
    M5.Lcd.setCursor(284, 130);
    M5.Lcd.printf("%dC",spot_v);
    M5.Lcd.drawCircle(160, 120,   6, TFT_WHITE);
    M5.Lcd.drawLine  (160, 110, 160, 130, TFT_WHITE);
    M5.Lcd.drawLine  (150, 120, 170, 120, TFT_WHITE);
  }
}
//==========================================================================
void infodisplay(void) {  /***infodisplay()*****/
  M5.Lcd.setTextColor(TFT_WHITE);
  // M5.Lcd.setCursor(288, 230);
  // M5.Lcd.printf("Power");
  M5.Lcd.fillRect(0, 0, 36, 16, TFT_BLACK);
  M5.Lcd.setTextSize(2);
  M5.Lcd.setCursor(0, 1);
  M5.Lcd.printf("%dC",MAXTEMP);
  M5.Lcd.setCursor(0, 225);
  M5.Lcd.fillRect(0, 225, 36, 16, TFT_BLACK);
  M5.Lcd.printf("%dC",MINTEMP);
  M5.Lcd.setCursor(284, 0);
  M5.Lcd.printf("Max");
  M5.Lcd.setCursor(284, 100);
  //  M5.Lcd.printf("Spot");
  M5.Lcd.drawCircle(300, 120, 6, TFT_WHITE);
  M5.Lcd.drawLine(300, 110, 300, 130, TFT_WHITE);
  M5.Lcd.drawLine(290, 120, 310, 120, TFT_WHITE);
}
//==========================================================================
void drawpixels(float *p, uint8_t rows, uint8_t cols, uint8_t boxWidth, 
                uint8_t boxHeight, boolean showVal) {
  int colorTemp;
  for (int y = 0; y < rows; y++) {
    for (int x = 0; x < cols; x++) {
      float val = get_point(p, rows, cols, cols-x, rows-y); // Modified
      if (val >= MAXTEMP) colorTemp = MAXTEMP;
      else if (val <= MINTEMP) colorTemp = MINTEMP;
      else colorTemp = val;
      uint8_t colorIndex = map(colorTemp, MINTEMP, MAXTEMP, 0, 255);
      colorIndex = constrain(colorIndex, 0, 255);
      uint16_t color;  //draw the pixels!
      color = val * 2;
      M5.Lcd.fillRect(40 + boxWidth * x, boxHeight * y,
                      boxWidth, boxHeight, camColors[colorIndex]);
    }
  }
}
//==========================================================================

Written by macsbug

6月 8, 2018 at 11:55 pm

カテゴリー: ESP32

Easy M5STACK JOYSTICK

leave a comment »

200円でできる 超安価な M5STACK JOYSTICK を作りました。 2018.06.06

テトリスをジョイスティックで操作できるようになります。
ケースに収まった感触と JOYSTICK の操作は とても使いやすいです。

左:M5STACK BASIC。 右:M5STAC BASIC + BATTERY:縦のサイズがピッタリです。


準備:

No  Nomen  Link   Price
 1  JoyStick Controller  whemyqong5 Store (C$1.01)   90円
 1  JoyStick Controller  cbincnm Store (C$1.01)   90円
 2  ピンヘッダ 1×40 (40P)  秋月電子通商   85円
 3  M5STACK BASIC  –     0円
 4  M5STACK BASIC CASE  –     0円
 5  ワイヤー  –   –
 6  穴あけ用カッター  –   –
 7  両面テープ  –   –
 ——————————-  ————————————  ——
 合計      175円
 スケッチ:macsbug  TETRIS with M5STACK
 8  スケッチ:しかるのち  M5Stack:テトリス改造

JoyStick Hots PS2 Two-axis Lever Joystick Game Sensor Controller

端子:[ GND, 5V, VRX, VRY, SW ]


ケース加工:
Joystick と USB-C, Power Swicth 場所にカッターで穴を空けます。
マルは 丸穴専用カッターが便利です。


回路図:配線は 5本のみです。


配線:直接配線。
_ ケースの穴と JOYSTICK KNOB の高さは重要です。
_ ケースの穴に対して JOYSTICK の高さと動きを事前に調べておきます。
_ 15ピン ピンヘッダー と JOYSTICK を 配線します。
_ 配線後 M5STACK に取り付け、JOYSTICK の高さと動きをチョックします。
_ 必要に応じて両面テープで固定してください。


配線:基板配線。
_ ケースの穴と JOYSTICK KNOB の高さは重要です。
_ ケースの穴に対して JOYSTICK の高さと動きを事前に調べておきます。
_ 基板に 15ピン ピンヘッダー と JOYSTICK を 配線します。
_ 配線後 M5STACK に取り付け、JOYSTICK の高さと動きをチョックします。
_ 必要に応じて両面テープで固定してください。
_ メモ:JOYSTICKは基板に取り付ける位置で高さを調整できます。


M5STACK 取り付け:JOYSTICKの高さ調整。
_ M5STACK と JOYSTICK は 以下の接続になります。
_ ケースの穴に対し JOYSTICKのKNOBが 自由に動く事が大切です。
_ JOYSTICKのKNOBが 穴に接触しない様に両面テープ等で高さを調整します。


Joystick 機能:

 
bool KeyPadLoop(){ 
 uint16_t joyX = analogRead(JOY_X);
 uint16_t joyY = analogRead(JOY_Y);
 if(digitalRead(sw) == 0){ClearKeys();but_A=true;delay(300);return true;}
 if( joyY >= 3500 ){ ClearKeys();but_DOWN =true;delay(250);return true;}
 if( joyX <= 1500 ){ ClearKeys();but_LEFT =true;delay(250);return true;}
 if( joyX >= 2500 ){ ClearKeys();but_RIGHT=true;delay(250);return true;}
 return false; }

参考:
How to connect the joystick to Arduino:JOYSICKの回路図と使用方法。


感想:
購入時の M5STACKケースが使用できないものかと考え、
超安価な 90円のジョイスティックを組み合わせてみました。
2つ作りましたが 基板にピンとJOYSITCK を取り付ける方法が楽でした。
ケースをカッターで切るのは 綺麗に出来ず なかなか難しいです。
1つの箱の中に収まる感じはスッキリして 握った感じがとても良いです。

 


スケッチ:

macsbug テトリス移植版オリジナル: TETRIS with M5STACK
しかるのち氏のテトリス改造版:M5Stack:テトリス改造 を DL します。
改造された しかるのち氏に感謝致し 使用させて頂きます。
M5Stack:テトリス改造 の [  bool KeyPadLoop ] を 以下の様に変更します。
_ これは Joystick の機能を追加する為です。

//========================================================================
// TETRIS with M5STACK : 2018.01.20 Transplant by macsbug
//                       2018.05.03 Modified by @shiakrunochi
//                       2018.06.06 Modified by macsbug
// Controller : Buttons A = LEFT, B = RIGHT, C = START, ROTATE
// Display    : Left = 100x240, Center = 120x240, Right = 100x240
// Block      : 8ea, 12x12 pixel
// SD         : tetris.jpg : BackGround Image : R.G.B 320x240 pixel
// Github     : (Original) https://macsbug.wordpress.com/2018/01/20/tetris-with-m5stack/
// Github     : (revision) http://shikarunochi.matrix.jp/?p=2296
// Github     : (joystick) https://macsbug.wordpress.com/2018/06/06/easy-m5stack-joystick/
//========================================================================
#include <M5Stack.h>                                       // M5STACK
#include "M5StackUpdater.h"                                // SD UPDATE
uint16_t BlockImage[8][12][12];                            // Block
uint16_t backBuffer[240][120];                             // GAME AREA
uint16_t nextBlockBuffer[60][48];                          // NEXT BLOCK AREA
const int Length = 12;     // the number of pixels for a side of a block
const int Width  = 10;     // the number of horizontal blocks
const int Height = 20;     // the number of vertical blocks
int screen[Width][Height] = {0}; //it shows color-numbers of all positions
struct Point {int X, Y;};
struct Block {Point square[4][4]; int numRotate, color;};
Point pos; Block block;
int nextBlockType = -1;
long score = 0;
Block nextBlock;
int rot, fall_cnt = 0;
bool started = false, gameover = false;
boolean but_A = false, but_LEFT = false, but_RIGHT = false, but_DOWN = false;
boolean but_UP = false;
int game_speed = 25; // 25msec
Block blocks[7] = {
  {{{{-1,0},{0,0},{1,0},{2,0}},{{0,-1},{0,0},{0,1},{0,2}},
  {{0,0},{0,0},{0,0},{0,0}},{{0,0},{0,0},{0,0},{0,0}}},2,1},
  {{{{0,-1},{1,-1},{0,0},{1,0}},{{0,0},{0,0},{0,0},{0,0}},
  {{0,0},{0,0},{0,0},{0,0}},{{0,0},{0,0},{0,0},{0,0}}},1,2},
  {{{{-1,-1},{-1,0},{0,0},{1,0}},{{-1,1},{0,1},{0,0},{0,-1}},
  {{-1,0},{0,0},{1,0},{1,1}},{{1,-1},{0,-1},{0,0},{0,1}}},4,3},
  {{{{-1,0},{0,0},{0,1},{1,1}},{{0,-1},{0,0},{-1,0},{-1,1}},
  {{0,0},{0,0},{0,0},{0,0}},{{0,0},{0,0},{0,0},{0,0}}},2,4},
  {{{{-1,0},{0,0},{1,0},{1,-1}},{{-1,-1},{0,-1},{0,0},{0,1}},
  {{-1,1},{-1,0},{0,0},{1,0}},{{0,-1},{0,0},{0,1},{1,1}}},4,5},
  {{{{-1,1},{0,1},{0,0},{1,0}},{{0,-1},{0,0},{1,0},{1,1}},
  {{0,0},{0,0},{0,0},{0,0}},{{0,0},{0,0},{0,0},{0,0}}},2,6},
  {{{{-1,0},{0,0},{1,0},{0,-1}},{{0,-1},{0,0},{0,1},{-1,0}},
  {{-1,0},{0,0},{1,0},{0,1}},{{0,-1},{0,0},{0,1},{1,0}}},4,7}
};
extern uint8_t tetris_img[];
#define JOY_X  2
#define JOY_Y 26
#define sw     5
//========================================================================
void setup(void) {
  Serial.begin(115200);         // SERIAL
  M5.begin();                   // M5STACK INITIALIZE
  Wire.begin();
  if(digitalRead(BUTTON_A_PIN) == 0){updateFromFS(SD);ESP.restart();}
  M5.Lcd.setBrightness(200);    // BRIGHTNESS = MAX 255
  M5.Lcd.fillScreen(BLACK);     // CLEAR SCREEN
  M5.Lcd.setRotation(1);        // SCREEN ROTATION = 0
  M5.Lcd.setTextColor(WHITE);
  M5.Lcd.setTextSize(2);
  //----------------------------// Make Block ----------------------------
  pinMode(sw,    INPUT_PULLUP);
  pinMode(JOY_X, INPUT);
  pinMode(JOY_Y, INPUT);
  //----------------------------// Make Block ----------------------------
  make_block( 0, BLACK);        // Type No, Color
  make_block( 1, 0x00F0);       // DDDD     RED
  make_block( 2, 0xFBE4);       // DD,DD    PUPLE 
  make_block( 3, 0xFF00);       // D__,DDD  BLUE
  make_block( 4, 0xFF87);       // DD_,_DD  GREEN 
  make_block( 5, 0x87FF);       // __D,DDD  YELLO
  make_block( 6, 0xF00F);       // _DD,DD_  LIGHT GREEN
  make_block( 7, 0xF8FC);       // _D_,DDD  PINK
  //----------------------------------------------------------------------
  // M5.Lcd.drawJpgFile(SD, "/tetris.jpg");     // Load background from SD
  M5.Lcd.drawJpg(tetris_img, 34215);     // Load background from file data
  PutStartPos();                                // Start Position
  for (int i = 0; i < 4; ++i) screen[pos.X + 
   block.square[rot][i].X][pos.Y + block.square[rot][i].Y] = block.color;
  Draw();                                       // Draw block
  DrawNextBlock();
}
//========================================================================
void loop() {
  if (gameover) return;
  Point next_pos;
  int next_rot = rot;
  GetNextPosRot(&next_pos, &next_rot);
  ReviseScreen(next_pos, next_rot);
  M5.update();
  delay(game_speed);                                      // SPEED ADJUST
}
//========================================================================
void Draw() {                               // Draw 120x240 in the center
  for (int i = 0; i < Width; ++i) for (int j = 0; j < Height; ++j)
   for (int k = 0; k < Length; ++k) for (int l = 0; l < Length; ++l)
    backBuffer[j * Length + l][i * Length + k] = BlockImage[screen[i][j]][k][l];
    M5.Lcd.pushImage(100, 0, 120, 240, (uint16_t *)backBuffer);
}
//========================================================================
void DrawNextBlock() {  
  for(int x = 0; x < 48;x++) {
    for(int y = 0; y < 60;y++){
      nextBlockBuffer[y][x]=0;
    }
  }
  nextBlock = blocks[nextBlockType];
  int offset = 6 + 12;
  for (int i = 0; i < 4; ++i) {
      for (int k = 0; k < Length; ++k) for (int l = 0; l < Length; ++l){
        nextBlockBuffer[60 - (nextBlock.square[0][i].X * Length + l + 
        offset)][nextBlock.square[0][i].Y * Length + k + offset] = 
        BlockImage[nextBlockType + 1][k][l];
      }
  }
  M5.Lcd.pushImage(26, 100, 48, 60, (uint16_t *)nextBlockBuffer);
  M5.Lcd.fillRect(2, 76, 96, 19, BLACK);
  M5.Lcd.setCursor(10, 78);
  M5.Lcd.print(score);//M5.Lcd.printf("%7d",score);
}
//========================================================================
void PutStartPos() {
  pos.X = 4; pos.Y = 1;
  if (nextBlockType == -1){
    block = blocks[random(7)];
  }else{
    block = blocks[nextBlockType];
  }
  nextBlockType = random(7);
  rot = random(block.numRotate);
}
//========================================================================
bool GetSquares(Block block, Point pos, int rot, Point* squares) {
  bool overlap = false;
  for (int i = 0; i < 4; ++i) {
    Point p;
    p.X = pos.X + block.square[rot][i].X;
    p.Y = pos.Y + block.square[rot][i].Y;
    overlap |= p.X < 0 || p.X >= Width || p.Y < 0 || p.Y >= 
      Height || screen[p.X][p.Y] != 0;
    squares[i] = p;
  }
  return !overlap;
}
//========================================================================
void ClearKeys(){but_A=false;but_LEFT=false;but_RIGHT=false;but_DOWN=false;}
//========================================================================
void GameOver() {
  for (int i = 0; i < Width; ++i) for (int j = 0; j < Height; ++j) if (screen[i][j] != 0) screen[i][j] = 4; gameover = true; } //======================================================================== bool KeyPadLoop(){ uint16_t joyX = analogRead(JOY_X); uint16_t joyY = analogRead(JOY_Y); if(digitalRead(sw) == 0){ClearKeys();but_A=true;delay(300);return true;} if( joyY >= 3500 ){ ClearKeys();but_DOWN =true;delay(250); return true;}
  if( joyX <= 1500 ){ ClearKeys();but_LEFT =true;delay(250); return true;} if( joyX >= 2500 ){ ClearKeys();but_RIGHT=true;delay(250); return true;}
  return false;
}
//========================================================================
void GetNextPosRot(Point* pnext_pos, int* pnext_rot) {
  bool received = KeyPadLoop();
  if (but_A) started = true;
  if (!started) return;
  pnext_pos->X = pos.X;
  pnext_pos->Y = pos.Y;
  if ((fall_cnt = (fall_cnt + 1) % 10) == 0) pnext_pos->Y += 1;
  else if (received) {
    if (but_LEFT) { but_LEFT = false; pnext_pos->X -= 1;}
    else if (but_RIGHT) { but_RIGHT = false; pnext_pos->X += 1;}
    else if (but_DOWN) { but_DOWN = false; pnext_pos->Y += 1;}
    else if (but_A) { but_A = false;
      *pnext_rot = (*pnext_rot + block.numRotate - 1)%block.numRotate; 
    }
  }
}
//========================================================================
void DeleteLine() {
  int deleteCount = 0;
  for (int j = 0; j < Height; ++j) {
    bool Delete = true;
    for (int i = 0; i < Width; ++i) if (screen[i][j] == 0) Delete = false; if (Delete) { for (int k = j; k >= 1; --k) {
        for (int i = 0; i < Width; ++i) { screen[i][k] = screen[i][k - 1]; } } deleteCount++; } } switch (deleteCount){ case 1:score = score + 40;break; case 2:score = score + 100;break; case 3:score = score + 300;break; case 4:score = score + 1200;break; } if(score > 9999999){score = 9999999;}
}
//========================================================================
void ReviseScreen(Point next_pos, int next_rot) {
  if (!started) return;
  Point next_squares[4];
  for (int i = 0; i < 4; ++i) screen[pos.X + 
    block.square[rot][i].X][pos.Y + block.square[rot][i].Y] = 0;
  if (GetSquares(block, next_pos, next_rot, next_squares)) {
   for (int i = 0; i < 4; ++i){
     screen[next_squares[i].X][next_squares[i].Y] = block.color;
   }
   pos = next_pos; rot = next_rot;
  }
  else {
   for (int i = 0; i < 4; ++i) screen[pos.X + 
    block.square[rot][i].X][pos.Y + block.square[rot][i].Y] = block.color;
   if (next_pos.Y == pos.Y + 1) {
    DeleteLine(); PutStartPos();DrawNextBlock();
    if (!GetSquares(block, pos, rot, next_squares)) {
     for (int i = 0; i < 4; ++i) screen[pos.X + 
      block.square[rot][i].X][pos.Y + block.square[rot][i].Y] = block.color;
      GameOver();
    }
   }
  }
  Draw();
}
//========================================================================
void make_block( int n , uint16_t color ){            // Make Block color       
  for ( int i =0 ; i < 12; i++ ) for ( int j =0 ; j < 12; j++ ){
    BlockImage[n][i][j] = color;                      // Block color
    if ( i == 0 || j == 0 ) BlockImage[n][i][j] = 0;  // BLACK Line
  } 
}
//========================================================================

Written by macsbug

6月 6, 2018 at 8:50 pm

カテゴリー: ESP32

Repair M5STACK Power Switch

leave a comment »

M5STACK の Power Switch 修理方法              2018.06.05

M5STACK の Power Switch が取れてしまう事があります。
小さなスイッチ1つの故障で 高価な M5STACK が使えなくなります。
部品を交換する修理する方法をまとめました。
部品費は 1個 14円から 41円程度です。

故障の原因:
_ スイッチカバーとスイッチの間の隙間により スイッチカバーが斜めに
_ なります。そのまま押すと、基板のスイッチが斜めに押され
_ 無理な力が加わる事により ハンダが剥がれ部品が取れる 為です。

部品の再使用:
スイッチが取れて 形状が良い場合と テスターでスイッチの ON / OF が良い場合は
スイッチの取り付けだけで済む場合があります。


準備:
1. Power Switch 購入:WIN ELEC-TECH CO.,LTD Store
Switch Nomen:3X4mm 4Pin Push Button Switch Side Push
Switch No:TS-1286VE-4
Switch Size:2.9 x 3.5
販売:Aliexpress : WIN ELEC-TECH CO.,LTD  :  TS-1286VE-4
価格:1個 14円。( 10個 $1.25 )
輸送期間:22日

1. Power Switch 購入:Happy&lucky gift house Store
Switch Nomen:Little Turtle legs side by touch switch button switch
Switch No:?
Switch Size:2.9 x 3.5
販売:Aliexpress : Happy&lucky gift house  :  ?
価格:1個 41円。( 10個 $3.71 )
輸送期間:9日

部品の確認:
_ サイズを確認してください。
_ テスターで スイッチの ON / OFF を確認してください。

2. ハンダゴテ:半田ごての先は ランド(ハンダ面) より小さい物を使用します。
3. その他、ソルダータオル(ハンダ吸い取り)、ピンセット、細いカッターナイフ。


以下の手順等は 各自の責任で行ってください。この記事は 私の備忘録です。

修理手順:
0. 基板を外す:全体を分解し基板だけにします。この分解は非常に難解です。
1. 六角のネジを外します。
2. スピーカーのワイヤーを少し抜きます。
_ ワーヤーが切れない様に無理にワイヤーを引っ張らない事。
3. スピーカーを抜きます。基板を移動できる隙間が出来ます。
4. 基板を左にずらして 固定している場所をずらし LOCK を外します。
5. 基板上側を上に少し持ち上げ 基板をケースから僅か上に外します
_ この持ち上がる場所は ほんの僅かの場所で なかなか外す事が難しいです。
_ TFT のフレキシブルワーヤーが裏にあり 無理に力を加えると切れますので要注意。
注意;全体に力を加えない事。ワーヤーや部品が壊れてしまう力を想像してください。
注意;ピンセット等の金属を使用する時は 金属の先で チップ部品を破損しない事。
注意;チップ部品や曲がる恐れのある部品に 力 を加えて基板を外さない事。

部品の取り外し:
部品が上記画像の様に綺麗に取れてしまえば、容易ですが、部品の一部が基板に残ったり
基板のパターンが剥がれていると難解になります。

部品が綺麗に取れている場合は 基板上に残ったハンダをハンダタオルで綺麗に取ります。
注意;基板に力を加えない事。

部品の一部が基板についている場合。
画像左側のハンダを溶かしながら ピンをカッターナイフ等の薄い金属で上に持ち上げます。
注意;基板のパターンに力を加えない事。
画像左側には 小さな抵抗があり 熱や力を加えない事。

部品を取りパターンのハンダを綺麗にします。
他の汚れも綺麗にします。アルコール等で綺麗にしてください。

部品の取り付け:
部品は基板の2つの穴に合わせて位置を決めます。少し余裕がありますので
基板の外側に寄せます。これは スイッチカバーとの隙間を少なくする為です。
スイッチの押す部分とスイッチのカバーが揃うと カバーとのズレが無くなり
スイッチの感触が良くなる事と 故障も無くなります。

位置が決まりましたら 何らかの方法で固定する様にしてください。
ハンダ面より細いハンダとハンダ小手先で短時間(0.5秒以内)にハンダを付けます。
この時、ハンダの量は極力少なくしてください。端子にハンダが丸くなる程乗せない事。
ハンダ後は アルコール等で綺麗にする事。破損した部品が無いか目視点検してください。

基板の組み立て:
分解の逆の手順で組み上げてください。くれぐれも力を加えないでください。


感想:
友人の M5STACK のスイッチが取れた為、上記の手順で交換しました。
自分の M5STACK のスイッチも取れた為、上記の手順で交換しました。
スイッチの端子をハンダで外す時は 力を加えず パターンを剥がさない様にする為に
_ かなり緊張しました。
部品取り付け時も 隣の抵抗を破損する近距離にある為に かなり緊張しました。
部品の購入について:その後 個数の記憶の曖昧もあり 注文時に確認してください。
M5STACK の Power Switch は モバイル用のスイッチを使用しています。
ESP32 に於いて Power Switch による ON / OFF は初めて採用された回路です。
_ この動作理論を調べると面白いかと思います。
不具合対策:スイッチカバーとスイッチの隙間をゼロにすると良いです。
_ ハンダ部への斜めの力が無くなり 取れ難くなります。
_ さらに スイッチの感触が良くなります。


Written by macsbug

6月 5, 2018 at 5:00 pm

カテゴリー: ESP32

M5STACK and mini bread board

leave a comment »

M5STACK と mini bread board をレイアウトしてみました。      2018.06.04


準備:

1. mini bread board:3個

2. ピンソケット:3個

_ ピンを 長さを加工したり 90度に加工して ブレッドボードに挿します。


ミニブレッドボード に ピンソケットで 一輪挿し。


感想:

ブレッドボードは あまり使用しませんが 簡単にできます。


Written by macsbug

6月 4, 2018 at 7:57 am

カテゴリー: ESP32, ESP8266

NES GAME with M5STACK

leave a comment »

M5STACK で NES GAME を 動かしてみました。        2018.05.07

Mac ( マック) での方法を記載します。
FACES を購入しますと マリオ風のゲームがインストールされています。
ゲームは エミュレーターで動いています。

NES EMULATOR と GAME の ソースは

m5stack/M5Stack-nesemu にあります。

M5Stack-nesemu-master を DL し、

中にある firmware.zip を解凍します。

4つのファイルを転送すると動きます。

1. bootloader.bin

2. partitions.bin

3. nesemu.bin

4. SuperMario4.nes


m5stack/M5Stack-nesemu:(SuperMario4.nes) をインストールする方法。
_ デスクトップに rom フォルダーを作成し bootloader.bin, partitions.bin,
_ nesemu.bin, SuperMario4.nes を入れておきます。
以下の4つを Terminalへ入力します。
1. esptool.py –port /dev/tty.SLAB_USBtoUART write_flash 0x1000 ~/Desktop/rom/bootloader.bin
2. esptool.py –port /dev/tty.SLAB_USBtoUART write_flash 0x8000 ~/Desktop/rom/partitions.bin
3. esptool.py –port /dev/tty.SLAB_USBtoUART write_flash 0x10000 ~/Desktop/rom/nesemu.bin
4. esptool.py –port /dev/tty.SLAB_USBtoUART write_flash 0x100000 ~/Desktop/rom/SuperMario4.nes

M5Stack-nesemu には、Controller、ROM,Copyright について書かれており
通常 FACES GAME Controller で操作できますが 他に NES, Playstation 1, 2
controller の接続方法が書かれています。(CLK=14,DAT=27,ATT=16,CMD=2)


Terminal入力の説明:
esptool.py –port /dev/tty.SLAB_USBtoUART write_flash 0x100000 ~/Desktop/rom/galaxian.nes
1. Python 2.7 又は Python 3.4以上がシステムにインストールされている事。
2. esptool.py:esptool.py がマックにある事が条件です。
_ 無い場合: esptool.py の Read.me に書かれています。
_ Terminal に 「pip install esptool」 を入力しますと動きます。
_ パーミッションエラーの場合は 「sudo pip install esptool 」を入力します。
3. –port /dev/tty.SLAB_USBtoUART:接続したM5STACKの USBの名前です。
_ 異なる USB デバイスの場合は 接続する USBの名前にします。
_ USBの名前の確認は Terminal に ls -l /dev/tty.* を入力しますと
_ usb デバイス名が表示されます。 ( /dev/tty.SLAB_USBtoUART )

crw-rw-rw-  1 root  wheel   19,   8  5  7 05:18 /dev/tty.SLAB_USBtoUART

4. write_flash:M5STACK の FLASH Memory へ書き込みます。
_ memo : 読み込みの場合は read_flash になります。
5. 0x100000:16進の100000番地に書き込みます。
6. ~/Desktop:デスクトップの場所です。他に書類の場所は Document です。
7. /rom:rom というフォルダーを作り nes ROM データーを入れておきます。
8. /galaxian.nes:galaxian の ROM DATA です。

MEMO:データーを読み込む方法:
_ write_flash を read_flash にし 読み込む長さを追加します。
例:esptool.py –port /dev/tty.SLAB_USBtoUART read_flash 0x1000 0x0010 ~/Desktop/data.bin
_ read_flash 開始番地 (0x000000)  長さ(0x0010 : 16byte)


使用方法は M5Stack Community の M5Stack Russia
_ Урок 13. FACES. Запуск игр от Dendy (NES) に記載されています。
_ 内容を お読み下さい。( 参考になる 検索先が書かれています ) 。

データーの構成:以下の4つで構成されています。
_ M5Stack-nesemu-master の中にある firmware.zip を解凍した
_ ものと同じで 0x100000 は ゲームのデーター です。

0x1000   bootloader.bin
0x8000   partitions.bin
0x10000  nesemu.bin
0x100000 Baltron.nes

配置:それぞれの bin は バイナリー表示の番地へ配置されます。
例:0x1000 bootloader.bin:bootloader.bin は 0x1000番地へ配置されます。
注意:書き込み番地を間違えますと 動かなくなるかもしれません。
_  各自の責任で行ってください。


解説は ESP32 DOWNLOAD TOOL を使用し Windows の方法が書かれています。
ここでは Mac ( マック) での方法を解説します。
使用環境は iMac 27 MacOS Sierra を使用。古いOSでは出来ない場合があります。

Mac の Terminal (ターミナル) を使用する方法です。
Terminal は アプリケーション フォルダー /  ユーティリティフォルダーにあります。
ゲームのデーター「galaxian.nes」(購入したデーター等) を用意します。
Desktop に rom フォルダーを作り、この中に「galaxian.nes」を入れます。
FACES (又は M5STACK ) と マックを USB接続します。
Terminal を起動し、以下の様に入力(1行です) しますと
esptool.py –port /dev/tty.SLAB_USBtoUART write_flash 0x100000 ~/Desktop/rom/galaxian.nes

esptool.py v2.2
Connecting........_____....._____.
Detecting chip type... ESP32
Chip is ESP32D0WDQ6 (revision 1)
Uploading stub...
Running stub...
Stub running...
Configuring flash size...
Auto-detected Flash size: 4MB
Compressed 40976 bytes to 10231...
Wrote 40976 bytes (10231 compressed) at 0x00100000 in 0.9 seconds (effective 363.9 kbit/s)...
Hash of data verified.

Leaving...
Hard resetting...

と表示され「galaxian」が動きます。


Windows の方法:MY氏から方法を教えて頂きました。感謝致します。
_ Windowsの場合は、以下の内容を “flash.cmd” という名前で各FWファイルを
_ 同じ場所に保存し、同じフォルダに “esptool.exe”を置けば、あとは NES
_ ファイルをドラッグ ドロップすると書き込めます。
—–
@echo off
SET COM_PORT=COM3
SET NES_IMAGE=%1
esptool.exe –chip esp32 –port %COM_PORT% –baud 921600 –before default_reset –after hard_reset write_flash -z –flash_mode dio –flash_freq 40m –flash_size detect 0x1000 bootloader.bin 0x10000 nesemu.bin 0x8000 partitions.bin 0x100000 %NES_IMAGE%
—–


自作データー集:
NES ROM は 購入した物や 怪しい所とか 幾つか方法があります。
ゲームを自作したデーターが公開されてます。
1. NES研究室 – 自作ゲーム
_ 「tkrpg100」、「tkshoot100」があります。
2. ど~もeagle0wlです:正規公開されているゲーム専用機のROMイメージ
_ 「2048」、「ブレイドバスター」があります。

3. 野うさぎ亭 – NESプログラミング
_ 「RevolvingGems」があります。


感想:
Terminal 操作:解りにくさや 難さがありますが 今回の方法で 出来ると
_ 便利かと思います。
自作ゲーム: asm で書かれており 開発時の熱意を感じます。
期待する機能:M5Stack-SD-Updater の様に SD に NES-EMU, NES DATA を
_ 入れ M5STACK のメニューリストから LOAD 出来ると便利かと思います。
_ 私の力量では無理ですので どなたか よろしくお願い致します。
掘り出し物:ファミコン時代にゲームを遊び、購入したゲームのROMを
_ 読み出して勉強した人もいるかと思います。M5STACKで再び再現でき
_ 保存したデーターが生き返る事になったかと思います。
_ NES EMULATOR を公開された M5STACK TEAM に感謝致します。


Written by macsbug

5月 7, 2018 at 12:00 pm

カテゴリー: ESP32

M5STACK WiFiScan

leave a comment »

ESP8266 WiFi Scan を M5STACK に移植しました。     2018.05.03

ORIGINALは oaquimorg/esp8266_wifi_scan です。
joaquim.org : joaquimorg氏の記事:ESP8266 WiFi Scan
joaquimorg氏 に感謝致します。

オリジナルのディスプレーは 2.4 inch 320×240 です。
M5STACK も 320×200 ですが 2.0 inch の為 文字が小さく見づらいですが 良しとします。

Free_Fonts.h は M5STACK Library の中にあります。

SD にアプリを入れて起動する為に SD Update のスケッチが入っています。


スケッチ:WiFiScan:
_ WiFiScan のフォルダーの構成は以下の3つです。
_ icons.h は esp8266_wifi_scan から使用すると良いです。
_ WiFiScan Folder : [ WiFiScan.ino, icons.h, Free_Fonts.h ]

// Scan WiFi networks. (c)joaquim.org
// https://github.com/joaquimorg/ESP8266/tree/master/esp8266_wifi_scan
// https://www.joaquim.org/esp8266-wifi-scan/
// Github:https://macsbug.wordpress.com/2018/05/03/m5stack-wifiscan/
#include "WiFi.h"
#include <M5Stack.h>
#include "M5StackUpdater.h"                          // SD Update
#include "icons.h"
//#include "Free_Fonts.h"

typedef struct {
  String SSID;
  uint8_t encryptionType,Active,Update;
  int32_t RSSI,Channel;
} NetInfo;
NetInfo networkInfo[30];
typedef struct {
  int32_t Total,RSSI;
}ChannelInfo;
ChannelInfo totalChannel[14],totalChannelOld[14];
#define TEXT_SIZE 10
int initclear = 1;

void setup() {
  Serial.begin(115200);delay(500);
  M5.begin();
  Wire.begin(); 
  if(digitalRead(BUTTON_A_PIN) == 0){                // SD Update
     updateFromFS(SD); ESP.restart();                // SD Update
  }                                                  // SD Update
  M5.Lcd.setTextColor(TFT_BLACK, TFT_WHITE);
  M5.Lcd.fillScreen(TFT_WHITE);
  //M5.Lcd.setFreeFont(FSSB12);
  //M5.Lcd.setFreeFont(FSS9);
  M5.Lcd.fillScreen(ILI9341_BLACK);
  M5.Lcd.drawBitmap(110, 10, wifiBitmap, 100, 70, ILI9341_WHITE);
  //M5.Lcd.setFont(&FreeMono9pt7b);
  M5.Lcd.setTextColor(ILI9341_YELLOW, ILI9341_BLACK);
  M5.Lcd.setCursor(105, 100);
  M5.Lcd.print("Wifi Scan");
  M5.Lcd.setTextColor(ILI9341_GREEN, ILI9341_BLACK);
  M5.Lcd.setCursor(95, 130);
  M5.Lcd.print("joaquim.org");
  //M5.Lcd.displayUpdate();
  M5.Lcd.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
  Serial.println("esp8266 Wifi Scan ... ");
  // Set WiFi to station mode and disconnect from an AP if it was previously connected
  WiFi.mode(WIFI_STA);
  WiFi.disconnect();
  delay(5000);
  Serial.println("running... ");
  //M5.Lcd.fillScreen(ILI9341_BLACK);
  M5.Lcd.setCursor(75, 200);
  M5.Lcd.println("Scanning WiFi...");
  //M5.Lcd.displayUpdate();
  memset( networkInfo,     0x0, sizeof(networkInfo) );
  memset( totalChannel,    0x0, sizeof(totalChannel) );
  memset( totalChannelOld, 0x0, sizeof(totalChannelOld) );
  M5.Lcd.setTextSize(1);
}

void showScreen1( int num ) {
  int pos = 0, col = 0, total = 0;  
  for (int i = 0; i < num; ++i) {
    if (networkInfo[i].Active == 1) {     
      M5.Lcd.fillRect(col, 2 + (TEXT_SIZE * pos),160,TEXT_SIZE,BLACK);      
      M5.Lcd.setCursor(col, 2 + (TEXT_SIZE * pos));       
      /*if (networkInfo[i].encryptionType == ENC_TYPE_NONE) {
        M5.Lcd.drawBitmap(col,(TEXT_SIZE * pos),unlockBitmap10,10,10,GREEN);
      } else {
        M5.Lcd.drawBitmap(col,(TEXT_SIZE * pos),lockBitmap10,10,10,RED);
      }*/    
      M5.Lcd.setCursor(col + 14, 2 + (TEXT_SIZE * pos)); 
      M5.Lcd.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
      if (networkInfo[i].RSSI <= -80) {
        M5.Lcd.setTextColor(ILI9341_RED, ILI9341_BLACK);
      } else if (networkInfo[i].RSSI >= -80 && networkInfo[i].RSSI < -70){
        M5.Lcd.setTextColor(ILI9341_YELLOW, ILI9341_BLACK);
      } else {
        M5.Lcd.setTextColor(ILI9341_GREEN, ILI9341_BLACK);
      }   
      M5.Lcd.print(networkInfo[i].SSID);
      //Serial.print(networkInfo[i].SSID);Serial.print(" : ");
      //Serial.println(networkInfo[i].RSSI);*/
      
      //M5.Lcd.fillRect(0, (TEXT_SIZE * pos), 240, TEXT_SIZE, ILI9341_BLACK);
      /*if (networkInfo[i].RSSI <= -80) {
        M5.Lcd.drawBitmap(120,20 + (TEXT_SIZE * pos),level1Bitmap, 8, 8,RED);
      } else if (networkInfo[i].RSSI >= -80 && networkInfo[i].RSSI < -70){
        M5.Lcd.drawBitmap(120,20 + (TEXT_SIZE * pos),level2Bitmap,8,8,YELLOW);  
      } else {
        M5.Lcd.drawBitmap(120,20 + (TEXT_SIZE * pos),level3Bitmap,8,8,GREEN);
      }*/
      pos++;
      total++;
      if ( total > 21) break;
      if ( total == 11 ) {
        col = 160;
        pos = 0;
      }
    }
  }
}

void BubbleSort(NetInfo netInfo[], int numLength) {
  uint8_t i, j, flag = 1;    // set flag to 1 to start first pass
  NetInfo temp;              // holding variable
  for (i = 1; (i <= numLength) && flag; i++){
    flag = 0;
    for (j = 0; j < (numLength - 1);j++){// ascending order simply changes to
      if (abs(netInfo[j + 1].RSSI) < abs(netInfo[j].RSSI)){ 
        temp = netInfo[j];             // swap elements
        netInfo[j] = netInfo[j + 1];
        netInfo[j + 1] = temp;
        flag = 1;                      // indicates that a swap occurred.
      }
    }
  }
  return;   //arrays are passed to functions by address; nothing is returned
}

void addToArray( NetInfo netInfo ) {
  uint8_t total = 0;
  for (int i = 0; i < 30; ++i) {
   if (networkInfo[i].Active == 1 && (networkInfo[i].SSID == netInfo.SSID)){
     networkInfo[i] = netInfo;
     //Serial.print("Found :" + netInfo.SSID + " ");Serial.println(i);
     return;
   } 
  }
  for (int i = 0; i < 30; ++i) {    
    /*Serial.print(i);Serial.print(" ");    
    Serial.print(networkInfo[i].Active);
    Serial.println(" " + networkInfo[i].SSID + " ");*/      
    if ( networkInfo[i].Active == 1 ) {
      total++;
    } 
  } 
  if ( total < 30 ) {
    networkInfo[total] = netInfo;
    //Serial.print("New :" + netInfo.SSID + " ");Serial.println(total);
  }
}

void drawGraphScreen() {
  M5.Lcd.drawRect(1, 120, 319, 105, ILI9341_DARKGREY);
  M5.Lcd.setTextColor(TFT_WHITE, TFT_BLACK); 
  M5.Lcd.drawString("01 02 03 04 05 06 07 08 09 10 11 12 13 14",50,210);
  M5.Lcd.drawFastHLine(40, 205, 265, ILI9341_ORANGE); 
  M5.Lcd.setTextColor(TFT_WHITE, TFT_BLACK); 
  M5.Lcd.drawString("-99", 15, 195);
  M5.Lcd.drawString("-80", 15, 185);
  M5.Lcd.drawString("-70", 15, 175);
  M5.Lcd.drawString("-60", 15, 165);
  M5.Lcd.drawString("-50", 15, 155);
  M5.Lcd.drawString("-40", 15, 145);
  M5.Lcd.drawString("-30", 15, 135);
  M5.Lcd.drawString("-20", 15, 125);
  M5.Lcd.drawFastVLine(40, 125, 80, ILI9341_ORANGE);
}

void drawGraph() {
  for (int i = 0; i < 14; ++i) {
    M5.Lcd.drawFastVLine(55 + (i * 18), 125, 75, ILI9341_BLACK);
    if ( totalChannelOld[i].Total > 0) {
      M5.Lcd.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
      M5.Lcd.setCursor(60 + (i * 18), 200 - totalChannelOld[i].RSSI);
      M5.Lcd.print("  ");
    }  
    if ( totalChannel[i].Total > 0) {
      M5.Lcd.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
      M5.Lcd.setCursor(60 + (i * 18), 200 - totalChannel[i].RSSI);
      M5.Lcd.print(totalChannel[i].Total);     
      M5.Lcd.drawFastVLine(55 + (i * 18), 200 - totalChannel[i].RSSI,
                          totalChannel[i].RSSI, ILI9341_GREEN);
    } 
    totalChannelOld[i] = totalChannel[i];
  }
}

void loop() {
  int n = WiFi.scanNetworks();
  int m = n;
  NetInfo netInfo;
  for (int i = 0; i < 30; ++i) {
    networkInfo[i].Update = 0;
  }
  for (int i = 0; i < 14; ++i) {
   totalChannel[i].Total = 0;
   totalChannel[i].RSSI = 0;
  }
  if ( initclear == 1 ) {
    initclear = 0;
    M5.Lcd.fillScreen(ILI9341_BLACK);
    drawGraphScreen();    
  }
  if (n == 0) {
    //M5.Lcd.setTextSize(2);
    M5.Lcd.fillScreen(ILI9341_BLACK);
    M5.Lcd.setTextColor(ILI9341_BLUE, ILI9341_BLACK);
    M5.Lcd.setCursor(0, 10);
    M5.Lcd.println();M5.Lcd.println();
    M5.Lcd.print("No networks found...");M5.Lcd.println();
    M5.Lcd.println("Scanning...");
    //M5.Lcd.setTextSize(1);
  } else {
    if ( m > 30 ) m = 30;
    for (int i = 0; i < m; ++i) {
      netInfo.SSID = WiFi.SSID(i);
      netInfo.encryptionType = WiFi.encryptionType(i);
      netInfo.RSSI = WiFi.RSSI(i);
      netInfo.Channel = WiFi.channel(i);
      netInfo.Active = 1;
      netInfo.Update = 1;
      addToArray(netInfo);
      totalChannel[netInfo.Channel - 1].Total = 
      totalChannel[netInfo.Channel - 1].Total + 1;
      if ((netInfo.RSSI + 100) > totalChannel[netInfo.Channel - 1].RSSI){
        totalChannel[netInfo.Channel - 1].RSSI = (netInfo.RSSI + 100);
      }
    }
    for (int i = 0; i < 30; ++i) {
      if ( networkInfo[i].Update == 0 ) {
           networkInfo[i].SSID   = "";
           networkInfo[i].RSSI   = 255;
           networkInfo[i].Active = 0;
      }
    }
    BubbleSort(networkInfo, 30);
    M5.Lcd.setCursor(5, 230);
    M5.Lcd.setTextColor(ILI9341_CYAN, ILI9341_BLACK);
    M5.Lcd.print(n);
    M5.Lcd.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
    M5.Lcd.print(" networks found");   
    //M5.Lcd.fillRect(0, 20, 240, 320, ILI9341_BLACK);
    showScreen1(30);
    drawGraph();   
  }
}

//icons.h
const unsigned char wifiBitmap [] PROGMEM = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 252, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
3, 255, 255, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 255, 255, 248, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 31, 255, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 255, 
255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 128, 0, 0, 0, 0, 
0, 0, 0, 1, 255, 255, 255, 255, 192, 0, 0, 0, 0, 0, 0, 0, 3, 255, 255, 
255, 255, 224, 0, 0, 0, 0, 0, 0, 0, 7, 255, 255, 255, 255, 240, 0, 0, 0, 
0, 0, 0, 0, 15, 255, 255, 255, 255, 248, 0, 0, 0, 0, 0, 0, 0, 15, 255, 
255, 255, 255, 252, 0, 0, 0, 0, 0, 0, 7, 255, 255, 255, 255, 255, 255, 
248, 0, 0, 0, 0, 0, 127, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 
0, 255, 255, 255, 255, 255, 255, 255, 255, 192, 0, 0, 0, 3, 255, 255, 
255, 255, 255, 255, 255, 255, 224, 0, 0, 0, 7, 255, 255, 255, 255, 255, 
128, 0, 1, 240, 0, 0, 0, 7, 255, 255, 255, 255, 255, 0, 0, 0, 120, 0, 0,
0, 15, 255, 255, 255, 255, 254, 0, 0, 0, 60, 0, 0, 0, 31, 255,255, 255, 
255, 252, 0, 0, 0, 28, 0, 0, 0, 31, 255,255, 255, 255, 248, 0, 0, 0, 30, 
0, 0, 0, 63, 255,255, 255, 31, 240, 0, 0, 30, 14, 0, 0, 0, 63, 7, 7, 6, 
15, 240, 255, 255, 62, 14, 0, 0, 0, 63, 7, 7, 6, 15, 224, 255, 255, 62, 
7, 0, 0, 0, 127, 7, 7, 14, 15, 224, 255, 255, 62, 7, 0, 0, 0, 127, 135, 
7, 15, 31, 224, 255, 255, 30, 7, 0, 0, 0, 127, 135, 7, 15, 255, 224, 
255, 255, 0, 3, 0, 0, 0, 127, 134, 6, 15, 255, 224, 252, 0, 30, 3, 0, 0, 
0, 127, 130, 2, 14, 31, 224, 252, 0, 62, 3, 0, 0, 0, 127, 130, 2, 30, 
31, 224, 252, 0, 62, 3, 0, 0, 0, 127, 194, 34, 30, 31, 224, 252, 0, 62, 
3, 0, 0, 0, 127, 194, 34, 30, 31, 224, 255, 254, 62, 3, 0, 0, 0, 127, 
194, 34, 30, 31, 224, 255, 254, 62, 3, 0, 0, 0, 127, 194, 34, 30, 31, 
224, 255, 254, 62, 3, 0, 0, 0, 127, 192, 32, 62, 31, 224, 255, 254, 62, 
3, 0, 0, 0, 127, 224, 32, 62, 31, 224, 255, 254, 62, 3, 0, 0, 0, 127, 
224, 96, 62, 31, 224, 255, 254, 62, 3, 0, 0, 0, 127, 224, 112, 62, 31, 
224, 252, 0, 62, 3, 0, 0, 0, 127, 224, 112, 62, 31, 224, 252, 0, 62, 3, 
0, 0, 0, 127, 224, 112, 126, 31, 224, 252, 0, 62, 3, 0, 0, 0, 127, 240, 
112, 126, 31, 192, 252, 0, 62, 7, 0, 0, 0, 127, 240, 240, 126, 31, 192, 
252, 0, 62, 7, 0, 0, 0, 63, 255, 255, 255, 255, 192, 248, 0, 62, 7, 0, 
0, 0, 63, 255, 255, 255, 255, 192, 0, 0, 0, 14, 0, 0, 0, 63, 255, 255, 
255, 255, 128, 0, 0, 0, 14, 0, 0, 0, 31, 255, 255, 255, 255, 128, 0, 0, 
0, 30, 0, 0, 0, 31, 255, 255, 255, 255, 0, 0, 0, 0, 28, 0, 0, 0, 15, 255, 
255, 255, 255, 0, 0, 0, 0, 56, 0, 0, 0, 7, 255, 255, 255, 254, 0, 0, 0, 
0, 248, 0, 0, 0, 7, 255, 255, 255, 252, 0, 0, 0, 1, 240, 0, 0, 0, 1, 255, 
255, 255, 255, 255, 255, 255, 255, 224, 0, 0, 0, 0, 255, 255, 255, 255, 
255, 255, 255, 255, 192, 0, 0, 0, 0, 63, 255, 255, 255, 255, 255, 255, 
255, 0, 0, 0, 0, 0, 7, 255, 255, 255, 255, 255, 255, 240, 0, 0, 0, 0, 0, 
0, 7, 255, 255, 255, 255, 248, 0, 0, 0, 0, 0, 0, 0, 3, 255, 255, 255, 255, 
240, 0, 0, 0, 0, 0, 0, 0, 3, 255, 255, 255, 255, 224, 0, 0, 0, 0, 0, 0, 
0, 1, 255, 255, 255, 255, 192, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 
128, 0, 0, 0, 0, 0, 0, 0, 0, 63, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
31, 255, 255, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 255, 255, 248, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 3, 255, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 255, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

const unsigned char battBitmap10 [] PROGMEM = {
0, 0, 0, 0, 0, 0, 127, 255, 0, 127, 193, 192, 127, 129, 192, 127, 1, 192, 
126, 1, 192, 127, 255, 0, 0, 0, 0, 0, 0, 0 };
 
const unsigned char lockBitmap10 [] PROGMEM = {
0, 0, 30, 0, 51, 0, 33, 0, 33, 0, 127, 128, 115, 128, 115, 128, 63, 0, 0, 
0 };
        
const unsigned char unlockBitmap10 [] PROGMEM = {
0, 0, 30, 0, 51, 0, 1, 0, 1, 0, 127, 128, 127, 128, 127, 128, 63, 0, 0, 0 };

const unsigned char level1Bitmap [] PROGMEM = {
7, 128, 63, 240, 240, 60, 199, 140, 31, 224, 48, 48, 7, 128, 12, 192, 0, 
0, 3, 0, 3, 0 };

const unsigned char level2Bitmap [] PROGMEM = {
0x00, 0x00, 0x00, 0x18, 0x18, 0xd8, 0xd8, 0x00 };

const unsigned char level3Bitmap [] PROGMEM = {
0x00, 0x03, 0x03, 0x1b, 0x1b, 0xdb, 0xdb, 0x00 };

const unsigned char openBitmap [] PROGMEM = {
0x00, 0x18, 0x24, 0x42, 0x42, 0x24, 0x18, 0x00 };

const unsigned char closeBitmap [] PROGMEM = {
0x00, 0x18, 0x3C, 0x7E, 0x7E, 0x3C, 0x18, 0x00 };

Written by macsbug

5月 3, 2018 at 7:00 pm

カテゴリー: ESP32