Category Archives: UbiCare

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/

 

NodeMcu (4) ADS1115 & OLED

経緯

アナログ信号を取り込み、TinyWebDBへ送るプログラムを作る予定。サンプリングレートは秒に100回。
WeMos miniは使いやすいから愛用しているが、2月から、WeMos miniの開発中も頻繁にリブートしています。デバイストライバのバージョンを変えたり、OSを変えたりしても改善しない。結局原因がわからず、仕方なく開発中書き込み直前にUSBケーブル接続、書き込み終わったらすぐUSBケーブ抜く方法で運がよければリブート回避する状態が続て、悩んでいます。
ADS1115プログラムを作るため、安定したNodeMcuできることならこちらで凌ぎ。

ADS1115とは

ADS1115 は、16-Bit ADC – 4 Channel with Programmable Gain Amplifier
特徴:広い電源電圧範囲:2.0V ~ 5.5V。低消費電流: 連続モード:150μA。
_ プログラマブルゲインアンプ内蔵。プログラミング可能なコンパレータ。
_ 4本のシングルエンド入力。2本の差動入力。I2Cインターフェイス。
_ 最小±256mVから電源電圧までの入力範囲に対応。
ライブラリーでは コマンド送信し 8msec 後に データーの読み込みを行う、サンプリングレートは秒に100回するため、Adafruit_ADS1X15/Adafruit_ADS1015.hのADS1115_CONVERSIONDELAYを8から9に変更する。

結線

普通のI2Cでつなぐだけ。

スケッチ

最初のプログラムは、アナログ読む度に表示してるが、表示できるのは秒に十回未満。そしてOLEDには、1秒間読み取れたデータの個数と、最新のアナログ値を表示すると変更して110回程度読み込みできるようになり。
ADS1115_CONVERSIONDELAYを8から9に変更して、表示の通り、秒に101回って、概ね要求に満たした。

#include <Wire.h>
#include <Adafruit_ADS1015.h>               // ADS1015,1115
Adafruit_ADS1115 ads(0x48);                 // 16-bit version
#include <Adafruit_GFX.h>                   // OLED
#include <Adafruit_SSD1306.h>           // OLED
Adafruit_SSD1306 display(0);                // OLED Reset
void setup(void) {
  //Serial.begin(115200);
//  Wire.begin(4,5);                          // OLED:SDA,SCL
  display.begin(SSD1306_SWITCHCAPVCC,0x3c); // I2C ADDRESS=3c
  display.clearDisplay();                   // Clear the buffer
  display.setTextSize(2);                   // font size 4
  display.setTextColor(WHITE);              //
  display.setCursor(0,0);                   //
  ads.setGain(GAIN_TWOTHIRDS);              // 2/3x gain +/-6.144V
  ads.begin();                              // 1 bit=0.1875mV
}
void loop(void) {
  int i=0;
  float v0;
  // // Count and Store data during 1,000 msec
  for(int time = millis(); millis()-time < 1000; i++) {
    v0 = (ads.readADC_SingleEnded(0) * 0.1875/1000); // A0 Read
  }
  display.clearDisplay();
  display.setCursor(0,0);
  display.print(i);
  display.setCursor(0,16);
  display.println(v0,3);
  display.display();
}

 

参考

  1. https://macsbug.wordpress.com/2016/02/04/i2c-adc-ads1115-in-esp8266/

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/

WeMos (b10) ADS1115 Oscilloscope

前回WeMos (b9) ADS1115 for A/Dで数値の表示ができたが、Oscilloscopeのような表示すべく、改造を試み。
しかし、2月から、WeMos miniの開発中も頻繁にリブートしています。デバイストライバのバージョンを変えたり、OSを変えたりしても改善しない。

そのため、このプログラムは未完成のまま放置。

/*
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 <limits.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_ADS1015.h>
#include <math.h>
#define WINDOW_SIZE 128
Adafruit_ADS1115 ads;  /* Use this for the 16-bit version */
//Adafruit_ADS1015 ads;     /* Use thi for the 12-bit version */
#define OLED_RESET 0    // 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       D6  // 2 set this pin high to enable trigger
#define SCREEN_UPDATE_ENABLE_PIN D8  // 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 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
  display.print(us);
  display.println(" us");
}
/********************************************/
void setup() {
  // The ADC input range (or gain) can be changed via the following
  // functions, but be careful never to exceed VDD +0.3V max, or to
  // exceed the upper and lower limits if you adjust the input range!
  // Setting these values incorrectly may destroy your ADC!
  //                                                                ADS1015  ADS1115
  //                                                                -------  -------
     ads.setGain(GAIN_TWOTHIRDS);  // 2/3x gain +/- 6.144V  1 bit = 3mV      0.1875mV (default)
  // ads.setGain(GAIN_ONE);        // 1x gain   +/- 4.096V  1 bit = 2mV      0.125mV
  // ads.setGain(GAIN_TWO);        // 2x gain   +/- 2.048V  1 bit = 1mV      0.0625mV
  // ads.setGain(GAIN_FOUR);       // 4x gain   +/- 1.024V  1 bit = 0.5mV    0.03125mV
  // ads.setGain(GAIN_EIGHT);      // 8x gain   +/- 0.512V  1 bit = 0.25mV   0.015625mV
  // ads.setGain(GAIN_SIXTEEN);    // 16x gain  +/- 0.256V  1 bit = 0.125mV  0.0078125mV
  ads.begin();
  // 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++] = (ads.readADC_SingleEnded(0)>> 7) / 3; // shifting right by 4 efficiently maps 0-1023 range to 0-63
//    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;
  }
}

 

WeMos (b9) ADS1115 for A/D

ADS1115とは

ADS1115 とは4チャンネル16bit  A/D 。I2C接続なので、OLEDと共に、WeMos に接続して利用してみる。

結線

SCL, SDA自由に変更可能。U8g2初期化コマンドでSetupする。

code

#include <Wire.h>
#include <Adafruit_ADS1015.h>
#include <U8g2lib.h>
#include <math.h>
#define WINDOW_SIZE 128
Adafruit_ADS1115 ads;  /* Use this for the 16-bit version */
//Adafruit_ADS1015 ads;     /* Use thi for the 12-bit version */
// Sets up the display to be the 128px x 32px display
U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE, /* clock=*/ SCL, /* data=*/ SDA);
void setup(void)
{
  Serial.begin(9600);
  Serial.println("Hello!");
  Serial.println("Getting differential reading from AIN0 (P) and AIN1 (N)");
  Serial.println("ADC Range: +/- 6.144V (1 bit = 3mV/ADS1015, 0.1875mV/ADS1115)");
  // The ADC input range (or gain) can be changed via the following
  // functions, but be careful never to exceed VDD +0.3V max, or to
  // exceed the upper and lower limits if you adjust the input range!
  // Setting these values incorrectly may destroy your ADC!
  //                                                                ADS1015  ADS1115
  //                                                                -------  -------
  ads.setGain(GAIN_TWOTHIRDS);  // 2/3x gain +/- 6.144V  1 bit = 3mV      0.1875mV (default)
  // ads.setGain(GAIN_ONE);        // 1x gain   +/- 4.096V  1 bit = 2mV      0.125mV
  // ads.setGain(GAIN_TWO);        // 2x gain   +/- 2.048V  1 bit = 1mV      0.0625mV
  // ads.setGain(GAIN_FOUR);       // 4x gain   +/- 1.024V  1 bit = 0.5mV    0.03125mV
  // ads.setGain(GAIN_EIGHT);      // 8x gain   +/- 0.512V  1 bit = 0.25mV   0.015625mV
  // ads.setGain(GAIN_SIXTEEN);    // 16x gain  +/- 0.256V  1 bit = 0.125mV  0.0078125mV
  // Initialize the display
  u8g2.begin();
  ads.begin();
}
// Function to print ${value} with a specific number of ${digits}
void print_digits(double value, short unsigned digits){
  double av = abs(value);
  value = av;
  while(av > 10){
    digits--;
    av/=10;
  }
  u8g2.print(value, digits - 1);
}
int16_t results[WINDOW_SIZE] = {0};
int current_result = 0;
void loop(void)
{
 int time = millis();
  /* Be sure to update this value based on the IC and the gain settings! */
  //float   multiplier = 3.0F;    /* ADS1015 @ +/- 6.144V gain (12-bit results) */
  float multiplier = 0.1875F; /* ADS1115  @ +/- 6.144V gain (16-bit results) */
  double voltage_multiplier = 5333;
  for (int i = 0; i < 16; i++){
    results[current_result] = ads.readADC_Differential_0_1();
    current_result++;
    current_result = current_result % WINDOW_SIZE;
  }
  double result = 0;
  int i;
  for (i = 0; i < WINDOW_SIZE; i++){
    result = result + results[i];
  }
  result = result / (double) WINDOW_SIZE;
  /*Serial.print("Differential: "); Serial.print(results); */
   //Serial.print("(");
   Serial.println(result * multiplier, 5);
   //Serial.println("mV)");
  u8g2.firstPage();
  do {
    // this is where the values get printed to the display
    //u8g2.setFont(u8g2_font_logisoso32_tr); // large 32px tall font
    // other font options can be found at https://github.com/olikraus/u8g2/wiki/fntlistall
    u8g2.setFont(u8g2_font_6x12_tn);
    if (result > 0){
      u8g2.setCursor(0,16);
      u8g2.print("+");
    } else {
      u8g2.setCursor(0,26);
      u8g2.print("-");
    }
    u8g2.setFont(u8g2_font_fur20_tr); // large 20px tall font
    u8g2.setCursor(7,26 );
    double volts = result / voltage_multiplier;
    print_digits(volts, 5);
    u8g2.print("V");
  } while ( u8g2.nextPage() );
  int d = (1000 / 16) - (millis() - time);
  if (d > 0){
    delay(d);
  }
}

 

動作確認

しかし、テスト結果は、思う通りにならない。
表示は0.0000V、1.0000V、ー1.0000V、の感じで、小数点以下は0000となっている。どうして?
大変の曲がり道して、わかったのは、OLEDの定義が間違え、「U8G2_SH1106_128X64_NONAME_F_HW_I2C」になって、その影響で、読み取り数字が変に。
 

「U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C」で定義を直したら、普通にA/D変換の結果が表示が出来た。

参考