電子趣味の部屋

電子系のガジェットやアプリ開発等の趣味の話題を書いてます

M5Stackで軽く遊んでみました 時計編

今回はM5Stackで遊んでみました。
これも前にM5StickCと一緒に買って積みハードになっていました。

サンプルスケッチを簡単にまとめただけですが、自分用のメモも兼ねてシンプルなソースを書きました。

Wi-fi経由でNTPサーバから時間を取得して日時を表示するまでのサンプルです。


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

const char* ssid       = "(Wi-fiアクセスポイントのSSID)";  
const char* password   = "(Wi-fiアクセスポイントのパスワード)";

// NTPサーバのURL
const char* ntpServer =  "ntp.jst.mfeed.ad.jp";
//  GMT+9(日本時間)
const long  gmtOffset_sec = 9 * 3600;
// サマータイム時差(無し)
const int   daylightOffset_sec = 0;

void setup() {
  M5.begin();
  
  M5.Lcd.clear(TFT_BLACK);
  M5.Lcd.setTextColor(TFT_WHITE, TFT_BLACK);
  M5.Lcd.setTextSize(4);

  WiFi.begin(ssid, password);

  // 500ms*120回なので、1分でタイムアウト
  for (int i = 0; i < 120 && WiFi.status() != WL_CONNECTED; i++) {
    delay(500);
  }
  if (WiFi.status() != WL_CONNECTED) {
    // Wifi接続エラー
  }

  if (WiFi.status() == WL_CONNECTED) {
    configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
    struct tm t;
    if (!getLocalTime(&t)) {
      // NTPサーバ接続エラー
    }
  }
  WiFi.disconnect(true);
  WiFi.mode(WIFI_OFF);

}

void loop() {
  struct tm t;
  if (getLocalTime(&t)) {
    M5.Lcd.setCursor(0, 0);
    M5.Lcd.printf("%04d/%02d/%02d", (1900 + t.tm_year), t.tm_mon, t.tm_mday);
    M5.Lcd.setCursor(0, 40);
    M5.Lcd.printf("%02d:%02d:%02d", t.tm_hour, t.tm_min, t.tm_sec);
  }
  
  delay(100);

}

みんなのM5Stack入門

みんなのM5Stack入門

M5StickCで軽く遊んでみました2 UIFlow編

前回紹介したM5StickCですが、今回はUIFlowで遊んでみました。

UIFlowはWEB版とデスクトップ版があるのですが、今回は手軽そうなWEB版を使いました。
WEB版を使用するには、ネットにつながったWifi環境が必要です

準備

ダウンロードページ

Download – m5stack-store
https://m5stack.com/pages/download

ここから M5Burner をダウンロードします。
デスクトップ版(UIFlow-Desktop-IDE)もここでダウンロードします。

M5Bunner

ダウンロードした M5Bunner でファームウェアM5StickCに書き込みます。
2020年5月14日の時点でM5StickCに対応しているファームウェアはUIFlow-v1.4.5.1です。

UIFlow-v1.4.5.1でを押してファームウェアをダウンロードした後で各設定をして[Burn]ボタンを押すとファームウェアM5StickCへ書き込まれます。

COM: M5StickCが接続されたCOMポートを選択
Baudrate: Series設定時に変更されたデフォルトの値のままでOK
Series: StickCを選択
SSID: WifiアクセスポイントのSSID
Password: Wifiアクセスポイントのパスワード

ファームウェアが書き込まれると、M5StickCに下の画像のような画面が表示されます。
f:id:uosoft:20200302165016j:plain
丸いマークが緑ならネット接続に成功しています。それ以外の場合はSSID等のネットの設定を見直してください。
で隠してある部分にAPIキーが表示されます。

UIFlow

ブラウザでUIFlowのページを開きます。

設定

起動時に下のような画面が表示されるので、APIキー等の設定をします。

Api key M5StickCに表示されたAPIキー
Language 日本語も選択できます
Device Stick-c

遊んでみる

前回 と同じように簡単なカウンターを作ってみました。

ソース?
f:id:uosoft:20200514111814p:plain
表示の部分は本来テキストを表示するブロックがあるのですが、数値の0埋め表示が無かった(わからなかった)ので、コード実行ブロックを使用して直接Pythonのコードを書きました。
内部的にはMicroPythonで動かしているようで、Pyhonに置き換えられたコードも見ることができます。
f:id:uosoft:20200514112836p:plain

プログラムできる人はArduinoIDEで普通にコードを書くのが圧倒的にやりやすいと思いますが。
ちょっと遊んだりプログラムの勉強をするのには面白いと思います。

M5StickCで軽く遊んでみました

結構前に買って放置していたM5StickCを見つけたので軽く遊んでみました。

開発環境

開発環境はいくつかあるのですが、とりあえず使い慣れたArduino IDEで行います。
セットアップ方法は公式ページに書いてあります。
M5Stack Docs-The reference docs for M5Stack products.
https://docs.m5stack.com/#/en/arduino/arduino_development
解説は英語で書かれてますが、設定個所は同じなのでわかると思います。

サンプルプログラム

簡単なカウンターを作ってみました。

M5ボタン(ホームボタン)を押すとカウントアップして、リセットボタンを押すとカウントが0になります。

// M5StickCのライブラリをインクルード
#include <M5StickC.h>

// カウントを0で初期設定
int count = 0;

void setup() {

  // M5StickC初期化
  M5.begin();
  
  // 背景色を黒で塗りつぶし
  M5.Lcd.fillScreen(TFT_BLACK);
  // 文字色を白、背景色を黒に設定
  M5.Lcd.setTextColor(TFT_WHITE, TFT_BLACK);

  // M5StickCの向きを設定(M5ボタンが左)
  M5.Lcd.setRotation(1);
  // 文字サイズを設定
  M5.Lcd.setTextSize(6);

  // カウント表示
  print_count();
}

void loop() {

  // M5ボタンが押された時の処理
  if (digitalRead(M5_BUTTON_HOME) == LOW) {
    // ボタンを離すまで待つ
    while (digitalRead(M5_BUTTON_HOME) == LOW) ;
    // カウントアップ
    count++;
    // 9999以上は9999にする
    if (count > 9999) {
      count = 9999;
    }
    // カウント表示
    print_count();
  }

  // リセットが押された時の処理
  if (digitalRead(M5_BUTTON_RST) == LOW) {
    // ボタンを離すまで待つ
    while (digitalRead(M5_BUTTON_RST) == LOW) ;
    // カウントを0に
    count = 0;
    // カウント表示
    print_count();
  }

}

void print_count() {
  // カーソル位置をセット
  M5.Lcd.setCursor(10, 20);
  // カウントを4桁0埋めで表示
  M5.Lcd.printf("%04d", count);
}

Hallo world を少し発展させたようなプログラムですが、基本の文字の表示とボタンの状態取得はわかると思います。

1つあれば便利!低価格小型オシロスコープ DS213

過去のエントリーで紹介したDSO203ですが、バッテリーが故障したせいか起動しなくなってしまいました。
使い勝手が良かったので、また同じものを買おうと思ってましたが、新型のDS213が発売されていたのでこちを選択しました。

アナログ帯域幅が旧型のほぼ倍の15MHzに、最大サンプル・レートが100MSa / sになっています。

仕様
モデル:DS213
MCU:STM32F103VC
ADC:HWD9288
チャンネル:2アナログ・チャンネル+ 2デジタル・チャンネル
アナログ帯域幅:15MHz
最大サンプル・レート:100MSa / s
最大サンプルメモリ長:4K
水平感度:100nS / Div〜1S / Div(1-2-5シーケンス・ステップ)
垂直感度:10mV / Div〜10V / Div(1-2-5シーケンス・ステップ)
アナログ入力インピーダンス:1MΩ
カップリング:DC / AC
ストレージ:8MB USBフラッシュディスクメモリ
USBポート:ミニUSB
バッテリー:1000mAh
画面サイズ:3 "
画面の解像度:400×240
寸法:99×59×13mm
重量(電池付):129グラム
オープン・ソース:アプリケーション層オープンソース
認証:CE / FCC

現在の用途ではスペックアップの恩恵はうけてませんが、使い勝手は変わっておらず、使いやすいです。

低価格で便利なマルチテスタ

コンデンサの容量や抵抗の値が簡単に見えるのがないかと思い探していたところ、便利なものを見つけました。

aliexpressで2千円ほどで購入しましたが、Amazonでも結構安く購入できそうです
外見は微妙に違うものもありますが、中身は同じだと思います。

コンデンサをセットしてStartボタンを押すだけで計測できます。


同じように抵抗値も計測できます。

さらにIRセンサで波形まで調べることができます。

他にも色々とできるようですが、説明書がないので徐々に調べていきます。

PC-9801NS/L再生

ふとPC-9801の白黒液晶のノートが欲しいと思いいろいろ調べてたら、意外と簡単にジャンク品を修理できそうだったので挑戦してみました。
1度目はPC-9801NS/Aのジャンク品を送料込みで3000円位で入手したのですが、電源が入るまで復活したものの、”system shutdown”とエラー表示され、これ以上いくら調べてもわからないので断念。
2度目にPC-9801NS/Lのジャンク品を同じく送料込みで3000円位で入手して修理で復活できました。

まず起動しない場合は電源部分のコンデンサの液漏れ等が原因で容量抜けしている場合があります。
特にこの頃に使用されていた4級塩電解コンデンサは液漏れしている可能性が高いです。
f:id:uosoft:20190104011902j:plain
PC-9801NS/Lの電源部にある2個のコンデンサ(10uF 16V, 4.7uF 35V)を交換してみました。
f:id:uosoft:20190104022713j:plain

これだけで起動してしまいました。
f:id:uosoft:20190106021816j:plain

この後さらにPC-9801NS/Tも挑戦してみました。
ところが、電源が入り画面も明るくなるところまで行きましたが、ピポ音が鳴らず、画面には何も表示されず。
他のコンデンサも交換してみましたが、改善されず。
もう古いもののため、電源以外にも問題があるものも多く、意外と難しいです。

蘇るPC-9801伝説 永久保存版―月刊アスキー別冊

蘇るPC-9801伝説 永久保存版―月刊アスキー別冊

蘇るPC-9801伝説 永久保存版 第2弾

蘇るPC-9801伝説 永久保存版 第2弾

YAMAHAのFM音源IC(YM2413)の使い方の基礎

過去に"YAMAHAの音源IC(YMZ294)の使い方の基礎"でPSG(SSG)音源のYMZ294の使い方の基礎を説明しましたが、今回はFM音源の中で一番簡単なYM2413(OPLL)について説明します。

この音源は音色データを内蔵しているので、複雑なパラメータを指定しなくてもすぐに音を鳴らすことができます。

今回もArduino Unoで制御しますが、理解すればmbedでもPICやAVRで直接制御するにせよ同じ方法で使うことができるはずです。
初期処理から基準のA(ラ,440Hz)の音を出力するまでの手順を説明します。

個々のレジスタの情報等の詳細な仕様はアプリケーションマニュアルを参照ください。

http://d4.princess.ne.jp/msx/datas/OPLL/YM2413AP.html

ハードウェア

下の回路図のようにArduinoとYMZ294を接続しています。

Arduino 2:9 - YM2413 D0:D7
Arduino A0 - YM2413 IC
Arduino A1 - YM2413 CS
Arduino A2 - YM2413 WE
Arduino A3 - YM2413 A0

出力はメロディー出力のMOとリズム出力のROと別れてますが、今回はメロディー出力のみ使用します。
出力は小さいので、アンプを別に通すなり、アンプ回路を組むなりしてスピーカーやイヤホン等に接続してください。、

実際に動作させるまでの処理

IOの設定

まず、Arduinoに接続されたピンに対して便宜上名前を付けます。

const byte IC_PIN = A0;
const byte CS_PIN = A1;
const byte WE_PIN = A2;
const byte A0_PIN = A3;
const int DATA_PIN[] = { 2, 3, 4, 5, 6, 7, 8, 9 };

setup()内ですべて出力に設定します。

for (int i = 0; i < 8; i++) {
  pinMode(DATA_PIN[i], OUTPUT);
}
pinMode(CS_PIN, OUTPUT);
pinMode(A0_PIN, OUTPUT);
pinMode(IC_PIN, OUTPUT);
pinMode(WE_PIN, OUTPUT);
レジスタ書き込みファンクション

音源ICの機能は全てレジスタにアクセスすることで制御できます。
これは同じYAMAHA製のFM音源ICも含めて基本的なことなので、この概念を理解すると他の音源ICもレジスタの仕様をチェックするだけで使えるようになります。

CS_PINがLOWの状態でDATA_PINにバイトデータをセットし、CS_PINをHIGHにするとバイトデータがYM2413に送られます。このときA0_PINがLOWの場合はレジスタのアドレス、A0_PINがHIGHの場合はレジスタに入れる値となります。
すぐにCS_PINピンの状態を変えても反応しないことがあるため、アドレス書き込み時には12us程度、データ書き込み時には84us程度ウェイトを入れます。

この方法でレジスタに値をセットするファンクションを定義します。

void set_register(byte addr, byte value)
{
  // addr
  digitalWrite(A0_PIN, LOW);
  digitalWrite(CS_PIN, LOW);
  for (int i = 0; i < 8; i++) {
    digitalWrite(DATA_PIN[i], bitRead(addr, i));
  }
  delayMicroseconds(12);
  digitalWrite(CS_PIN, HIGH);

  // value
  digitalWrite(A0_PIN, HIGH);
  digitalWrite(CS_PIN, LOW);
  for (int i = 0; i < 8; i++) {
    digitalWrite(DATA_PIN[i], bitRead(value, i));
  }
  delayMicroseconds(84);
  digitalWrite(CS_PIN, LOW);
}
YM2413の初期化

動作の初めにYM2413を初期化します。
ICをLOWにし、100us程度間をおいてからICをHIGHにするとすべてのレジスタが0でリセットされます。
また今回はレジスタに書き込む程度の操作しかしないため、WEをLOWにしておきます。

リセット後にすぐにレジストを操作しても動作しないことがあるので、最後に1秒程度のウェイトを入れてますが、もっと短くしても大丈夫です。適当に調整してください。

この方法で初期化するファンクションを定義します。

void reset() {
  digitalWrite(WE_PIN, LOW);
  digitalWrite(IC_PIN, LOW);
  delayMicroseconds(100);
  digitalWrite(IC_PIN, HIGH);
  delay(1000);
}

このファンクションをsetup()内で実行します

  reset();
F-Numberを指定して出力

音の出力はF-Numberという値を使用します。

音程とF-Numberの対応表はアプリケーションマニュアルに書いてあります。

レジスタ0x10(+チャンネル番号)にF-Numberの下位8ビットを指定します。
レジスタ0x20(+チャンネル番号)に音階(オクターブ)とF-Numberの上位1ビットを指定します。

チャンネルとF-Numberを設定するファンクションを定義
レジスタ0x20(+チャンネル番号)に音のオン/オフ(key)も指定するするのですが、今回はkey=1(オン)を固定で設定します

void SetFNumber(int ch, int oct, int f_number) {
  // F-Numberの下位8ビット
  set_register(0x10 + ch, f_number & 0xff);
  // key=1, oct, F-Numberの上位1ビット
  set_register(0x20 + ch, (1 << 4) | (oct << 1) | (f_number >> 8));
}
音色と音量

レジスタ0x30(+チャンネル番号)の上位4ビットは音色、下位4ビットは音量になっています。

チャンネルと音色と音量を設定するファンクションを定義

void SetInstVol(int ch, int inst, int vol) {
  set_register(0x30 + ch, (inst << 4) | vol);
}
演奏

チャンネル0の音色を3(ピアノ)、音量を15にします。
チャンネル0に440HzのA(ラ)の音程のF-Number(288)とオクターブ4をセットします。
1秒後にチャンネル0の演奏を止めます。
この時0x20(+チャンネル番号)に0を入れます。こうすることによりkeyのビットも0になるので、演奏も止まります。
この処理は1回だけ実行するつもりだったので、setup()内の最後に追加しました。

  SetInstVol(0, 3, 16);
  SetFNumber(0, 4, 288);
  delay(1000);
  set_register(0x20, 0);

これで起動後、1秒間だけ音が出力されるはずです。

今回はおまけでloop()無いでドレミファソラシドを演奏するサンプルも書きました。

void loop() {
  delay(1000);
  SetFNumber(0, 4, 172);
  delay(500);
  SetFNumber(0, 4, 192);
  delay(500);
  SetFNumber(0, 4, 216);
  delay(500);
  SetFNumber(0, 4, 229);
  delay(500);
  SetFNumber(0, 4, 257);
  delay(500);
  SetFNumber(0, 4, 288);
  delay(500);
  SetFNumber(0, 4, 323);
  delay(500);
  SetFNumber(0, 4, 343);
  delay(1000);
  set_register(0x20, 0);
}

最後にソース全文を掲載するので、参考にどうぞ。

// Output Pins
const byte IC_PIN = A0;
const byte CS_PIN = A1;
const byte WE_PIN = A2;
const byte A0_PIN = A3;
const int DATA_PIN[] = { 2, 3, 4, 5, 6, 7, 8, 9 };

void setup() {

  for (int i = 0; i < 8; i++) {
    pinMode(DATA_PIN[i], OUTPUT);
  }
  pinMode(CS_PIN, OUTPUT);
  pinMode(A0_PIN, OUTPUT);
  pinMode(IC_PIN, OUTPUT);
  pinMode(WE_PIN, OUTPUT);
  
  reset();
  
  SetInstVol(0, 3, 16);
  SetFNumber(0, 4, 288);
  delay(1000);
  set_register(0x20, 0);

}

void loop() {
  delay(1000);
  SetFNumber(0, 4, 172);
  delay(500);
  SetFNumber(0, 4, 192);
  delay(500);
  SetFNumber(0, 4, 216);
  delay(500);
  SetFNumber(0, 4, 229);
  delay(500);
  SetFNumber(0, 4, 257);
  delay(500);
  SetFNumber(0, 4, 288);
  delay(500);
  SetFNumber(0, 4, 323);
  delay(500);
  SetFNumber(0, 4, 343);
  delay(1000);
  set_register(0x20, 0);
}

// 初期化
void reset() {
  digitalWrite(WE_PIN, LOW);
  digitalWrite(IC_PIN, LOW);
  delayMicroseconds(100);
  digitalWrite(IC_PIN, HIGH);
  delay(1000);
}

// F-Number指定
void SetFNumber(int ch, int oct, int f_number) {
  set_register(0x10 + ch, f_number & 0xff);
  set_register(0x20 + ch, 16 | (oct << 1) | (f_number >> 8));
}

// 音色と音量指定
void SetInstVol(int ch, int inst, int vol) {
  set_register(0x30 + ch, (inst << 4) | vol);
}

// レジスタセット
void set_register(byte addr, byte value)
{
  // addr
  digitalWrite(A0_PIN, LOW);
  digitalWrite(CS_PIN, LOW);
  for (int i = 0; i < 8; i++) {
    digitalWrite(DATA_PIN[i], bitRead(addr, i));
  }
  delayMicroseconds(12);
  digitalWrite(CS_PIN, HIGH);

  // value
  digitalWrite(A0_PIN, HIGH);
  digitalWrite(CS_PIN, LOW);
  for (int i = 0; i < 8; i++) {
    digitalWrite(DATA_PIN[i], bitRead(value, i));
  }
  delayMicroseconds(84);
  digitalWrite(CS_PIN, LOW);
}

【永久保証付き】Arduino Uno

【永久保証付き】Arduino Uno