3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

M5SticC と MLX90614/MLX90615 で非接触温度計を作った

Last updated at Posted at 2021-01-10

コロナ禍で非接触体温計があちこちで見かけることもあり、遅ればせながら、M5StickCを使って非接触温度計を作ろうと思った。(体温計にはならないが額の表面温度はわかる)

NCIR Hat が無い

手っ取り早いのが、NCIR HAT (MLX90614)を購入すれば良いのだが、国内の販売代理店はもとより、本家 M5Stick ショップにも在庫が無い状態だった。(以下のサイトのとおり)
https://m5stack.com/collections/m5-hat

センサーの手持ちが有った

手持ちの部品を調べたら、GY-906 というのが2つ出てきた。以前、Arduino nano互換機で使っていたもので、調べてみると MLX90614 と同じようで、5vだけでなく、3.3v でも動作するようだった。これは使える!
(1月17日追記)MLX90165も有ったので、そちらでも使えるようにしたいと思った。

配線の情報とサンプルプログラムを見つける

本家のサイトに詳しく載っていた。
https://docs.m5stack.com/#/en/hat/hat-ncir

配線情報

HHAT 用の8ピンと、センサーの接続は次のとおり
M5StickC ---> MLX90614

  • GND ---> GND
  • 3V3 ---> VIN
  • G0 ---> SDA
  • G26 ---> SCL

サンプルプログラム

 https://github.com/m5stack/M5StickC/tree/master/examples/Hat/NCIR_HAT
から、NCIR_HAT.ino を Arduino IDE のスケッチにコピペするだけと簡単!

動かない!

なんと、コピペしただけのスケッチでは M5StickC の画面に何も表示されないのだった!
原因は7行目の Serial.begin(115200); のようで、この行を削除したら動作した。
動作はしたものの、表示される温度は1つだけ。(対象物の温度のようだ)

環境温度と対象物の温度を出すには

MLX90614 のデータシート
https://m5stack.oss-cn-shenzhen.aliyuncs.com/resource/docs/datasheet/hat/MLX90614-Datasheet-Melexis_en.pdf
を見てみると、17ページの「8.3.4 RAM」の表に

  • TA: 0x06
  • TOBJ1: 0x07

とある。(TOBJ2 って何だろう?)
やはりサンプルは 0x07 を読んでいるので、対象物の温度を読み出していたことがわかる。
その部分を改造して両方を読み出すようにすれば良いというわけだ。
(後で知ったが、Adafruit_MLX90614.h ライブラリーを使うと、もっと簡単に「readAmbientTempC()」で呼び出せる) --> 参考にしたサイトを参照

動作の様子

冷めたコーヒーカップ(笑)の温度
ジャンパーピンに直接半田付けがみっともないのですが...
IMG_6194X.JPG

HATも自作

本家の Proto HAT の基盤を使って自前のHAT(勝手HATともいうらしい)も作った。
筐体は Fusion360 でモデリングして 3Dプリントした。
IMG_6214.JPG

出来上がったソース

ファイル名が「Temp.cpp」となっていますが、cpp としているのは文脈をカラーで表示させたいためで、実際には「好きな名前.ino」としてください。スケッチにソースをコピペするのでファイル名は関係ないか(笑)
(1月17日追記)小数点以下が常に0で表示されるバグも見つかり、ついでに MLX90164 と MLX90165 のどちらを繋いでも起動時に識別して動作するように改良しました。

Temp.cpp
/*    No contact IR temperature measurements.
      used to measure the surface temperature of a human body or other object.
      For MLX90615 or MLX90614(Infra Red thermometer)
*/
      
# include <M5StickC.h>

// =================== for MIX90614
# define I2C_Addr_90614 0x5A                 // MIX90614 I2C Addr = 0x5A
# define AMBIENT_90614  0x06;                 // Select data for MLX90614 to Ambient Temp.
# define OBJECT_90614   0x07;                 // Select data for MLX90614 to Object Temp.

// ===================  for MIX90615
# define I2C_Addr_90615 0x5B;                 // MIX90615 I2C Addr = 0x5B
# define AMBIENT_90615  0x26;                 // Select data for MLX90615 to Ambient Temp.
# define OBJECT_90615   0x27;                 // Select data for MLX90615 to Object Temp.

// ================= set default senser to 90614

uint8_t Addr = I2C_Addr_90614;
uint8_t Amb = AMBIENT_90614;
uint8_t Obj = OBJECT_90614;

float maxtemp=0.0;
float mintemp=100.0;
float hold=0.0;
float TempO=0.0;
float TempA=0.0;

void setup() {
  M5.begin();
  Wire.begin(0,26);                    // I2C begin,  SDA: Pin0,  SCL: Pin26
  M5.Lcd.setRotation(0);
  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.setCursor(0,0);
  M5.Lcd.setTextSize(2);

//------------- Sensor detection
  Addr = I2C_Addr_90614;
  Amb = AMBIENT_90614;
  Obj = OBJECT_90614;
  if(I2CreadTest()) {
    M5.Lcd.printf("MIX\n\n 90614\n\n Sensor");
  } else {
    Addr = I2C_Addr_90615;
    Amb = AMBIENT_90615;
    Obj = OBJECT_90615;
    if(I2CreadTest()) {
      M5.Lcd.printf("MIX\n 90615\n\n Sensor\n\n");
    } else {
      M5.Lcd.setTextSize(4);
      M5.Lcd.setTextColor(RED);
      M5.Lcd.printf("NO SENSOR!\n");
    }
  } 
  delay(1000);
}

bool I2CreadTest() {             // I2C read test function for Sensor detection
  Wire.beginTransmission(Addr);                         // Send Initial Signal and I2C Bus Address
  Wire.write(Amb);                                      // set target to Ambient or Object
  Wire.endTransmission(false);                          // Stop signal
  size_t ReturnSize = Wire.requestFrom(Addr, 3);        // read 3 consecutive data from I2C
  if(ReturnSize > 0) {
    for(int i = ReturnSize; i <= 0; i--) Wire.read();
    return true;
  }
  return false;
}


 float ReadTemp(uint8_t Target) {      // read Temp Function
  uint16_t temp;
  Wire.beginTransmission(Addr);          // Send Initial Signal and I2C Bus Address
  Wire.write(Target);                    // set target to Ambient or Object
  Wire.endTransmission(false);           // Stop signal
  Wire.requestFrom(Addr, 3);             // read 3 consecutive data from I2C
  temp = Wire.read();                    // read data (low 8 bit)
  temp |= Wire.read() << 8;              // read data (high 8 bit)
  Wire.read();                           // read and discard PEC (packet error code)
  return temp * 0.02 - 273.15;           // convet temperature to degree Celsius
}


void loop() {
  for(int i = 0; i <= 100; i++) {
    M5.update();
    if ( M5.BtnA.wasPressed() ) {
      hold = ReadTemp(Obj);
    }
    if ( M5.BtnB.wasPressed() ) {
      esp_restart();
    }
    if (i >= 100) {                        // Read temp and display interval (1 second.)
      TempA = ReadTemp(Amb);
      TempO = ReadTemp(Obj); 
      if (mintemp>TempO) mintemp = TempO;
      if (maxtemp<TempO) maxtemp = TempO;
      M5.Lcd.fillScreen(BLACK);
      M5.Lcd.setCursor(0,0);
      M5.Lcd.setTextSize(1);M5.Lcd.setTextColor(GREEN); 
      M5.Lcd.printf("Ambient temp\n");
      M5.Lcd.setTextSize(3);M5.Lcd.setTextColor(WHITE);   
      M5.Lcd.printf("%3.1f\n",TempA);
      M5.Lcd.setTextSize(1);M5.Lcd.setTextColor(GREEN); 
      M5.Lcd.printf("\Object  temp\n");
      M5.Lcd.setTextSize(3);M5.Lcd.setTextColor(WHITE);   
      M5.Lcd.printf("%3.1f\n",TempO);
      M5.Lcd.setTextSize(1);M5.Lcd.setTextColor(CYAN);  
      M5.Lcd.printf("\nBtnB=Restart\n");
      M5.Lcd.setTextColor(GREEN); 
      M5.Lcd.printf("Battery:%3.1fV\n", M5.Axp.GetBatVoltage());
      M5.Lcd.setTextSize(1);M5.Lcd.setTextColor(GREEN);  
      M5.Lcd.printf("\n min   max\n"); 
      M5.Lcd.setTextSize(1);M5.Lcd.setTextColor(WHITE);   
      M5.Lcd.printf(" %3.1f  %3.1f\n",mintemp,maxtemp);
      M5.Lcd.setTextSize(1);M5.Lcd.setTextColor(CYAN);   
      M5.Lcd.printf("\nBtnA = hold\n");
      M5.Lcd.setTextSize(3);M5.Lcd.setTextColor(WHITE);     
      M5.Lcd.printf("%3.1f\n",hold);
    }
  delay(10);
  }
}

M5StickCライブラリーのみを使用してできたソースです。
(M5StickC Plusでもライブラリーを M5StidkC_Plusに変えるだけで使えるはず)

上記以外に参考にしたサイト

(1)画面表示のレイアウトを参考にさせていただいた
「M5StickC MLX90615 赤外線温度センサー で 非接触温度計 を作ってみました。」
 http://gijin77.blog.jp/archives/23823203.html

(2)Adafruit_MLX90614.h ライブラリーの情報が参考になります
「M5StickCにNCIR(MLX90614)をつなぐ(2)」
 https://edycube.blog.fc2.com/blog-entry-1106.html

あとがき

配線とセンサーが剥き出しで格好悪いので、後で HAT風のケースを 3D プリンターで作るつもり。

追記

2020/1/11 ソースを修正:MLX90614 だけでなく MLX90165 にも対応できるよう修正した。(コードの一部をコメントで修正)

2020/1/17 ソースを修正
・起動時に MLX90164/MLX90615 のどちらのセンサーが接続されているかを判断して動作する。
・小数点以下が常にゼロで表示されるバグの対策

2020/1/17(その2) ソースを修正
・センサーの判別部分を改良

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?