M5StickCPlus + ENVⅢ Hat による時刻・室温・湿度サンプル

IKEAで買った温度・湿度付きの時計がすぐにズレるのが気になったので、手持ちのM5StickCPlus + ENVⅢ Hatで簡単につくってみました。ENV Hatを本体に直付けすると熱がこもるか本体の温度に引っ張られるような感じで+2~3℃上がってしまう問題があったので適当に引き伸ばしています。

世のサンプルコードでSHT3Dのインスタンスに対してinitを呼んでないことが多かったのですが、それだと起動時点で動作が止まってしまうので sht30.init()呼んでいます。

サンプル

#include <M5StickCPlus.h>
#include <WiFi.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
#include <Wire.h>
#include "M5_ENV.h"
#include "Adafruit_Sensor.h"
#include <Adafruit_BMP280.h>

WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", 3600 * 9);  // UTC+9 日本時間
String previousTime = "";                                // 前回の時刻を保存するための変数

SHT3X sht30;

const char *ssid = "********";  // あなたのWiFiのSSID
const char *password = "********";       // あなたのWiFiのパスワード

uint16_t rgbToColor(uint8_t r, uint8_t g, uint8_t b) {
  return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
}

void setup() {

  setCpuFrequencyMhz(80);

  pinMode(33, INPUT_PULLUP); // GPIO33をプルアップ入力に設定

  M5.begin();
  M5.Lcd.setRotation(1);
  M5.Lcd.fillScreen(BLACK);
  uint16_t color = rgbToColor(100, 100, 100);  // 赤色を指定
  M5.Lcd.setTextColor(color);
  M5.Lcd.setTextSize(5);  // フォントサイズを大きく設定
//  M5.Axp.ScreenBreath(10); // 液晶の明るさ設定

  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    M5.Lcd.print('.');
    delay(500);
  }

  timeClient.begin();

  Wire.end();
  Wire.begin(0, 26);
  sht30.init(); //この関数を呼ぶサンプルがなくてエラー履いていたのが、追加で動作した・・・
}

void loop() {

  timeClient.update();
  String currentTime = timeClient.getFormattedTime();

  if (currentTime != previousTime) {

    // 温度と湿度の読み取り
    sht30.get();
    float temperature = sht30.cTemp;  //Store the temperature obtained from shT30.
    float humidity = sht30.humidity;  //Store the humidity obtained from the SHT30.

    // センサーの値を画面に表示
    M5.Lcd.fillScreen(BLACK);
    M5.Lcd.setCursor(0, 10);
    M5.Lcd.println(currentTime);
    M5.Lcd.setCursor(40, 50);
    M5.Lcd.printf("%.1fC", temperature);
    M5.Lcd.setCursor(80, 90);
    M5.Lcd.printf("%.1f%%", humidity);

    previousTime = currentTime;
  }

  delay(250);
}

#M5StickCPlus のSPIFFS領域(内部フラッシュ)を扱うシンプルなサンプルコード #Arduino

M5StickCPlusには標準でSDカードなし

センシングしたデータなどを電源が切れても保存しておくためのデータ保存について。M5StackにはSDカードが使えるようですが、M5StickCPlusには残念ながら標準では付いていません。

調べるとSPIFFSというフラッシュメモリの一部を使える事が分かりました。上記のサイトなどを参考にさせて頂きつつ、分かりにくかったところにコメントやSerial.print入れまくって自分なりに整理したものを置いておきます。

サンプルコード SPIFFS_Sample.ino

#include <M5StickCPlus.h>
#include "FS.h"
#include "SPIFFS.h"

const char *FILE_PATH = "/log.txt"; //テキスト保存するファイル名
const char *INIT_STR = ""; //初期化するテキスト;

void readFile() {

  File file = SPIFFS.open(FILE_PATH, "r");
  if (!file || file.isDirectory()) {
    Serial.printf("Failed to open file for reading: %s\r\n", FILE_PATH);
    return;
  } else {
    Serial.printf("Success to open file for reading: %s\r\n", FILE_PATH);
  }

  Serial.println("/////////////////////READ START/////////////////////");

  while (file.available()) {
    Serial.write(file.read());
  }

  Serial.println("/////////////////////READ END/////////////////////");

  file.close();
}

void removeFile() {

  //ファイルが存在すればリムーブできる
  if (SPIFFS.remove(FILE_PATH)) {

    //Serial.println("Remove success.");
    Serial.printf("Remove success: %s\r\n", FILE_PATH);
  } else {

    Serial.printf("Remove failed. Not available.: %s\r\n", FILE_PATH);
  };
}

void writeFile(const char *str) {
  File file = SPIFFS.open(FILE_PATH, FILE_APPEND);

  if (!file) {
    Serial.printf("Failed to open file for appending.: %s\r\n", FILE_PATH);
    return;
  } else {

    Serial.printf("Success to open file for appending.: %s\r\n", FILE_PATH);    

    if (file.print(str)) {

      Serial.printf("File writen: %s\r\n", str);

    } else {

      Serial.printf("File write failed: %s\r\n", str);
    }
  }

  Serial.print("File size:");
  Serial.println(file.size());

  file.close();
}


void resetFile() {

  removeFile();
  writeFile(INIT_STR);
}


void setup() {

  M5.begin();

  if (!SPIFFS.begin(true)) {
    Serial.println("SPIFFS Mount Failed");
    return;
  } else {
    Serial.println("SPIFFS Mount Success");
  }

  resetFile();
  writeFile("Test\r\n");
  writeFile("Test2\r\n");
  writeFile("139.85289,135.7654\r\n");
  readFile();
  readFile();
}

void loop() {
 
}

#M5StickCPlus + Speaker Hat でサンプル音を鳴らす Speaker.ino の改良 #Arduino

M5StickCPlus + Speaker Hat

M5StickCPlusで音を鳴らすサンプルにはArduino IDE / M5StickCPlus ライブラリ付属の Speaker.ino がありますが、ビープ音を鳴らす実装しかされていませんでした。音のデータ配列を鳴らす関数もあるのですがデータが入ってなかったので探してくっつけてみました。

見つけた音データはどうやらM5Stackの起動音的なものらしいです。探して分かったのですがバイナリデータがデカいのでサンプルコードから外されているのかなと思いました。

https://github.com/m5stack/M5Stack/blob/7e863fb9934bcb25f15afa720e9299b8a8e9a8fd/examples/Basics/FactoryTest/startup_music.c

また音を再生する上で26番PINにデータを送るのですがいろいろ試した結果 dacWrite 関数で出力するのが一番素直に再生されているようだったのでledcWriteToneから変更しています。

デモ

ボタンを押すとサンプル音が鳴りました!音質は8bitで古いサンプラーのような味のある音です。

これでM5StickCPlusに付属のMicで録音した音、Webからダウンロードした音・SDカード等から読み出した音を再生したりできそうです。

コード

#include <M5StickCPlus.h>

const int speakerPin = 26;

#define SAMPLES	(40000)
// BITSPERSAMPLE:	8,
// CHANNELS:	1,
#define SAMPLERATE	(20000)
// NORMALIZED:	FALSE,

extern const unsigned char m5stack_startup_music[];

void setup() {

    // put your setup code here, to run once:
    M5.begin();
    M5.Lcd.setRotation(0);
    M5.Lcd.setCursor(25, 80, 4);
    M5.Lcd.println("speaker");
    
}

void playMusic(const uint8_t* music_data,uint16_t sample_rate) {
    
    uint32_t length         = strlen((char*)music_data);
    uint32_t delay_interval = ((uint32_t)1000000 / sample_rate);
    for (int i = 0; i < length; i++) {
        
        dacWrite(speakerPin,music_data[i]);
        delayMicroseconds(delay_interval);
    }

}

void loop() {

  M5.update();

  if(M5.BtnA.wasReleased()){

    M5.Lcd.setCursor(25, 80, 4);
    M5.Lcd.println("playing!");

    //音楽の再生
    playMusic(m5stack_startup_music,SAMPLERATE);
    
    M5.Lcd.setCursor(25, 80, 4);
    M5.Lcd.println("speaker");

  }
   
}

// music from https://github.com/m5stack/M5Stack/blob/7e863fb9934bcb25f15afa720e9299b8a8e9a8fd/examples/Basics/FactoryTest/startup_music.c
const unsigned char m5stack_startup_music[] = {

 //ここに上のリンクの配列データを貼り付ける

 };

#M5StickCPlus でビープを鳴らす

M5Stackがアツいらしい

ちょいと試作をしてみようと思い久しぶりにArduino界隈に触れてみました。M5 Stackという開発環境が流行っているようなので上記の本を元に勉強を進めています。

購入したのはM5 StickC Plus

用途的に細くて軽い方が良かったのでSwitch ScienceにてM5 StickC Plusという製品を買いました。本を進めていると搭載Beep音を鳴らす所でM5 Stackのコードでは単純には動かないものがあり、M5 StickC Plusでは少し書き方が違うので調べました。

M5以下のSpeakerクラスが実装されておらず、代わりにBeepクラスが実装されているようでした。

修正後動いた!

コード(上記の本のサンプルコードのM5 Stick C Plus用 改変版)

#include <M5StickCPlus.h>

//各音符の周波数を定義しています
#define NOTE_C4 261.626  //ド4 C4
#define NOTE_C4b 277.183 //ド#4 C#4
#define NOTE_D4 293.665  //レ4 D4
#define NOTE_D4b 311.127 //レ#4 D#4
#define NOTE_E4 329.628  //ミ4 E4
#define NOTE_F4 349.228  //ファ4 F4
#define NOTE_F4b 369.994 //ファ#4 F#4
#define NOTE_G4 391.995  //ソ4 G4
#define NOTE_G4b 415.305 //ソ#4 G#4
#define NOTE_A4 440.000  //ラ4 A4
#define NOTE_A4b 466.164 //ラ#4 A#4
#define NOTE_B4 493.883  //シ4 B4
#define NOTE_C5 523.251  //ド5 C5
#define NOTE_C5b 554.365 //ド#5 C#5
#define NOTE_D5 587.330  //レ5 D5
#define NOTE_D5b 622.254 //レ#5 D#5
#define NOTE_E5 659.255  //ミ5 E5
#define NOTE_F5 698.456  //ファ5 F5
#define NOTE_F5b 739.989 //ファ#5 F#5
#define NOTE_G5 783.991  //ソ5 G5
#define NOTE_G5b 830.609 //ソ#5 G#5
#define NOTE_A5 880.000  //ラ5 A5
#define NOTE_A5b 932.328 //ラ#5 A#5
#define NOTE_B5 987.767  //シ5 B5
#define NOTE_C6 1046.502 //ド6 C6

//音符の長さをミリ秒で定義しています
#define R_4 2800
#define R_3 2100
#define R_2 1400
#define R_1 700
#define R_1_2 350
#define R_1_3 233.3
#define R_1_4 175
#define R_1_6 116.6
#define R_1_8 87.5
#define R_1_12 58.3
#define R_1_16 43.75

//エルガー「愛の挨拶」のメロディ
float salut[][2] =
{
  {NOTE_G5b, R_1},   {NOTE_B4, R_1_2}, {NOTE_G5b, R_1_2},
  {NOTE_F5b, R_1_2}, {NOTE_E5, R_1_2}, {NOTE_D5b, R_1_2}, {NOTE_E5, R_1_2},
  {NOTE_A5, R_1},   {NOTE_A5, R_1}, {NOTE_A5, R_1},    {NOTE_B4, R_1_2}
};

void setup() {
  M5.begin();
}

void loop() {
  //ボタンA(左のボタン)が押されたとき
  if (M5.BtnA.wasPressed()) {
    //スピーカーからブザー音を鳴らします
    M5.Beep.beep();
  }
  //ボタンB(中央のボタン)が押されたとき
  if (M5.BtnB.wasPressed()) {
    //配列salutを順番に読み込みます
    for (int i = 0; i < sizeof(salut) / sizeof(salut[0]); i++) {
      //[i][0]番目の要素の周波数をスピーカーから鳴らします。
      M5.Beep.tone(salut[i][0]);
      //[i][1]番目の要素の時間待ちます(音符の長さ)
      delay(salut[i][1]);
    }
    M5.Beep.end();
  }

  // M5Stackのボタン操作やスピーカーの状態を更新します
  M5.update();
}

秋月で売ってるESP-WROOM-02 DIPへ、FTDI USBシリアル変換アダプターで書き込むぞい

FullSizeRender 3

秋月電子通商Wi-Fiモジュール ESP-WROOM-02 DIPへSwitch ScienceのFTDI USBシリアル変換アダプターで書き込むためのブレッドボードメモ。

  • 書き込んだプログラムを走らせる場合、IO0とGNDを繋げているジャンパーピンを取り外す。
  • FIDI USBシリアル変換アダプタの電圧を3.3vにしておく。(ジャンパーピンで電圧を変更できる。)
  • 抵抗10KΩ