NodeMcu (5) Pulse Sensor

ESP8266でHeart Rate Monitorの表示は、色々と試してうまい表示方法はなかなか見つからない。

たまたま検索キーワードは”Pulse Sensor Arduino OLED”に変えて、参考にできそうなサイトはいくつ見つかった。

その中、”Online Heart Rate Monitor Using NodeMCU and Cayenne”「参考1」はイメージに近い。

Pulse Sensorについて、下記のサイトへどうぞ。

https://pulsesensor.com/

Pulse Sensorなどの部品があるので、早速実験。しかしコンバイルすると、Cayenne関連のエラーは出た。

Cayenneサービスは古いようで、適切なサービスが見つからない。OLEDでのMonitorは目的、Cayenneのサービスどうでもいいので、コメントアウトした。

それからPulse Sensorのライブラリも変わる。以前がここ;

https://github.com/WorldFamousElectronics/PulseSensor_Amped_Arduino

今はここ;

https://github.com/WorldFamousElectronics/PulseSensorPlayground

例のソースコードは、古いライブラリを使うから、そちらをダウンロードして利用。

表示はうまくできた。しかしPulse Sensorの精度はいまいち。

「参考1」の波形は、どうしてまともに表示されるね。

安定して表示できないから、このPulse Sensorは実験のみの意義かな。

参考:

  1. https://www.instructables.com/id/Online-Heart-Rate-Monitor-Using-NodeMCU-and-Cayenn/

 

Arduino NANO (10) Basic PC With VGA Output

経緯

参考1から、昔の BASIC は、2台のArduino NANOで実現可能とわかって、BASIC動くだけじゃなく、GPIOの制御もできるので、IoTの可能性の一つとして、試したくなった。

制作

専用のVGAとキーボードのコンセント部品の調達は時間がかかった。

それから結線にも時間がかかった、さらにプログラムの書き込みも手惑いが重ね、しかし電源入れると、あっさり成功。

正面の部品一覧

背面の配線

参考

  • https://www.instructables.com/id/Arduino-Basic-PC-With-VGA-Output/

ESP32 (2) SSD1306 & Clock

目的

SSD1306に時刻を表示するプログラム。

ESP8266と違って、SCL,SDAを探すも一苦労。

  • I2C0 – SDA,SCL = 21,22

**2019/9/2 注意:Adafruit_SSD1306関数の引数順番変更により、関連プログラムが影響する。

もともと次のような1行ものが、

// Adafruit_SSD1306 display(OLED_RESET);

次の数行に変わる。

// OLED Setting
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

なぜ互換性ないの引数順にするね?!どうしてもしたいならば、コンパイルエラーを出す方法で、修正を促す。

以前のプログラムが再検証するところ、エラーがなし、書き込みも成功、しかしOLEDが表示ない!困った。

ハードウェア故障?ソフトウェアバージョン問題?色々と検討して、数日無駄の末、やっと引数順変わったとわかった。Adafruitひどい!

ハードウェア

「DOIT ESP32 DEVKIT V1」が幅が広いから、ブレッドボードは片側しか空いてない。結線は、片側で間にってよかった。

「ESPDUINO-32」の場合も動作する

ソフトウェア

参考1のそのまま

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

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

// OLED Setting
#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);

#if (SSD1306_LCDHEIGHT != 32)
#error("Height incorrect, please fix Adafruit_SSD1306.h!");
#endif

// WiFi Setting
#define WIFI_SSID   "uislab003"
#define WIFI_PASSWORD   "nihao12345"
#define JST     3600*9

void setup() {
  Serial.begin(115200);
  delay(100);
  Serial.print("\n\nReset:\n");

  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3C (for the 128x32)
  // Clear the buffer.
  display.clearDisplay();
  display.setTextColor(WHITE);

  // WiFi starting
  drawLog("WiFi connecting...");
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  while(WiFi.status() != WL_CONNECTED) {
    Serial.print('.');
    delay(500);
  }
  Serial.println();
  Serial.printf("Connected, IP address: ");
  Serial.println(WiFi.localIP());
  drawLog("WiFi connected!");

  // NTP start
  configTime( JST, 0, "ntp.nict.jp", "ntp.jst.mfeed.ad.jp");
  delay(1000);
}

void loop() {
  time_t t;
  struct tm *tm;
  static const char *wd[7] = {"Sun","Mon","Tue","Wed","Thr","Fri","Sat"};
  char rdate[30], rtime[30];

  t = time(NULL);
  tm = localtime(&t);

  Serial.printf(" %04d/%02d/%02d(%s) %02d:%02d:%02d\n",
        tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
        wd[tm->tm_wday],
        tm->tm_hour, tm->tm_min, tm->tm_sec);
  sprintf(rdate, " %04d/%02d/%02d(%s)",
        tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, wd[tm->tm_wday]);
  sprintf(rtime, " %02d:%02d:%02d", 
        tm->tm_hour, tm->tm_min, tm->tm_sec);
  drawClock(rdate, rtime);      
  delay(1000 - millis()%1000);
}

void drawClock(const char* rdate, const char* rtime) {
  display.clearDisplay();
  display.setCursor(0,0);

  display.setTextSize(1);
  drawText(rdate);

  display.setCursor(0,13);

  display.setTextSize(2);
  drawText(rtime);

  display.display();
  delay(1);
}

void drawText(const char* text) {
  for (uint8_t i=0; i < strlen(text); i++) {
    display.write(text[i]);
  }    
}

void drawLog(const char* msg) {
  display.clearDisplay();
  display.setCursor(0,0);
  display.setTextSize(1);
  drawText(msg);

  display.display();
  delay(1);
}

 

参考

  1. https://qiita.com/nori-dev-akg/items/bbe269d1d1bf1826532a

Arduino NANO (7) ADS1115 for A/D

経緯

ADS1115を購入して、生体信号のAD変換に利用するつもりだが、うまくいかない( WeMos (b9) ADS1115 for A/D 参考)、正しい電圧が表示されない。

そこで、Arduino NANOのチュートリアルを探して、検証することに。

ハードウェア

ADS1115とArduino NANOはI2Cで接続。

ソフトウェア

「参考1」コードそのまま。

#include <Wire.h>
#include <Adafruit_ADS1015.h>

Adafruit_ADS1115 ads;  // Declare an instance of the ADS1115

int16_t rawADCvalue;  // The is where we store the value we receive from the ADS1115
float scalefactor = 0.1875F; // This is the scale factor for the default +/- 6.144 Volt Range we will use
float volts = 0.0; // The result of applying the scale factor to the raw value

void setup(void)
{
  Serial.begin(9600); 
  ads.begin();
}

void loop(void)
{  

  rawADCvalue = ads.readADC_Differential_0_1(); 
  volts = (rawADCvalue * scalefactor)/1000.0;
  
  Serial.print("Raw ADC Value = "); 
  Serial.print(rawADCvalue); 
  Serial.print("\tVoltage Measured = ");
  Serial.println(volts,6);
  Serial.println();
  

  delay(1000);
}

結果

うまくいく!

電池の電圧はちゃんでシリアルモニターに表示。

参考

 

http://henrysbench.capnfatz.com/henrys-bench/arduino-voltage-measurements/arduino-ads1115-differential-voltmeter-tutorial/

IoT Study Kit 2

ESP8266 IoT Study Kit 2は、ESP8266 IoT Study Kitと同じ、センサー、表示機能が備えている。

モジュール式って、結線は必要ない。携帯不便の問題を解消した。また結線がないことで、ハードウェア苦手の人でも、IoTはソフトウェアの課題に限定出来る。

ESP8266 IoT Study Kit 2には、次の部品から構成:

  1. ESP8266 モジュール(WeMos D1 Mini)
  2. SHT30 モジュール(温度、湿度センサー)
  3. MatrixLED モジュール
  4. 三連装ベース
  5. Mini OLED モジュール (Option)

三連装ベースの上に、各モジュールを装着する。

MatrixLED モジュール装着した様子。

Mini OLED モジュール (Option)装着した様子。

Arduino UNO (8) mini-Oscilloscope

Piezoセンサーを検証中、信号が見えないので、機能の確認に困っている。

OLEDのミニモニターは、何とかできないかよ探したところ、Arduino UNO時代のものがあり、ESP8266の対応品がない。ESP8266に対応して見たが、うまく表示できない。

仕方なく、蔵入りのArduino UNOを出して、まず検証して見る。

 

コンパイルエラーと、それと関連する表示範囲おかしい問題があった。

下記の分はエラーになり、コメントアウトして対応。

// error(“Height incorrect, please fix Adafruit_SSD1306.h!”);

そして表示範囲おかしい問題は、Adafruit_SSD1306.hを直接修正し、ディフォルトの128×32をコメントアウトし、もう一つの128×64のコメントを外すように変更した。

結果はうまくできた。

Arduino mini-oscilloscope

/*
This is set up to use a 128x64 I2C screen, as available
here: http://www.banggood.com/buy/0-96-oled.html
For wiring details see http://youtu.be/XHDNXXhg3Hg
*/

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);

#if (SSD1306_LCDHEIGHT != 64)
//  error("Height incorrect, please fix Adafruit_SSD1306.h!");
#endif

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

#define CHARWIDTH           5
#define CHARHEIGHT          8
#define AXISWIDTH           (2 + 1)                   // axis will show two-pixel wide graph ticks, then an empty column
#define VISIBLEVALUEPIXELS  (128 - AXISWIDTH)         // the number of samples visible on screen
#define NUMVALUES           (2 * VISIBLEVALUEPIXELS)  // the total number of samples (take twice as many as visible, to help find trigger point

#define TRIGGER_ENABLE_PIN       2  // set this pin high to enable trigger
#define SCREEN_UPDATE_ENABLE_PIN 3  // set this pin high to freeze screen

byte values[NUMVALUES];           // stores read analog values mapped to 0-63
int pos = 0;                      // the next position in the value array to read
int count = 0;                    // the total number of times through the loop
unsigned long readStartTime = 0;  // time when the current sampling started
int sampleRate = 1;              // A value of 1 will sample every time through the loop, 5 will sample every fifth time etc.

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

// Draws a printf style string at the current cursor position
void displayln(const char* format, ...)
{
  char buffer[32];
  
  va_list args;
  va_start(args, format);
  vsprintf(buffer, format, args);
  va_end(args);
  
  int len = strlen(buffer);
  for (uint8_t i = 0; i < len; i++) {
    display.write(buffer[i]);
  }
}

// Draws the graph ticks for the vertical axis
void drawAxis()
{  
  // graph ticks
  for (int x = 0; x < 2; x++) {
    display.drawPixel(x,  0, WHITE);
    display.drawPixel(x, 13, WHITE);
    display.drawPixel(x, 26, WHITE);
    display.drawPixel(x, 38, WHITE);
    display.drawPixel(x, 50, WHITE);
    display.drawPixel(x, 63, WHITE);  
  }
}

// Draws the sampled values
void drawValues()
{
  int start = 0;
  
  if ( digitalRead(TRIGGER_ENABLE_PIN) ) {
    // Find the first occurence of zero
    for (int i = 0; i < NUMVALUES; i++) {
      if ( values[i] == 0 ) {
        // Now find the next value that is not zero
        for (; i < NUMVALUES; i++) {
          if ( values[i] != 0 ) {
            start = i;
            break;
          }
        }
        break;
      }
    }    
    // If the trigger point is not within half of our values, we will 
    // not have enough sample points to show the wave correctly
    if ( start >= VISIBLEVALUEPIXELS )
      return;
  }
  
  for (int i = 0; i < VISIBLEVALUEPIXELS; i++) {
    display.drawPixel(i + AXISWIDTH, 63 - (values[i + start]), WHITE);
  }
}

// Shows the time taken to sample the values shown on screen
void drawFrameTime(unsigned long us)
{
  display.setCursor(9 * CHARWIDTH, 7 * CHARHEIGHT - 2); // almost at bottom, approximately centered
  displayln("%ld us", us);
}

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

void setup() {

  // Set up the display
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // Initialize with the I2C addr 0x3D (for the 128x64)
  display.setTextColor(WHITE);

  pinMode(TRIGGER_ENABLE_PIN, INPUT);
  pinMode(SCREEN_UPDATE_ENABLE_PIN, INPUT);
}

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

void loop() {
  
  // If a sampling run is about to start, record the start time
  if ( pos == 0 )
    readStartTime = micros();
  
  // If this iteration is one we want a sample for, take the sample
  if ( (++count) % sampleRate == 0 )
    values[pos++] = analogRead(0) >> 4; // shifting right by 4 efficiently maps 0-1023 range to 0-63

  // If we have filled the sample buffer, display the results on screen
  if ( pos >= NUMVALUES ) {
    // Measure how long the run took
    unsigned long totalSampleTime = (micros() - readStartTime) / 2;     // Divide by 2 because we are taking twice as many samples as are shown on the screen
 
    if ( !digitalRead(SCREEN_UPDATE_ENABLE_PIN) ) {
      // Display the data on screen   
      display.clearDisplay();
      drawAxis();
      drawValues();
      drawFrameTime(totalSampleTime);
      display.display();
    }
       
    // Reset values for the next sampling run
    pos = 0;
    count = 0;
  }
}

同じプログラムは、Nanoも動いた。

参考

参考にしたビデオ:

Arduino mini-oscilloscope

WeMos (10) Adafruit NeoPixel LED Matrix

Adafruit NeoPixel LED Matrix の互換品が手に入れたので、試します。

二種類のLED Arrayがあり。

  1. 8連装LED Array
  2. 8x8LED Matrix

ライブラリから、Adafruit NeoPixel を追加してください。

Adafruit NeoPixelのスケッチの例から、Sample、Sampletestを実行してください。

スケッチの例には、実際に繋がったGPIOの番号を設定してください。ここではD6に変更する。

Sampleは、単純に指定した数のLEDを点灯する。ここでは数を8(または64)に変更する。

Sampletestは、いろんなパターンで指定した数のLEDを点灯する。ここでは数を8(または64)に変更する。

 

Wemos (d5) Weather Bureau

前回の Weather Stationはおもに気象情報の表示がメイン。

今回のWeather Bureauは、気象情報の収集とクラウンに送信するがメイン。

ソースコードは TinyWebDB-WeatherStation を参考してください。

無人でも長時間自動運用するために、太陽電池で発電、Li-po電池に充電、給電など機能追加された。

問題は、太陽電池の発電は、Weather Bureauの24時間持続運用には足りない。deep sleep機能を利用して、節電する工夫が必要である。

その部分できたらまた共有する。