So-net無料ブログ作成
検索選択

ESP-WROOM-02で心拍センサーを動かしてみた [Arduino]

ESP-WROOM-02で心拍センサーを動かしてみました。


DSC04081.JPG


ESP-WROOM-02のADCは0Vから1Vの範囲しか測定できないので、3.3Vの心拍センサーの出力をだいたい1/3に分圧して入力しています。


ESP-WROOM-02 with PulseSensor.png


スケッチを設計するポイントは、

・ シグナル値の読み込みに analobRead() 関数ではなく sysytem_adc_read() 関数を使用
・ 割り込みの設定に、timer0_isr_init()、timer0_attachInterrupt()、timer0_write() 関数を使用
・ 時間取得に、ESP.getCycleCount() 関数を使用

の3点です。


extern "C" {
  #include "user_interface.h"
}

#define N 10

volatile int BPM;
volatile int Signal;
volatile int IBI = 600;
volatile boolean Pulse = false;
volatile boolean QS = false;

volatile int Rate[N];
volatile unsigned long CurrBeatTime = 0;
volatile unsigned long LastBeatTime = 0;
volatile int P = 500;
volatile int T = 500;
volatile int Threshold = 512;
volatile int Amplifier = 100;

int PulseSensorPin = 17;
int FadePin = 4;
int FadeRate = 0;

void timer0_ISR (void) {
  noInterrupts();
  Signal = system_adc_read();
  CurrBeatTime = getCurrentTime(); // msec
  unsigned long interval = CurrBeatTime - LastBeatTime;
  
  // hold bottom
  if ((Signal < Threshold) && (interval > (IBI*3) / 5)) {
    if (Signal < T) {
      T = Signal;
    }
  }
   
  // hold peak
  if (Signal > Threshold && Signal > P) {
    P = Signal;
  }
  
  if (interval > 250 /* ms */) {
    
    // check if Signal is over Threshold
    if ((Signal > Threshold) && !Pulse && (interval > (IBI*3) / 5)) {
      Pulse = true;
      IBI = interval;
      
      if (Rate[0] < 0) { // first time
        Rate[0] = 0;
        LastBeatTime = getCurrentTime();
        setupTimer(10);
        noInterrupts();
        return;
      } else if (Rate[0] == 0) {  // second time
        for (int i = 0; i < N; ++i) {
          Rate[i] = IBI;
        }
      }
      
      word running_total = 0;     
      for (int i = 0; i < N-1; ++i) {
        Rate[i] = Rate[i+1];
        running_total += Rate[i];
      }
      
      Rate[N-1] = IBI;
      running_total += IBI;
      running_total /= N;
      BPM = 60000 / running_total;
      QS = true;
      LastBeatTime = getCurrentTime();
    }
  }
  
  // check if Signal is under Threshold
  if ((Signal < Threshold) && Pulse) {
    Pulse = false;
    Amplifier = P - T;
    Threshold = Amplifier / 2 + T; // revise Threshold
    P = Threshold;
    T = Threshold;
  }
  
  // check if no Signal is over 2.5 sec
  if (interval > 2500 /* ms */) {
    Threshold = 512;
    P = 500;
    T = 500;
    LastBeatTime = getCurrentTime();
    for (int i = 0; i < N; ++i) {
      Rate[i] = -1;
    }
  }
  setupTimer(10);
  interrupts();
}

void setupTimer(int m /* msec */) {
  timer0_isr_init();
  timer0_attachInterrupt(timer0_ISR);
  timer0_write(ESP.getCycleCount() + 80000L * m); // 80MHz/1000 == 1msec
}

unsigned long getCurrentTime() {
  return ESP.getCycleCount() / 80000L;
}

void setup() {
  pinMode(FadePin, OUTPUT);
  analogWriteRange(255);
  Serial.begin(115200); 
  noInterrupts();
  setupTimer(10);
  interrupts();
  LastBeatTime = getCurrentTime(); // msec
}

void loop() {
  if (QS) {
    FadeRate = 255; 
    Serial.print("BPM: ");
    Serial.println(BPM);
    QS = false;
  }
  
  FadeRate -= 15;
  FadeRate = constrain(FadeRate, 0, 255);
  analogWrite(FadePin, FadeRate);
  delay(20);
}


さて、きちんと動くかなー?



システムから時間をとっているせいか、Arduno Pro Mini で使ったアルゴリズムよりも精度よく測定しているような気がします。次はいよいよバッテリー駆動にチャレンジかなぁ。
σ(^_^)





ESP-WROOM-02ピッチ変換済みモジュール《フル版》

ESP-WROOM-02ピッチ変換済みモジュール《フル版》

  • 出版社/メーカー: スイッチサイエンス
  • メディア: エレクトロニクス



心拍センサ

心拍センサ

  • 出版社/メーカー: スイッチサイエンス
  • メディア: エレクトロニクス