macsbug

Archive for 6月 2019

M5Stack Nixie tube Clock

leave a comment »

M5Stack で ニキシー管時計を製作しました。                 2019.06.16

M5Stack に 130円の リアルタイムクロックボード(RTC)を追加し 表示は ニキシー管画像 を使用しました。
ネット接続ができない場所でも RTCボード があると動作します。
RTCボード が無くても ネット接続 ( NTP ) できると動作します。

.

機能:Cボタン スイッチで 表示を切り換えます。
_  時計機能:130円の リアルタイムクロックボード(RTC)を追加しました。
_        RTCが無くとも動作します。
_  NTP設定:起動時に ネット接続が可能であれば RTCにNTPを保存します。
_  時間調整:ネット接続が可能であれば 決められた時間にNTP時間を調整(保存)します。

動作:ネットのNTPへ接続し 日付と時間のデーターを入手します。
_  日付と時間を RTC へ保存します。
_  ネット環境が無いか 接続出来ない場合は 上記のNTPをパスします。
_  RTC から 日付と時間を取得し ディスプレーのニキシー管に表示します。
_  RTC が無い場合は NTP の時間を使用します。
_  時間の更新は ESP32内の Timer を使用します。( 理由は 製作メモ を参照ください) 

DS3231 ボード:M5Stackは 時計機能が無い為、DS3231 リアルタイムクロック (RTC) を追加します。
_ 使用する DS3231 は ラズベリーパイ用の RTC Module で 130円と低価格で小型です。
_ Raspberry Pi RTC Module With Battery:回路図参照の事。
_ DS3231 の使用事例、価格、販売店 は 「DS3231 RTC in ESP8266」を参照ください。
_ 日本国内は高いですので ebay か Aliexpress で入手します。
_ 


.
部品の準備:DS3231 Precision RTC Clock Memory Module For Arduino Raspberry Pi
販売:ebay の worldchips Store は 製品管理は良いです。輸送期間は8日〜16日を経験しています。 
注意:Aliexpress や ebay は 販売画像と異なる物が来る事があります。
_  DS3231 Module は 電池付きであるかを確かめてください。
_  以下の worldchips Store を再調査すると Battery 付きではありませんでした。2019.06.29
_  最近、中◯からのバッテリの輸送は出来ない話を聞いています。2019.07.07
_  CR1025:3V 10.0 x 2.5mm。2019.07.07
_  ボタン電池一覧表で 電圧とサイズを確認して購入してください。2019.07.07

Store price memo    
 ebay : worldchips  127円  1個    
 ebay : worldchips  118円  10個 1184円    
 ebay : lincx  116円  1個    
 ebay : 3c_topstore  214円  1個 調査済(追記)  ⭕ 

.
追記:2019.07.23。3c_topstore Store の調査結果:
_  価格:1個 215円 ( 10個 $19.9 )。バッテリー付。輸送期間=19日。
追記:2019.07.04。DS3231 価格:
_  その後の調査で スイッチサイエンスの DS3231 は 1個 2104円です。約17倍の価格。
.


.
M5Stack 改造:DS3231 BOARD の取り付け。

1. DS3231 BOARD の BATTERY が 3.0V ある事を確認します。
2. BATTERY の位置を移動します。移動とハンダ付け時に向きに注意してください。
_ 
3. DS3231 BOARD をカプトンテープで保護します。
4. ハンダ付け時に周囲を溶かさない様にテープ等でケースを保護します。
5. M5Stackの基板にある小さな部品に接触や負担を与えない配置を考えます。
6. 回路図に従い 配線します。
7. M-BUS 3.3V と GROVE PIN にハンダ付けする時は 短時間(0.5秒)に実施します。
8, 注意:M5Stackには 小さな部品があり 接触, 衝撃, 熱 を加えないでください。


.
ニキシー管 画像のHex データー製作:元画像 70×134 pixel ( png ):

_ 12枚の画像 70×134 から vfd_70x134.c を作成します。

1.  vfd_18x34.c と vfd_35x67.c は 「M5StickC Nixie tube Clock」から入手します。

2.  vfd_70x134_0, , , , vfd_70x134_9, vfd_70x134_n.png, vfd_70x134_q.png
_ 以下の画像を DL ( ドラッグ アンド ドロップ ) し
_ 「M5StickC Nixie tube Clock」を参照し
_ 「lcd-image-converter 20180211-beta」で vfd_70x134.c を作成します。
_ 少し手間かもしれませんが マスターすると 綺麗な作品を自由に作る事が可能になります。

3. apple_35x41.png:Apple icon が好きな方へ。 apple_35x41.c は リストに記載しました。
_ 

4. vfd_70x134_0 〜 vfd_70x134_9, vfd_70x134_n.png, vfd_70x134_q.png

.

5. スケッチ:
_ 下の様に スケッチを用意します。
_ ライブラリー:RTClib : スケッチ内に入れるか ライブラリーにいれます。
_ フォルダーは以下の様になります。
_  


.
製作メモ:Production note
1. 時間の更新は ESP32内の Timer を使用します:
_ RTC の データーを 1秒毎に取得すると なぜか 飛び飛びの値しか取得出来ません。
_ いろいろ試しましたが 技術力が無い為か 1秒毎に取得する事はできませんでした。
_ 対策:その為に 1秒毎の動作は ESP32 の Timer を使用しています。
_ ネットでのサンプルを見ると 3秒毎に取得する例が殆どで 1秒単位の表示ができません。
_ M5Stack のサンプルは Timer を使用しています。
_ Timer を使用する場合は 適切な 単位の宣言(unsigned long)が必要です。
2. RTC は CS が無きため GPIO は D(SDA)=5, C(SCK)=13 としました。

maffucci氏の M5Stack Fire Robottillo:Stack Case を製作しました。
ロボチックな感じがなかなか良いです。

3. トラブルシュート:
_ シリアルモニター:「RTC is NOT running!」が表示される:DS3231 の配線を確認します。
_ ディスプレーの表示:「2165/165/165 165:165:85」になる:DS3231 の配線を確認します。
_ ディスプレーの表示:「2010 ,,,, 」になる:DS3231 のバッテリー不足です。交換します。
_ バッテリー交換:電圧をチェックしてください。


.
追記:青いニキシー管:2019.07.04
_ ニキシー管イメージは 微妙で 数字周りのニキシー管イメージが少ない感じです。
_ 


.
参考:
M5StickC Nixie tube Clock:2019.06.15
DS3231 RTC in ESP8266:2016.10.07:
ESP8266 + RTC + NTP デジタル時計:2015.12.05:
+DEVICE PLUS:ESP32とRTCで「二度寝防止アラーム時計」を作ろう!
Raspberry Pi RTC Module With Battery:回路図があります。


.
感想:
_ 前回 M5StickC Nixie tube Clock:これに基づき M5Stack も製作しました。
_ 小型化:PROTO Board か Expansion Board は大きくなりますので本体に収めました。
_ 本体未改造方法:Expansion Board か Expansion Adapter で行なう方法があります。
_ Nixie 画像 70×134 pixel :M5Stack の画面に合わせ作成しました。
_ DS3231のバッテリー:ハンダ付けです。電圧が無い場合は交換する必要があります。
_ DS3231 モジュールが無い場合:NTPやPC TIME を使用し電源を切らなければ使用できます。
_ 表示:ニキシー数値のサイズや位置を変更すると 好みのデザインができます。

_ 追記:2019.06.30。
_  facebook:関氏の情報:「電池は省略し本体のBATT端子に接続しました。」
_   配線は使い慣れた0.2mmのホルマル線を使用。
_   GROVEのGNDは付けにくいのでUSBフレームのGNDに強引にはんだ付け。


.
スケッチ:M5Stack nixie tube clock : 2019.06.16 macsbug

// M5Stack nixie tube clock : 2019.06.16 macsbug
// https://macsbug.wordpress.com/2019/06/16/m5stack-nixie-tube-clock/
// RTC DS3231 : https://wiki.52pi.com/index.php/Raspberry_Pi_Super_Capacitor_RTC(English)
// RTClib : https://www.arduinolibraries.info/libraries/rt-clib
#include <M5Stack.h>
#include "M5StackUpdater.h"
#include <WiFi.h>
#include <SPI.h> 
#include "RTClib.h"
RTC_DS3231 rtc;
#include "vfd_18x34.c"   // font 18px34
#include "vfd_35x67.c"   // font 35x67
#include "vfd_70x134.c"  // font 70px134
#include "apple_35x41.c" // icon 35px41 
const uint8_t rtc_sda = 5, rtc_sck = 13;
const char *ssid = "your ssid";
const char *pass = "your password";
uint32_t targetTime = 0; // for next 1 second timeout
const uint8_t*n[] = { // vfd font 18x34
  vfd_18x34_0,vfd_18x34_1,vfd_18x34_2,vfd_18x34_3,vfd_18x34_4,
  vfd_18x34_5,vfd_18x34_6,vfd_18x34_7,vfd_18x34_8,vfd_18x34_9 };
const uint8_t*m[] = { // vfd font 35x67
  vfd_35x67_0,vfd_35x67_1,vfd_35x67_2,vfd_35x67_3,vfd_35x67_4,
  vfd_35x67_5,vfd_35x67_6,vfd_35x67_7,vfd_35x67_8,vfd_35x67_9,
  vfd_35x67_q,vfd_35x67_n };
  const uint8_t*b[] = { // vfd font 70x134
  vfd_70x134_0,vfd_70x134_1,vfd_70x134_2,vfd_70x134_3,vfd_70x134_4,
  vfd_70x134_5,vfd_70x134_6,vfd_70x134_7,vfd_70x134_8,vfd_70x134_9,
  vfd_70x134_q,vfd_70x134_n };
const char *monthName[12] = {
  "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
uint16_t yy;
uint8_t mn, dd, hh, mm, ss;
uint8_t md = 2; // mode 1(yyyy_mmdd_hhmmss),2(mmdd_hh_mmss),3(mmdd_ss_hhmm)
 
void setup() { 
  M5.begin();
  Wire.begin(rtc_sda,rtc_sck);delay(10); //GLOVE A : SDA,SCL
  if(digitalRead(39)==0){updateFromFS(SD);ESP.restart();}
  rtc.begin(); 
  M5.Lcd.setBrightness(255);
  M5.Lcd.setRotation(1);
  M5.Lcd.fillRect(0, 0, 319, 239, ORANGE);
  M5.Lcd.fillRect(1, 1, 317, 236, BLACK);
  M5.Lcd.setTextSize(2);
  esp_timer_init();
  wifi_setup(); // wifi conection, NTP read, Save NTP to RTC
  rtc_setup();  // Read the value of RTC
}

void loop() {
  M5.update();
  if (targetTime < esp_timer_get_time()/1000 ){
    targetTime = esp_timer_get_time()/1000 + 1000;
    ss++; if (ss == 60) { ss = 0; mm++;
           if (mm == 60) { mm = 0; hh++;
            if (hh == 24) { hh = 0; dd++; //
   }}}}
  if(M5.BtnC.wasPressed()){            // mode change
   if (md == 3){md = 1;M5.Lcd.fillRect(1,1,317,236,BLACK);return;}
   if (md == 2){md = 3;M5.Lcd.fillRect(1,1,317,236,BLACK);return;}
   if (md == 1){md = 2;M5.Lcd.fillRect(1,1,317,236,BLACK);return;}
  }
  if ( md == 3 ){ hhmm();}             // yyyy,mm,dd,ss,hh,mm
  if ( md == 2 ){ yyyy_mmdd_hhmmss();} // yyyy,mm,dd,hh,mm,ss
  if ( md == 1 ){ mmss();}             // mm,ss
  periodic_ntp();                      // Set the time by periodic NTP
  delay(500);
}

void wifi_setup(){
  WiFi.mode(WIFI_STA);
  WiFi.disconnect();
  M5.Lcd.setCursor(20,40);M5.Lcd.setTextColor(WHITE);
  M5.Lcd.print("Connecting to wifi");
  WiFi.begin(ssid,pass);
  int wifi_check = 10; // WiFi count
  M5.Lcd.setCursor(20,80);M5.Lcd.setTextColor(YELLOW);
  M5.Lcd.print("wifi check in progress");
  while (WiFi.status() != WL_CONNECTED){ // WiFI Status
    delay(500); wifi_check--; if (wifi_check < 0){break;}
  }
  if (wifi_check > 0){  // when there is wifi
    M5.Lcd.setCursor(20,120);M5.Lcd.setTextColor(GREEN);
    M5.Lcd.print("wifi connection complete");delay(2000);
    struct tm t;
    configTime(9*3600L,0,"ntp.nict.jp",
      "time.google.com","ntp.jst.mfeed.ad.jp");
    getLocalTime(&t);
    yy = t.tm_year + 1900; mn = t.tm_mon + 1; dd = t.tm_mday;
    hh = t.tm_hour; mm = t.tm_min; ss = t.tm_sec;
    //Serial.printf("%d %d %d %d %d %d\n",yy,mn,dd,hh,mm,ss);
    rtc.adjust(DateTime(yy,mn,dd,hh,mm,ss));//save ntp to rtc
    M5.Lcd.setCursor(20,160);M5.Lcd.setTextColor(GREEN);
    M5.Lcd.print("SET UP NTP");delay(2000); 
  }
  if (wifi_check < 0){   // When there is no wifi
    M5.Lcd.setCursor(20,120);M5.Lcd.setTextColor(ORANGE);
    M5.Lcd.print("without wifi connection");delay(2000);
  }
}

void rtc_setup(){
  DateTime now = rtc.now(); // time geting from RTC
  if (now.year() == 2165){  // rtc check
    M5.Lcd.setCursor(20,200);M5.Lcd.setTextColor(RED);
    M5.Lcd.print("RTC FAIL");delay(2000);
    M5.Lcd.fillRect(1, 1, 317, 236, BLACK);
    }else{
    yy = now.year(); mn = now.month(); dd = now.day();
    hh = now.hour(); mm = now.minute(); ss = now.second();
    //Serial.printf("%d %d %d %d %d %d\n",yy,mn,dd,hh,mm,ss);
    M5.Lcd.setCursor(20,200);M5.Lcd.setTextColor(BLUE);
    M5.Lcd.print("SET UP RTC");delay(2000);
    M5.Lcd.fillRect(1, 1, 317, 236, BLACK);
  }
}

void yyyy_mmdd_hhmmss(){
  int y1 = (yy / 1000) % 10; int y2 = (yy / 100) % 10;
  int y3 = (yy /   10) % 10; int y4 = yy % 10;
  int ma = (mn /   10) % 10; int mb = mn % 10;
  int d1 = (dd /   10) % 10; int d2 = dd % 10;
  int h1 = (hh /   10) % 10; int h2 = hh % 10;
  int m1 = (mm /   10) % 10; int m2 = mm % 10;
  int s1 = (ss /   10) % 10; int s2 = ss % 10;

  //int p0 = 8; int x0 = 40; int t0 = 22; // icon
  //M5.Lcd.pushImage( p0 + 0*x0, t0, 35,41, (uint16_t *)apple_35x41);

  int p1 = 80; int px1 = 40; int py1 = 5;
  M5.Lcd.pushImage( p1 + 0*px1, py1, 35,67, (uint16_t *)m[y1]); 
  M5.Lcd.pushImage( p1 + 1*px1, py1, 35,67, (uint16_t *)m[y2]);
  M5.Lcd.pushImage( p1 + 2*px1, py1, 35,67, (uint16_t *)m[y3]);
  M5.Lcd.pushImage( p1 + 3*px1, py1, 35,67, (uint16_t *)m[y4]);
  
  int p2 = 80; int px2 = 40; int py2 = 76;
  M5.Lcd.pushImage( p2 + 0*px2, py2, 35,67, (uint16_t *)m[ma]);
  M5.Lcd.pushImage( p2 + 1*px2, py2, 35,67, (uint16_t *)m[mb]);
  //M5.Lcd.drawPixel(118,13, ORANGE); M5.Lcd.drawPixel(119,23,ORANGE);
  M5.Lcd.pushImage( p2 + 2*px2, py2, 35,67, (uint16_t *)m[d1]);
  M5.Lcd.pushImage( p2 + 3*px2, py2, 35,67, (uint16_t *)m[d2]);

  int p3 = 2; int px3 = 40; int py3 = 150;
  M5.Lcd.pushImage( p3 + 0*px3, py3, 35,67, (uint16_t *)m[h1]);
  M5.Lcd.pushImage( p3 + 1*px3, py3, 35,67, (uint16_t *)m[h2]);
  M5.Lcd.pushImage( p3 + 2*px3, py3, 35,67, (uint16_t *)m[10]);
  M5.Lcd.pushImage( p3 + 3*px3, py3, 35,67, (uint16_t *)m[m1]);
  M5.Lcd.pushImage( p3 + 4*px3, py3, 35,67, (uint16_t *)m[m2]);
  M5.Lcd.pushImage( p3 + 5*px3, py3, 35,67, (uint16_t *)m[10]);
  M5.Lcd.pushImage( p3 + 6*px3, py3, 35,67, (uint16_t *)m[s1]);
  M5.Lcd.pushImage( p3 + 7*px3, py3, 35,67, (uint16_t *)m[s2]);
  
  if ( s1 == 0 && s2 == 0 ){ fade1();}
}

void mmss(){
  int ma = (mn / 10) % 10; int mb = mn % 10;
  int d1 = (dd / 10) % 10; int d2 = dd % 10;
  int h1 = (hh / 10) % 10; int h2 = hh % 10;
  int m1 = (mm / 10) % 10; int m2 = mm % 10;
  int s1 = (ss / 10) % 10; int s2 = ss % 10;

  int p0 = 8; int x0 = 40; int t0 = 22; // icon
  M5.Lcd.pushImage( p0 + 0*x0, t0, 35,41, (uint16_t *)apple_35x41);

  int p2 = 65; int px2 = 40; int py2 = 10;
  M5.Lcd.pushImage( p2 + 0*px2, py2, 35,67, (uint16_t *)m[ma]);
  M5.Lcd.pushImage( p2 + 1*px2, py2, 35,67, (uint16_t *)m[mb]);
  //M5.Lcd.drawPixel(118,13, ORANGE); M5.Lcd.drawPixel(119,23,ORANGE);
  M5.Lcd.pushImage( p2 + 2*px2, py2, 35,67, (uint16_t *)m[d1]);
  M5.Lcd.pushImage( p2 + 3*px2, py2, 35,67, (uint16_t *)m[d2]);
  
  int p3 = 240; int px3 = 40; int py3 = 10;
  M5.Lcd.pushImage( p3 + 0*px3, py3, 35,67, (uint16_t *)m[h1]);
  M5.Lcd.pushImage( p3 + 1*px3, py3, 35,67, (uint16_t *)m[h2]);
  
  int p4 = 2; int px4 = 80; int py4 = 100;
  M5.Lcd.pushImage( p4 + 0*px4   , py4, 70,134, (uint16_t *)b[m1]);
  M5.Lcd.pushImage( p4 + 1*px4 -4, py4, 70,134, (uint16_t *)b[m2]);
  //M5.Lcd.drawPixel(155,150, ORANGE); M5.Lcd.drawPixel(155,190,ORANGE);
  M5.Lcd.fillCircle(156,151,3,ORANGE);M5.Lcd.fillCircle(156,191,3,ORANGE);
  M5.Lcd.fillCircle(156,151,1,YELLOW);M5.Lcd.fillCircle(156,191,1,YELLOW);
  M5.Lcd.pushImage( p4 + 2*px4 +4, py4, 70,134, (uint16_t *)b[s1]);
  M5.Lcd.pushImage( p4 + 3*px4   , py4, 70,134, (uint16_t *)b[s2]);

  if ( m1 == 0 && m2 == 0 ){ fade2();}
}

void hhmm(){
  int ma = (mn / 10) % 10; int mb = mn % 10;
  int d1 = (dd / 10) % 10; int d2 = dd % 10;
  int h1 = (hh / 10) % 10; int h2 = hh % 10;
  int m1 = (mm / 10) % 10; int m2 = mm % 10;
  int s1 = (ss / 10) % 10; int s2 = ss % 10;

  //int p0 = 8; int x0 = 40; int t0 = 22; // icon
  //M5.Lcd.pushImage( p0 + 0*x0, t0, 35,41, (uint16_t *)apple_35x41);

  int p2 = 65; int px2 = 40; int py2 = 10;
  M5.Lcd.pushImage( p2 + 0*px2, py2, 35,67, (uint16_t *)m[ma]);
  M5.Lcd.pushImage( p2 + 1*px2, py2, 35,67, (uint16_t *)m[mb]);
  //M5.Lcd.drawPixel(118,13, ORANGE); M5.Lcd.drawPixel(119,23,ORANGE);
  M5.Lcd.pushImage( p2 + 2*px2, py2, 35,67, (uint16_t *)m[d1]);
  M5.Lcd.pushImage( p2 + 3*px2, py2, 35,67, (uint16_t *)m[d2]);
  
  int p3 = 240; int px3 = 40; int py3 = 10;
  M5.Lcd.pushImage( p3 + 0*px3, py3, 35,67, (uint16_t *)m[s1]);
  M5.Lcd.pushImage( p3 + 1*px3, py3, 35,67, (uint16_t *)m[s2]);
  
  int p4 = 2; int px4 = 80; int py4 = 100;
  M5.Lcd.pushImage( p4 + 0*px4   , py4, 70,134, (uint16_t *)b[h1]);
  M5.Lcd.pushImage( p4 + 1*px4 -4, py4, 70,134, (uint16_t *)b[h2]);
  //M5.Lcd.drawPixel( 155,150, ORANGE); M5.Lcd.drawPixel(155,190,ORANGE);
  M5.Lcd.fillCircle(156,151,3,ORANGE);M5.Lcd.fillCircle(156,191,3,ORANGE);
  M5.Lcd.fillCircle(156,151,1,YELLOW);M5.Lcd.fillCircle(156,191,1,YELLOW);
  M5.Lcd.pushImage( p4 + 2*px4 +4, py4, 70,134, (uint16_t *)b[m1]);
  M5.Lcd.pushImage( p4 + 3*px4   , py4, 70,134, (uint16_t *)b[m2]);

  if ( h1 == 0 && h2 == 0 ){ fade2();}
}

void fade1(){
  int p3 = 2; int px3 = 40; int py3 = 150;
  for ( int i = 0; i < 2; i++ ){
  M5.Lcd.pushImage( p3 + 2*px3, py3, 35,67, (uint16_t *)m[11]);
  M5.Lcd.pushImage( p3 + 5*px3, py3, 35,67, (uint16_t *)m[11]);
  delay(25);
  M5.Lcd.pushImage( p3 + 2*px3, py3, 35,67, (uint16_t *)m[10]);
  M5.Lcd.pushImage( p3 + 5*px3, py3, 35,67, (uint16_t *)m[10]);
  delay(25);
  }
}

void fade2(){
  int p3 = 2; int px3 = 40; int py3 = 150;
  for ( int i = 0; i < 2; i++ ){
  M5.Lcd.fillCircle(156,151,3,BLACK);M5.Lcd.fillCircle(156,191,3,BLACK);
  delay(25);
  M5.Lcd.fillCircle(156,151,3,ORANGE);M5.Lcd.fillCircle(156,191,3,ORANGE);
  delay(25);
  }
}

void periodic_ntp(){ // Adjust to ntp at hh mm ss
  if ( (hh == 1) & (mm == 0) & (ss == 0)){ // AM 1:00:00
    wifi_setup();
    rtc_setup();
  }
}

.
apple_35x41.c
.

/*******************************************************************************
* generated by lcd-image-converter rev.c6da9ce from 2018-02-11 00:03:45 +0500
* image
* filename: unsaved
* name: apple_35x41
* macsbug
* preset name: Color R5G6B5
* data block size: 8 bit(s), uint8_t
* RLE compression enabled: no
* conversion type: Color, not_used not_used
* split to rows: yes
* bits per pixel: 16
*
* preprocess:
*  main scan direction: top_to_bottom
*  line scan direction: forward
*  inverse: no
*******************************************************************************/

/*
 typedef struct {
     const uint8_t *data;
     uint16_t width;
     uint16_t height;
     uint8_t dataSize;
     } tImage;
*/
#include <stdint.h>

static const uint8_t apple_35x41[2870] = {
    // ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙░▒∙∙∙∙∙∙∙∙∙∙
    // ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▒▓▓▓∙∙∙∙∙∙∙∙∙∙
    // ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▓▓▒▒▓∙∙∙∙∙∙∙∙∙∙
    // ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▓▒▒▒▒▒∙∙∙∙∙∙∙∙∙∙
    // ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▓▒▒▒▒▓░∙∙∙∙∙∙∙∙∙∙
    // ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙░▓▒▒▒▒▓∙∙∙∙∙∙∙∙∙∙∙
    // ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▒▒▒▒▒▓░∙∙∙∙∙∙∙∙∙∙∙
    // ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▓▒▒▒▓▒∙∙∙∙∙∙∙∙∙∙∙∙
    // ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▓▒▓▓░∙∙∙∙∙∙∙∙∙∙∙∙∙
    // ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▓▓░∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
    // ∙∙∙∙∙∙░▒▓▓▓▓▓▒░∙∙∙∙∙∙∙▒▓▓▓▓▓▓▒∙∙∙∙∙
    // ∙∙∙∙∙▓▓▒▒▒▒▒▒▒▓▓▒░░░▒▓▓▒▒▒▒▒▒▓▓░∙∙∙
    // ∙∙∙∙▓▓▒▒▒▒▒▒▒▒▒▒▒▓▓▓▒▒▒▒▒▒▒▒▒▒▒▓░∙∙
    // ∙∙∙▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓░∙
    // ∙∙▒▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▒∙∙
    // ∙∙█▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓█▒∙∙∙
    // ∙▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒∙∙∙∙
    // ∙█▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓█∙∙∙∙∙
    // ░█▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒∙∙∙∙∙
    // ▒█▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓█░∙∙∙∙∙
    // ▒▓▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▓∙∙∙∙∙∙
    // ▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓∙∙∙∙∙∙
    // ▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓∙∙∙∙∙∙
    // ▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░∙∙∙∙∙
    // ▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓∙∙∙∙∙
    // ░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒∙∙∙∙∙
    // ∙▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒∙∙∙∙
    // ∙▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░∙∙∙
    // ∙▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░∙∙
    // ∙∙▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒∙
    // ∙∙▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
    // ∙∙░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒∙
    // ∙∙∙▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒∙
    // ∙∙∙░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒∙∙
    // ∙∙∙∙▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒∙∙
    // ∙∙∙∙░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒∙∙∙
    // ∙∙∙∙∙▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓░∙∙∙
    // ∙∙∙∙∙∙▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░∙∙∙∙
    // ∙∙∙∙∙∙∙▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒∙∙∙∙∙
    // ∙∙∙∙∙∙∙∙▒▒▒▒▒▒▒░∙∙∙∙∙▒▒▒▒▒▒▒░∙∙∙∙∙∙
    // ∙∙∙∙∙∙∙∙∙∙░▒░∙∙∙∙∙∙∙∙∙∙░░▒░∙∙∙∙∙∙∙∙
    0x21, 0x24, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x21, 0x64, 0x43, 0x87, 0x6d, 0xc9, 0x19, 0x03, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x21, 0x24, 
    0x08, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0xc9, 0x7f, 0xaa, 0x6e, 0xe9, 0x87, 0xea, 0x10, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x61, 
    0x10, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x62, 0x87, 0xeb, 0x6e, 0xc9, 0x65, 0xe8, 0x65, 0xe8, 0x77, 0x0a, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x82, 
    0x10, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xe1, 0x87, 0xeb, 0x66, 0x08, 0x65, 0xe8, 0x65, 0xe8, 0x66, 0x08, 0x6e, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x82, 
    0x10, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x0a, 0x66, 0x48, 0x65, 0xe8, 0x65, 0xe8, 0x65, 0xe8, 0x77, 0x49, 0x44, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x82, 
    0x10, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x45, 0x77, 0x6a, 0x65, 0xe8, 0x65, 0xe8, 0x65, 0xe8, 0x65, 0xe8, 0x7f, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x82, 
    0x10, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x49, 0x66, 0x28, 0x65, 0xe8, 0x65, 0xe8, 0x65, 0xe8, 0x87, 0xea, 0x32, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x82, 
    0x10, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x77, 0x2a, 0x65, 0xe8, 0x65, 0xe8, 0x65, 0xe8, 0x87, 0xea, 0x4c, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x82, 
    0x10, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xe1, 0x7f, 0x6a, 0x66, 0x08, 0x6f, 0x09, 0x87, 0xcb, 0x33, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x82, 
    0x10, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xc1, 0x08, 0xe1, 0x08, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xe1, 0x8f, 0xec, 0x76, 0xea, 0x44, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xc1, 0x21, 0xe3, 0x19, 0xa2, 0x08, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x82, 
    0x10, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x04, 0x66, 0x29, 0x77, 0x0a, 0x7f, 0x4a, 0x7f, 0x4a, 0x7f, 0x2a, 0x76, 0xc9, 0x66, 0x29, 0x44, 0x26, 0x11, 0x42, 0x00, 0x00, 0x08, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0xc2, 0x5d, 0x68, 0x76, 0xea, 0x7f, 0x4a, 0x77, 0x4a, 0x77, 0x4a, 0x7f, 0x4a, 0x6e, 0xaa, 0x4c, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x82, 
    0x10, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x8a, 0x7f, 0x8a, 0x66, 0x48, 0x65, 0xe8, 0x65, 0xe8, 0x65, 0xe8, 0x65, 0xe8, 0x65, 0xe8, 0x66, 0x28, 0x6f, 0x09, 0x7f, 0x6a, 0x5d, 0xc8, 0x3b, 0x45, 0x2a, 0x83, 0x44, 0x26, 0x66, 0x49, 0x7f, 0x6a, 0x66, 0xa9, 0x65, 0xe8, 0x65, 0xe8, 0x65, 0xe8, 0x65, 0xe8, 0x65, 0xe8, 0x66, 0x08, 0x6f, 0x29, 0x7f, 0x8b, 0x2a, 0xa4, 0x00, 0x00, 0x00, 0x00, 0x10, 0x82, 
    0x10, 0x82, 0x00, 0x00, 0x00, 0x00, 0x08, 0x20, 0x87, 0xab, 0x66, 0xa9, 0x65, 0xe8, 0x65, 0xe8, 0x65, 0xe8, 0x65, 0xe8, 0x65, 0xe8, 0x65, 0xe8, 0x65, 0xe8, 0x65, 0xe8, 0x65, 0xe8, 0x65, 0xe8, 0x66, 0x29, 0x6e, 0xe9, 0x6f, 0x29, 0x6e, 0xc9, 0x66, 0x08, 0x65, 0xe8, 0x65, 0xe8, 0x65, 0xe8, 0x65, 0xe8, 0x65, 0xe8, 0x65, 0xe8, 0x65, 0xe8, 0x65, 0xe8, 0x65, 0xe8, 0x66, 0x08, 0x87, 0xea, 0x3b, 0x85, 0x00, 0x00, 0x10, 0x82, 
    0x10, 0x82, 0x00, 0x00, 0x00, 0x00, 0x67, 0x2b, 0x5e, 0x89, 0x55, 0xe8, 0x55, 0xe8, 0x55, 0xe8, 0x55, 0xe8, 0x55, 0xe8, 0x55, 0xe8, 0x55, 0xe8, 0x55, 0xe8, 0x55, 0xe8, 0x55, 0xe8, 0x55, 0xe8, 0x55, 0xe8, 0x55, 0xe8, 0x55, 0xe8, 0x55, 0xe8, 0x55, 0xe8, 0x55, 0xe8, 0x55, 0xe8, 0x55, 0xe8, 0x55, 0xe8, 0x55, 0xe8, 0x55, 0xe8, 0x55, 0xe8, 0x55, 0xe8, 0x55, 0xe8, 0x55, 0xe8, 0x55, 0xe8, 0x97, 0xec, 0x3b, 0x45, 0x10, 0x82, 
    0x10, 0x82, 0x00, 0x00, 0x5c, 0x86, 0x87, 0x48, 0x6d, 0xc8, 0x6d, 0xc8, 0x6d, 0xc8, 0x6d, 0xc8, 0x6d, 0xc8, 0x6d, 0xc8, 0x6d, 0xc8, 0x6d, 0xc8, 0x6d, 0xc8, 0x6d, 0xc8, 0x6d, 0xc8, 0x6d, 0xc8, 0x6d, 0xc8, 0x6d, 0xc8, 0x6d, 0xc8, 0x6d, 0xc8, 0x6d, 0xc8, 0x6d, 0xc8, 0x6d, 0xc8, 0x6d, 0xc8, 0x6d, 0xc8, 0x6d, 0xc8, 0x6d, 0xc8, 0x6d, 0xc8, 0x6d, 0xc8, 0x6d, 0xc8, 0x6d, 0xc8, 0xa7, 0x89, 0x4c, 0x66, 0x00, 0x00, 0x10, 0x82, 
    0x10, 0x82, 0x00, 0x21, 0xff, 0x85, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xff, 0x85, 0xab, 0x02, 0x00, 0x00, 0x00, 0x00, 0x10, 0x82, 
    0x10, 0x82, 0xc4, 0x63, 0xfe, 0xc5, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfe, 0xc5, 0xc4, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x82, 
    0x10, 0x82, 0xff, 0x05, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xff, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x82, 
    0x49, 0xe4, 0xff, 0x65, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xc4, 0xfe, 0xa5, 0xc4, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x82, 
    0x93, 0xa5, 0xfe, 0xe5, 0xfd, 0xc5, 0xfd, 0xc5, 0xfd, 0xc5, 0xfd, 0xc5, 0xfd, 0xc5, 0xfd, 0xc5, 0xfd, 0xc5, 0xfd, 0xc5, 0xfd, 0xc5, 0xfd, 0xc5, 0xfd, 0xc5, 0xfd, 0xc5, 0xfd, 0xc5, 0xfd, 0xc5, 0xfd, 0xc5, 0xfd, 0xc5, 0xfd, 0xc5, 0xfd, 0xc5, 0xfd, 0xc5, 0xfd, 0xc5, 0xfd, 0xc5, 0xfd, 0xc5, 0xfd, 0xc5, 0xfd, 0xc5, 0xfd, 0xc5, 0xfd, 0xc5, 0xff, 0x25, 0x51, 0xe2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x82, 
    0xb3, 0x45, 0xfc, 0x64, 0xf3, 0xe4, 0xf3, 0xe4, 0xf3, 0xe4, 0xf3, 0xe4, 0xf3, 0xe4, 0xf3, 0xe4, 0xf3, 0xe4, 0xf3, 0xe4, 0xf3, 0xe4, 0xf3, 0xe4, 0xf3, 0xe4, 0xf3, 0xe4, 0xf3, 0xe4, 0xf3, 0xe4, 0xf3, 0xe4, 0xf3, 0xe4, 0xf3, 0xe4, 0xf3, 0xe4, 0xf3, 0xe4, 0xf3, 0xe4, 0xf3, 0xe4, 0xf3, 0xe4, 0xf3, 0xe4, 0xf3, 0xe4, 0xf3, 0xe4, 0xf3, 0xe4, 0xfc, 0xc4, 0x28, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x82, 
    0xdb, 0xe5, 0xfc, 0x24, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xfc, 0x04, 0xfc, 0xe4, 0x20, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x82, 
    0xdb, 0xe5, 0xfc, 0x24, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xf4, 0x04, 0xfd, 0x04, 0x41, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x82, 
    0xcb, 0xc6, 0xfc, 0x44, 0xf4, 0x24, 0xf4, 0x24, 0xf4, 0x24, 0xf4, 0x24, 0xf4, 0x24, 0xf4, 0x24, 0xf4, 0x24, 0xf4, 0x24, 0xf4, 0x24, 0xf4, 0x24, 0xf4, 0x24, 0xf4, 0x24, 0xf4, 0x24, 0xf4, 0x24, 0xf4, 0x24, 0xf4, 0x24, 0xf4, 0x24, 0xf4, 0x24, 0xf4, 0x24, 0xf4, 0x24, 0xf4, 0x24, 0xf4, 0x24, 0xf4, 0x24, 0xf4, 0x24, 0xf4, 0x24, 0xf4, 0x24, 0xfc, 0xa4, 0x9a, 0xa2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x82, 
    0x92, 0xe5, 0xfd, 0x24, 0xf4, 0x64, 0xf4, 0x84, 0xf4, 0x84, 0xf4, 0x84, 0xf4, 0x84, 0xf4, 0x84, 0xf4, 0x84, 0xf4, 0x84, 0xf4, 0x84, 0xf4, 0x84, 0xf4, 0x84, 0xf4, 0x84, 0xf4, 0x84, 0xf4, 0x84, 0xf4, 0x84, 0xf4, 0x84, 0xf4, 0x84, 0xf4, 0x84, 0xf4, 0x84, 0xf4, 0x84, 0xf4, 0x84, 0xf4, 0x84, 0xf4, 0x84, 0xf4, 0x84, 0xf4, 0x84, 0xf4, 0x64, 0xfc, 0x84, 0xfc, 0xe4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x82, 
    0x61, 0x25, 0xfa, 0x28, 0xe1, 0xa7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xfa, 0x68, 0x28, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x82, 
    0x30, 0xe4, 0xf9, 0xe8, 0xd9, 0xc7, 0xd9, 0xc7, 0xd9, 0xc7, 0xd9, 0xc7, 0xd9, 0xc7, 0xd9, 0xc7, 0xd9, 0xc7, 0xd9, 0xc7, 0xd9, 0xc7, 0xd9, 0xc7, 0xd9, 0xc7, 0xd9, 0xc7, 0xd9, 0xc7, 0xd9, 0xc7, 0xd9, 0xc7, 0xd9, 0xc7, 0xd9, 0xc7, 0xd9, 0xc7, 0xd9, 0xc7, 0xd9, 0xc7, 0xd9, 0xc7, 0xd9, 0xc7, 0xd9, 0xc7, 0xd9, 0xc7, 0xd9, 0xc7, 0xd9, 0xc7, 0xd9, 0xc7, 0xe9, 0xc7, 0xf9, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x82, 
    0x10, 0xa2, 0xfa, 0x08, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xfa, 0x08, 0x99, 0x45, 0x00, 0x00, 0x00, 0x00, 0x10, 0x82, 
    0x10, 0x82, 0xe1, 0xc7, 0xf1, 0xe7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xe1, 0xc7, 0xfa, 0x08, 0x89, 0x45, 0x00, 0x00, 0x10, 0x82, 
    0x10, 0x82, 0x58, 0xc3, 0xfa, 0x07, 0xe9, 0xc4, 0xe9, 0xc5, 0xe9, 0xc5, 0xe9, 0xc5, 0xe9, 0xc5, 0xe9, 0xc5, 0xe9, 0xc5, 0xe9, 0xc5, 0xe9, 0xc5, 0xe9, 0xc5, 0xe9, 0xc5, 0xe9, 0xc5, 0xe9, 0xc5, 0xe9, 0xc5, 0xe9, 0xc5, 0xe9, 0xc5, 0xe9, 0xc5, 0xe9, 0xc5, 0xe9, 0xc5, 0xe9, 0xc5, 0xe9, 0xc5, 0xe9, 0xc5, 0xe9, 0xc5, 0xe9, 0xc5, 0xe9, 0xc5, 0xe9, 0xc5, 0xe9, 0xc5, 0xe9, 0xc5, 0xe9, 0xc5, 0xfa, 0x07, 0xd9, 0x84, 0x30, 0xe2, 
    0x10, 0x82, 0x00, 0x00, 0xd2, 0x34, 0xa9, 0xf0, 0xa1, 0xf0, 0xa9, 0xf0, 0xa9, 0xf0, 0xa9, 0xf0, 0xa9, 0xf0, 0xa9, 0xf0, 0xa9, 0xf0, 0xa9, 0xf0, 0xa9, 0xf0, 0xa9, 0xf0, 0xa9, 0xf0, 0xa9, 0xf0, 0xa9, 0xf0, 0xa9, 0xf0, 0xa9, 0xf0, 0xa9, 0xf0, 0xa9, 0xf0, 0xa9, 0xf0, 0xa9, 0xf0, 0xa9, 0xf0, 0xa9, 0xf0, 0xa9, 0xf0, 0xa9, 0xf0, 0xa9, 0xf0, 0xa9, 0xf0, 0xa9, 0xf0, 0xa9, 0xf0, 0xa9, 0xf0, 0xa1, 0xef, 0xe2, 0x34, 0xa1, 0xed, 
    0x10, 0x82, 0x00, 0x00, 0x71, 0xb1, 0xa2, 0x16, 0x91, 0xf3, 0x91, 0xf3, 0x91, 0xf3, 0x91, 0xf3, 0x91, 0xf3, 0x91, 0xf3, 0x91, 0xf3, 0x91, 0xf3, 0x91, 0xf3, 0x91, 0xf3, 0x91, 0xf3, 0x91, 0xf3, 0x91, 0xf3, 0x91, 0xf3, 0x91, 0xf3, 0x91, 0xf3, 0x91, 0xf3, 0x91, 0xf3, 0x91, 0xf3, 0x91, 0xf3, 0x91, 0xf3, 0x91, 0xf3, 0x91, 0xf3, 0x91, 0xf3, 0x91, 0xf3, 0x91, 0xf3, 0x91, 0xf3, 0x91, 0xf3, 0x89, 0xf3, 0xb2, 0x59, 0x18, 0xe5, 
    0x10, 0x82, 0x00, 0x00, 0x08, 0x20, 0xc2, 0x58, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0xa2, 0x13, 0xa2, 0x13, 0x10, 0x82, 
    0x10, 0x82, 0x00, 0x00, 0x00, 0x00, 0x81, 0xaf, 0xaa, 0x15, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0x91, 0xf2, 0xc2, 0x58, 0x20, 0x64, 0x10, 0x82, 
    0x10, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd2, 0x58, 0xb9, 0x71, 0xb9, 0x51, 0xb9, 0x71, 0xb9, 0x71, 0xb9, 0x71, 0xb9, 0x71, 0xb9, 0x71, 0xb9, 0x71, 0xb9, 0x71, 0xb9, 0x71, 0xb9, 0x71, 0xb9, 0x71, 0xb9, 0x71, 0xb9, 0x71, 0xb9, 0x71, 0xb9, 0x71, 0xb9, 0x71, 0xb9, 0x71, 0xb9, 0x71, 0xb9, 0x71, 0xb9, 0x71, 0xb9, 0x71, 0xb9, 0x71, 0xb9, 0x71, 0xb9, 0x51, 0xb1, 0x51, 0xc9, 0xb3, 0x9a, 0x12, 0x00, 0x00, 0x10, 0x82, 
    0x10, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x0d, 0x4c, 0xff, 0x3b, 0x97, 0x3b, 0xb8, 0x3b, 0xb8, 0x3b, 0xb8, 0x3b, 0xb8, 0x3b, 0xb8, 0x3b, 0xb8, 0x3b, 0xb8, 0x3b, 0xb8, 0x3b, 0xb8, 0x3b, 0xb8, 0x3b, 0xb8, 0x3b, 0xb8, 0x3b, 0xb8, 0x3b, 0xb8, 0x3b, 0xb8, 0x3b, 0xb8, 0x3b, 0xb8, 0x3b, 0xb8, 0x3b, 0xb8, 0x3b, 0xb8, 0x3b, 0xb8, 0x3b, 0xb8, 0x3b, 0xb8, 0x3b, 0xb8, 0x54, 0xff, 0x00, 0x00, 0x00, 0x00, 0x10, 0x82, 
    0x10, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xff, 0x05, 0xff, 0x05, 0x5c, 0x05, 0x5c, 0x05, 0x5c, 0x05, 0x5c, 0x05, 0x5c, 0x05, 0x5c, 0x05, 0x5c, 0x05, 0x5c, 0x05, 0x5c, 0x05, 0x5c, 0x05, 0x5c, 0x05, 0x5c, 0x05, 0x5c, 0x05, 0x5c, 0x05, 0x5c, 0x05, 0x5c, 0x05, 0x5c, 0x05, 0x5c, 0x05, 0x5c, 0x05, 0x5c, 0x05, 0x5c, 0x05, 0x5c, 0x05, 0x3c, 0x07, 0x3f, 0x03, 0x50, 0x00, 0x00, 0x00, 0x00, 0x10, 0x82, 
    0x10, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x3f, 0x05, 0x7e, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x05, 0x1c, 0x05, 0x1c, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x06, 0x5f, 0x04, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x82, 
    0x10, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x5f, 0x05, 0xbf, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x05, 0x1c, 0x05, 0xff, 0x06, 0x1f, 0x05, 0xbf, 0x05, 0xbf, 0x05, 0xff, 0x06, 0x1f, 0x05, 0x7f, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x05, 0x1b, 0x06, 0x9f, 0x04, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x82, 
    0x08, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x1c, 0x06, 0x9f, 0x05, 0x9f, 0x05, 0x3d, 0x05, 0x7f, 0x06, 0x5f, 0x05, 0xbf, 0x02, 0xcf, 0x00, 0xa3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xa8, 0x04, 0x99, 0x06, 0x5f, 0x06, 0x1f, 0x05, 0x5e, 0x05, 0x3d, 0x06, 0x1f, 0x06, 0x9f, 0x02, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x61, 
    0x21, 0x24, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x11, 0xa8, 0x1b, 0xd4, 0x14, 0x98, 0x13, 0xd4, 0x11, 0xc9, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0xa3, 0x12, 0xad, 0x1c, 0x15, 0x1c, 0x77, 0x1a, 0xef, 0x10, 0xc3, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x21, 0x24
};

.
M5Stack nixie tube clock , DS3231 , RTC , VFD , Nixie tube , ニキシー管 , Hex File

Written by macsbug

6月 16, 2019 at 11:00 am

カテゴリー: M5STACK

M5StickC Nixie tube Clock

with 2 comments

M5StickC で ニキシー管時計を製作しました。    2019.06.06, rev 2019.06.15

ニキシー管は 高電圧が必要である事や 高価である為 製作する機会がありません。
見たい気持ちは大きく ソフトで製作しました。

費用:M5StickC以外の材料費は0円です。
外観:M5StickC の IPS Display は 80×160 で表示サイズは小さいですが
_  明るく綺麗で見やすいです。
機能:M5のスイッチで YYYY,MM,DD, HH,MM,SS 表示と
_  MM,SS 表示に切り換える事ができます。

追記:2019.06.15
Carlos Orts に スケッチがパクられました。
McOrts/M5StickC_Nixie_tube_Clock: Jun 14, 2019
原作者(macsbug) や URLリンク が削除されています。
M5Stack Community / PROJECTS にMcOrts/M5StickC_Nixie_tube_Clockを記載しました。
その中で 3箇所に 原作者(macsbug) や URLリンク削除されている事を記載しました。


.
準備:以下の画像をドラック&ドロップし 画像を入手します。

ニキシー管 画像の製作:元画像 18×34 pixel

.

ニキシー管 画像の製作:元画像 35×67 pixel

.
参考:画像から Hex.c の作成方法は M5Stack CoinMarketCap:2019.05.30 を参照下さい。

⭕ HEX File 変換の準備:
_ png画像を「LCD image Converter 」アプリで hex ( .c ) に変換します。
_ 「LCD image Converter 」は Windowsアプリです。
_ 「lcd-image-converter 20180211-beta」を使用します。
_  メモ:投稿時 最新の20190317 は エラーで動作しません。
_ Mac では「Wine.app」を使用しWindows アプリケーションを動かすことができます。
_ Wine.app Downloads:例 Wine 2.0 を 選択し Download を押します。
_ 約5sec後に「Continue」が表示されますので「Continue」を選択します。
_ 約4sec後に 右上(のアイコン) を選択します。Wine_2.0.dmg 175.6MB が DLされます。
_ 解凍すると Wine.app ができます。
_

⭕ HEX File 変換方法:
1. Wine.app を起動し LCD image Converter を動作させます。
_ 事前に Wine.app や LCD image Converter の動かし方や 配置を把握しておきます。
_ 初めての場合は Winの配置等に慣れない為に時間を要するかと思います。

2. LCD image Converter:
_ File Menu から png 又は Jpg を読み込みます。読み込まれると画像が表示されます。
_ Option Menu を選択します。一番上の Preset: は「Color R5G6B5」を選択します。
_ Image を選択し Block size: は「8 bit」を選択します。「OK」を押します。
_ File Menu にある 「Convert… 」 で 例「vfd_35x67_8.c」が出力されます。
_  事前に読み込み先 ong や 出力先を把握しておきます。
_  全ての画像を読み込み 「Convert… all」で 全部の出力もできます。
_ 

3. .c の編集:そのままではエラーが出ますので ご使用のエディターで修正します。
_ 上位にある 「static const uint8_t image_data_vfd_35x67[4690] = {」は
_  解りやすくする為に名前を編集します。
_ ⭕ 「image_data_ 」を削除し「static const uint8_t vfd_35x67_8[4690] = {」にします。
_ ⭕最下位にある「const tImage vfd_35x67 = { image_data_vfd_35x67, 35, 67, 8 };」は
_   削除します。
_ 例「vfd_35x67_8」を保存します。
_ 同様に 0 から 9 まで実施し 保存します。
_ ⭕ 0 から 9 までのファイルは1つにした方が便利です。「0」の行末の後に
_   1 から 9 までの名前とデーター部を全て「0」の下に追加し 1つのファイルにします。

4. スケッチの作成。
_ 最下位にあるスケッチをコピーして 以下の画像の様に準備し
_ 画像フォント「vfd_18x34.c」 と 「vfd_35x67.c」 もフォルダーに入れます。
_ 
_ 以上で完了です。


.
M5StickC 開発環境:
Arduino IDE 1.8.9

_ 1. Upload Speed : “115200”
_ 1. シリアルモニター:115200 baud:OPEN 又は CLOSE で可能。

_ 2. Upload Speed : “500000”
_ 2. シリアルモニター:500000 baud:OPEN である事。

_ 書込み時に「A fatal error occurred: Timed out waiting for packet header」
_ が発生する場合があります。
_ 速度を速くしたく board.txt を書き換える方法もありますが、
_ 手順の簡単な 115200 baud が無難かと思います。


.
参考:
RTC: I2C BM8563:RTC機能を実現する。アドレス:0x15。
_  M5.Rtc.GetBm8563Time(); : ASCII形式で Rtc.Hour / Rtc.Minute / Rtc.Second
m5stack/m5-docs / system_m5stickc:M5stickC システム。
m5stack/m5-docs / axp192_m5stickc:AXP192 電源管理IC。
m5stack/m5-docs / lcd_m5stickc: IPS Display。
m5stack/m5-docs / sh200q_m5stickc:SH200Q 6 axis inertial sensor。
Virtual nixie tube (digitron) display – DHTML component library:nixie tube の画像データーがあります。
Long-ship:M5Stick-CのRTCをNTPサーバーからセットする:NTPが可能です。


.
感想:
画像の製作:画像処理により飽和したり綺麗でない場合がありますので
_ 手間ですが綺麗な表示になるように編集します。
_ 発光文字部分とニキシー管の背景とのバランスが重要です。
_ ニキシー管の背景が無いと雰囲気出ませんし強調すると全体が白く飽和します。
_ hex.c の編集が面倒でしたら「M5Stack CoinMarketCap」での
_ microSD 方式で 画像を使用する方法も良いかとも思います。
時刻:書込み時に PC の時刻を読み込み ESP内部の RTCに設定しています。
_  NTPは使用していません。
ニキシー管:ニキシー管をなんとか見る事ができて ほっとしています。
_     私もそうですが ニキシー管を好きな人が多い様です。
_     光る数値は前後に配置され数値の部分が重なる所があります。
_     細かく見るとフィラメントが重なる部分は綺麗に表示されないのですね。
github:使用していませんので大きなデータやリストを載せられず申し訳有りません。
M5StickC 価格:M5Stack Official Store = 1799円。$16.64。輸送期間 8日。
_ スイッチサイエンス = 2444円。
_ 10個購入する場合 M5Stack Official Store は 国内販売よりも 6450円お得になります。
M5Stack版:同様に M5Stack FIRE でも表示可能です。
_ M5Stack FIRE Nixie tube Clock:


.
スケッチ:M5StickC Nixie tube Clock: 2019.06.06 macsbug

// M5StickC Nixie tube Clock: 2019.06.06 macsbug
// https://macsbug.wordpress.com/2019/06/06/m5stickc-nixie-tube-clock/
#include <M5StickC.h>
#include "vfd_18x34.c"
#include "vfd_35x67.c"
RTC_TimeTypeDef RTC_TimeStruct;
RTC_DateTypeDef RTC_DateStruct;
int mode_ = 2; // 2: 2line, 1:1line
const uint8_t*n[] = { // vfd font 18x34
  vfd_18x34_0,vfd_18x34_1,vfd_18x34_2,vfd_18x34_3,vfd_18x34_4,
  vfd_18x34_5,vfd_18x34_6,vfd_18x34_7,vfd_18x34_8,vfd_18x34_9
  };
const uint8_t*m[] = { // vfd font 35x67
  vfd_35x67_0,vfd_35x67_1,vfd_35x67_2,vfd_35x67_3,vfd_35x67_4,
  vfd_35x67_5,vfd_35x67_6,vfd_35x67_7,vfd_35x67_8,vfd_35x67_9
  };
const char *monthName[12] = {
  "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};

void setup(void){ 
  M5.begin();
  pinMode(M5_BUTTON_HOME, INPUT);
  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.setRotation(1);
  M5.Axp.ScreenBreath(10);             // 7-15
  // rtc setup start ---------------------------------------------
  String pt = (__DATE__ " " __TIME__); // PC DATE TIME READ
  //000000000011111111112  Read data
  //012345678901234567890
  //Jun  6 2019 07:20:41
  char m1[3]; int  m2; // Month conversion ( Jun to 6 )
  (pt.substring(0,3)).toCharArray(m1,4);
  for (int mx = 0; mx < 12; mx ++) {
    if (strcmp(m1, monthName[mx]) == 0){m2 = mx + 1; break;}
  }
  RTC_DateTypeDef DateStruct;         // Month, Date, Year 
  DateStruct.Month   = m2;
  DateStruct.Date    = (pt.substring(4, 6)).toInt();
  DateStruct.Year    = (pt.substring(7,11)).toInt();
  M5.Rtc.SetData(&DateStruct);
  RTC_TimeTypeDef TimeStruct;         // Hours, Minutes, Seconds 
  TimeStruct.Hours   = (pt.substring(12,14)).toInt();
  TimeStruct.Minutes = (pt.substring(15,17)).toInt();
  TimeStruct.Seconds = (pt.substring(18,20)).toInt();
  M5.Rtc.SetTime(&TimeStruct);
  // rtc setup end -----------------------------------------------
}

void loop(void){ 
  if(digitalRead(M5_BUTTON_HOME) == LOW){
    if (mode_ == 2){mode_ = 1;M5.Lcd.fillScreen(BLACK);return;}
    if (mode_ == 1){mode_ = 2;M5.Lcd.fillScreen(BLACK);return;}
  }
  if ( mode_ == 2 ){ vfd_2_line();}   // yyyy,mm,dd,hh,mm,ss
  if ( mode_ == 1 ){ vfd_1_line();}   // mm,ss
  delay(500);
}

void vfd_2_line(){
  M5.Rtc.GetTime(&RTC_TimeStruct);
  M5.Rtc.GetData(&RTC_DateStruct);
  //Serial.printf("Data: %04d-%02d-%02d\n",RTC_DateStruct.Year,RTC_DateStruct.Month,RTC_DateStruct.Date);
  //Serial.printf("Week: %d\n",RTC_DateStruct.WeekDay);
  //Serial.printf("Time: %02d : %02d : %02d\n",RTC_TimeStruct.Hours,RTC_TimeStruct.Minutes,RTC_TimeStruct.Seconds);
  // Data: 2019-06-06
  // Week: 0
  // Time: 09 : 55 : 26
  int y1 = int(RTC_DateStruct.Year    / 1000 );
  int y2 = int((RTC_DateStruct.Year   - y1*1000 ) / 100 );
  int y3 = int((RTC_DateStruct.Year   - y1*1000 - y2*100 ) / 10 );
  int y4 = int(RTC_DateStruct.Year    - y1*1000 - y2*100 - y3*10 );
  int j1 = int(RTC_DateStruct.Month   / 10);
  int j2 = int(RTC_DateStruct.Month   - j1*10 );
  int d1 = int(RTC_DateStruct.Date    / 10 );
  int d2 = int(RTC_DateStruct.Date    - d1*10 );
  int h1 = int(RTC_TimeStruct.Hours   / 10) ;
  int h2 = int(RTC_TimeStruct.Hours   - h1*10 );
  int i1 = int(RTC_TimeStruct.Minutes / 10 );
  int i2 = int(RTC_TimeStruct.Minutes - i1*10 );
  int s1 = int(RTC_TimeStruct.Seconds / 10 );
  int s2 = int(RTC_TimeStruct.Seconds - s1*10 );
  
  M5.Lcd.pushImage(  0, 0,18,34, (uint16_t *)n[y1]); 
  M5.Lcd.pushImage( 19, 0,18,34, (uint16_t *)n[y2]);
  M5.Lcd.pushImage( 38, 0,18,34, (uint16_t *)n[y3]);
  M5.Lcd.pushImage( 57, 0,18,34, (uint16_t *)n[y4]);
  M5.Lcd.drawPixel( 77,13, ORANGE); M5.Lcd.drawPixel( 77,23,ORANGE);
  M5.Lcd.pushImage( 80, 0,18,34, (uint16_t *)n[j1]);
  M5.Lcd.pushImage( 99, 0,18,34, (uint16_t *)n[j2]);
  M5.Lcd.drawPixel(118,13, ORANGE); M5.Lcd.drawPixel(119,23,ORANGE);
  M5.Lcd.pushImage(120, 0,18,34, (uint16_t *)n[d1]);
  M5.Lcd.pushImage(140, 0,18,34, (uint16_t *)n[d2]);
                                                   
  M5.Lcd.pushImage( 00,40,18,34, (uint16_t *)n[h1]);
  M5.Lcd.pushImage( 20,40,18,34, (uint16_t *)n[h2]);
  M5.Lcd.drawPixel( 48,54, ORANGE); M5.Lcd.drawPixel( 48,64,ORANGE); 
  M5.Lcd.pushImage( 60,40,18,34, (uint16_t *)n[i1]);
  M5.Lcd.pushImage( 80,40,18,34, (uint16_t *)n[i2]);
  M5.Lcd.drawPixel(108,54, ORANGE); M5.Lcd.drawPixel(108,64,ORANGE);
  M5.Lcd.pushImage(120,40,18,34, (uint16_t *)n[s1]);
  M5.Lcd.pushImage(140,40,18,34, (uint16_t *)n[s2]);

  if ( i1 == 0 && i2 == 0 ){ fade();}
}

void vfd_1_line(){
  M5.Rtc.GetTime(&RTC_TimeStruct);
  M5.Rtc.GetData(&RTC_DateStruct);
  int i1 = int(RTC_TimeStruct.Minutes / 10 );
  int i2 = int(RTC_TimeStruct.Minutes - i1*10 );
  int s1 = int(RTC_TimeStruct.Seconds / 10 );
  int s2 = int(RTC_TimeStruct.Seconds - s1*10 );
 
  //M5.Lcd.drawPixel( 48,54, ORANGE); M5.Lcd.drawPixel( 48,64,ORANGE); 
  M5.Lcd.pushImage(  2,6,35,67, (uint16_t *)m[i1]);
  M5.Lcd.pushImage( 41,6,35,67, (uint16_t *)m[i2]);
  //M5.Lcd.drawPixel(108,54, ORANGE); M5.Lcd.drawPixel(108,64,ORANGE);
  M5.Lcd.pushImage( 83,6,35,67, (uint16_t *)m[s1]);
  M5.Lcd.pushImage(121,6,35,67, (uint16_t *)m[s2]);

  if ( s1 == 0 && s2 == 0 ){ fade();}
}

void fade(){
  for (int i=7;i<16;i++){M5.Axp.ScreenBreath(i);delay(25);}
  for (int i=15;i>7;i--){M5.Axp.ScreenBreath(i);delay(25);}
  M5.Axp.ScreenBreath(12);
}

.
M5StickC , VFD , Nixie tube , ニキシー管 , IPS , clock , M5Stack Official Store , Hex File

Written by macsbug

6月 6, 2019 at 5:00 pm

カテゴリー: M5STACK

M5StickC Audio Spectrum Display

leave a comment »

M5StickC で Audio Spectrum Display を製作しました。 2019.06.01


_ 注:gif 画像にて音はでません。


.
準備:
_ 1. Arduino IDE 1.8.9
_ 2. M5StickC:販売:M5Stack Official Store:$11.90 + $4.74 shipping。
_   輸送期間:8日。
_ 3. Audio spectrum:Audio Spectrum Display with M5STACK
_ 4. m5Stack / M5StickC:github
_ 5. M5StickC exsample:Microphone


.
作成:
_ Audio Spectrum Display with M5STACK に M5StickC の Microphone を移植。

_ M5StickC の マイクは SPM1423 I2C を使用しています。
_ 使用 PORT は D : G34 , C : G0 です。
_ マイクは M5 ボタンの下にあります。
_ 特性:iPad の Signal Generator で周波数特性を確認し大凡の表示をしています。
_    雰囲気を感じる程度です。

_ 

_ 


.
補足:
_ tobozo/ESP32-Audio-Spectrum-Waveform-Display を基に移植しました。
_ 今回は ESP32_Spectrum_Display_03.ino 以前のバージョンで制作しています。
_ 周波数領域:8オクターブ
_ バンド:125Hz 250Hz 500Hz 1KHz 2KHz 4KHz 8KHz 16kHz の8つ。
_ マイクと感度:最適な結果を得る為には マイクや感度の考慮が重要です。
_  tobozo氏の例では “DCオフセットなしで約50mV〜100mV pk-pkの
_    Audioを直接ADCポートに供給することです。” と書かれています。
_ 調整:eqBand で設定します。
_    eqBand は freqname, amplitude, peak, lastpeak, lastval, lastmeasured
_    で構成されています。これは オクターブ毎にあります。
_    例:1KHz: { “1KHz”, 200, 0, 0, 0, 0} // 200 は ゲインです。
_      M5StcickCのマイクの特性に合わせて調整してください。

eqBand audiospectrum[8] = {
  // Adjust the amplitude values to fit your microphone
  // freqname,amplitude,peak,lastpeak,lastval,lastmeasured
  { ".1", 900, 0, 0, 0, 0}, 
  { ".2", 500, 0, 0, 0, 0}, 
  { ".5", 200, 0, 0, 0, 0},
  { "1" , 200, 0, 0, 0, 0},
  { "2" , 200, 0, 0, 0, 0},
  { "4" , 100, 0, 0, 0, 0},
  { "8" , 100, 0, 0, 0, 0},
  { "16",  50, 0, 0, 0, 0}
};

_ 最新版の tobozo/ESP32_Spectrum_Display_03.ino では
_    eqBand は freqname, amplitude, bandWidth, peak, lastpeak, curval,
_     lastval, lastmeasured で 6つから8つになっています。
_    例:1KHz:{ “1KHz”, 250, 7, 0, 0, 0, 0, 0}


.
参照:
_ M5StickC docs:概要(電源操作、サポート ボーレート、ピンマップ)
_ github:M5StickC Library:M5StickC ライブラリー
_ M5StickC Audio Spectrum Display : 2019.06.01 : macsbug
_ Audio Spectrum Display with M5STACK : 2017.12.31 : macsbug
_ tobozo/ESP32-Audio-Spectrum-Waveform-Display:ESP32-8-Octave-Audio-Spectrum-Display
_ G6EJD/ESP32-8266-Audio-Spectrum-Display:ESP32-8266-Audio-Spectrum-Display
_ kosme/arduinoFFT
_ M5StickC 使用チップ:ESP32-PICO-D4
_ SPM1423 I2C:仕様。
_ M5StickC exsample:Microphone:M5StickC exsample。
_ hacster.oi:Audio Spectrum Display with M5Stack:2019.04.17 紹介記事。
_ ElectroMagus/M5-FFT:MAX9814 マイクロフォンの例。


.
感想:
M5StickC IPS Display の表示は綺麗です。
M5StickC が 2台有るとステレオで表示する事が出来ます。
M5StickCの注意点:時折 動作しなくなる時があります。故障ではなく慌てない事です。
_ 電源IC AXP192 の設定による物と想像します。
とりあえず表示したく移植し 縦軸と横軸は深い検討をしていません。
輸送期間:M5Stack Official Store は これまでの最短の 8日で到着。
_    $4.74 shipping で Air Mail を使用しています。例:5/8 に注文し 5/16 に到着。
_    輸送力の向上は 販売側と購入者の双方に大きなメリットがあります。
I2C SPM1423 Mic:example の Microphone は 複雑で使用し難いです。
_ Arduino や ESP8266 では analogRead の1行で済みますが I2C Microphone は
_  かなりの行数を使用しています。1行で可能なライブラリーを期待しています。
価格:追記 2019.06.04。 M5Stack Official Store = 1799円。$16.64。SS = 2444円。


.
スケッチ:M5StickC Audio Spectrum Display : 2019.06.01 : macsbug

/* ESP8266/32 Audio Spectrum Analyser on an SSD1306/SH1106 Display
 * The MIT License (MIT) Copyright (c) 2017 by David Bird. 
 * The formulation and display of an AUdio Spectrum using an ESp8266 or ESP32 and SSD1306 or SH1106 OLED Display using a Fast Fourier Transform
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files 
 * (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, 
 * publish, distribute, but not to use it commercially for profit making or to sub-license and/or to sell copies of the Software or to 
 * permit persons to whom the Software is furnished to do so, subject to the following conditions:  
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
 * See more at http://dsbird.org.uk 
*/
// M5StickC Audio Spectrum             : 2019.06.01 : macsbug
//  https://macsbug.wordpress.com/2019/06/01/
// Audio Spectrum Display with M5STACK : 2017.12.31 : macsbug
//  https://macsbug.wordpress.com/2017/12/31/audio-spectrum-display-with-m5stack/
// https://github.com/tobozo/ESP32-8-Octave-Audio-Spectrum-Display/tree/wrover-kit
// https://github.com/G6EJD/ESP32-8266-Audio-Spectrum-Display
// https://github.com/kosme/arduinoFFT

#include "arduinoFFT.h"
arduinoFFT FFT = arduinoFFT();  
#include <M5StickC.h>
#include <driver/i2s.h>
#pragma GCC optimize ("O3")
#define PIN_CLK  0
#define PIN_DATA 34
#define READ_LEN (2 * 1024)
uint8_t BUFFER[READ_LEN] = {0};
uint16_t oldx[160];
uint16_t oldy[160];
uint16_t *adcBuffer = NULL; // uint16_t *adcBuffer = NULL;
#define SAMPLES 512         // Must be a power of 2
#define SAMPLING_FREQUENCY 40000
struct eqBand {
  const char *freqname;
  uint16_t amplitude;
  int peak;
  int lastpeak;
  uint16_t lastval;
  unsigned long lastmeasured;
};

eqBand audiospectrum[8] = {
  // Adjust the amplitude values to fit your microphone
  // freqname,amplitude,peak,lastpeak,lastval,lastmeasured
  {  ".1",1000, 0, 0, 0, 0},
  {  ".2", 500, 0, 0, 0, 0},
  {  ".5", 300, 0, 0, 0, 0},
  {  "1" , 250, 0, 0, 0, 0},
  {  "2" , 200, 0, 0, 0, 0},
  {  "4" , 100, 0, 0, 0, 0},
  {  "8" ,  50, 0, 0, 0, 0},
  { "16" ,  50, 0, 0, 0, 0}
};

unsigned int sampling_period_us;
unsigned long microseconds;
double vReal[SAMPLES];
double vImag[SAMPLES];
unsigned long newTime, oldTime;
uint16_t tft_width  = 160;
uint16_t tft_height =  80;
uint8_t bands = 8;
uint8_t bands_width = floor( tft_width / bands );
uint8_t bands_pad = bands_width - 10;
uint16_t colormap[255];//color palette for the band meter(pre-fill in setup)

void i2sInit(){
   i2s_config_t i2s_config = {
    .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_PDM),
    .sample_rate =  44100,
    .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, //is fixed at 12bit,stereo,MSB
    .channel_format = I2S_CHANNEL_FMT_ALL_RIGHT,
    .communication_format = I2S_COMM_FORMAT_I2S,
    .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
    .dma_buf_count = 2,
    .dma_buf_len = 128,
   };
   i2s_pin_config_t pin_config;
   pin_config.bck_io_num   = I2S_PIN_NO_CHANGE;
   pin_config.ws_io_num    = PIN_CLK;
   pin_config.data_out_num = I2S_PIN_NO_CHANGE;
   pin_config.data_in_num  = PIN_DATA; 
   i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);
   i2s_set_pin(I2S_NUM_0, &pin_config);
   i2s_set_clk(I2S_NUM_0, 44100,I2S_BITS_PER_SAMPLE_16BIT,I2S_CHANNEL_MONO);
}

void mic_record_task (void* arg){      
  while(1){
    i2s_read_bytes(I2S_NUM_0,(char*)BUFFER,READ_LEN,(100/portTICK_RATE_MS));
    adcBuffer = (uint16_t *)BUFFER;
    showSignal();
    vTaskDelay(100 / portTICK_RATE_MS);
  }
}

void setup() {
  M5.begin();
  M5.Lcd.setRotation(1);
  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.setTextColor(BLUE);
  M5.Lcd.setTextSize(1);
  
  i2sInit();
  xTaskCreatePinnedToCore(mic_record_task,"mic_record_task",2048,NULL,1,NULL,1);

  sampling_period_us = round(1000000 * (1.0 / SAMPLING_FREQUENCY));
  delay(2000);
  for(uint8_t i=0;i<tft_height;i++) {
  //colormap[i] = M5.Lcd.color565(tft_height-i*.5,i*1.1,0); //RGB 
    colormap[i] = M5.Lcd.color565(tft_height-i*4.4,i*2.5,0);//RGB:rev macsbug
  }
  for (byte band = 0; band <= 7; band++) {
    M5.Lcd.setCursor(bands_width*band + 2, 0);
    M5.Lcd.print(audiospectrum[band].freqname);
  }
}

void showSignal(){
  for (int i = 0; i < SAMPLES; i++) {
    newTime  = micros() - oldTime;
    oldTime  = newTime;
    vReal[i] = adcBuffer[i];
    vImag[i] = 0;
    while (micros() < (newTime + sampling_period_us)){//do nothing to wait
    }
  }
  
  FFT.Windowing(vReal, SAMPLES, FFT_WIN_TYP_HAMMING, FFT_FORWARD);
  FFT.Compute(vReal, vImag, SAMPLES, FFT_FORWARD);
  FFT.ComplexToMagnitude(vReal, vImag, SAMPLES);

  for (int i = 2; i < (SAMPLES/2); i++){ 
    // Don't use sample 0 and only first SAMPLES/2 are usable. 
    // Each array eleement represents a frequency and its value the amplitude.
    if (vReal[i] > 1500) { // Add a crude noise filter, 10 x amplitude or more
      byte bandNum = getBand(i);
      if(bandNum!=8) {
        displayBand(bandNum, (int)vReal[i]/audiospectrum[bandNum].amplitude);
      }
    }
  }
  long vnow = millis();
  for (byte band = 0; band <= 7; band++) {
    // auto decay every 50ms on low activity bands
    if(vnow - audiospectrum[band].lastmeasured > 50) {
      displayBand(band, audiospectrum[band].lastval>4 ? audiospectrum[band].lastval-4 : 0);
    }
    if (audiospectrum[band].peak > 0) {
      audiospectrum[band].peak -= 2;
      if(audiospectrum[band].peak<=0) {
        audiospectrum[band].peak = 0;
      }
    }
    // only draw if peak changed
    if(audiospectrum[band].lastpeak != audiospectrum[band].peak) {
      // delete last peak
     M5.Lcd.drawFastHLine(bands_width*band,tft_height-audiospectrum[band].lastpeak,bands_pad,BLACK);
     audiospectrum[band].lastpeak = audiospectrum[band].peak;
     M5.Lcd.drawFastHLine(bands_width*band, tft_height-audiospectrum[band].peak,
                          bands_pad, colormap[tft_height-audiospectrum[band].peak]);
    }
  } 
}

void displayBand(int band, int dsize){
  uint16_t hpos = bands_width*band;
  int dmax = 200;
  if(dsize>tft_height-10) {
    dsize = tft_height-10; // leave some hspace for text
  }
  if(dsize < audiospectrum[band].lastval) {
    // lower value, delete some lines
    M5.Lcd.fillRect(hpos, tft_height-audiospectrum[band].lastval,
                    bands_pad, audiospectrum[band].lastval - dsize,BLACK);
  }
  if (dsize > dmax) dsize = dmax;
  for (int s = 0; s <= dsize; s=s+4){
    M5.Lcd.drawFastHLine(hpos, tft_height-s, bands_pad, colormap[tft_height-s]);
  }
  if (dsize > audiospectrum[band].peak){audiospectrum[band].peak = dsize;}
  audiospectrum[band].lastval = dsize;
  audiospectrum[band].lastmeasured = millis();
}

byte getBand(int i) {
  if (i<=2 )             return 0;  // 125Hz
  if (i >3   && i<=5 )   return 1;  // 250Hz
  if (i >5   && i<=7 )   return 2;  // 500Hz
  if (i >7   && i<=15 )  return 3;  // 1000Hz
  if (i >15  && i<=30 )  return 4;  // 2000Hz
  if (i >30  && i<=53 )  return 5;  // 4000Hz
  if (i >53  && i<=200 ) return 6;  // 8000Hz
  if (i >200           ) return 7;  // 16000Hz
  return 8;
}

void loop() {}

.
M5StickC , Audio , Spectrum , M5Stack Official Store , ESP32-PICO-D4 , SPM1423 ,

Written by macsbug

6月 1, 2019 at 10:00 am

カテゴリー: M5STACK