adafruit / Adafruit-MLX90614-Library

Arduino library for the MLX90614 sensors in the Adafruit shop
Other
128 stars 97 forks source link

thermopile sensor MLX90614 Using different IO-pins as the standard I2C-IO-pins #42

Closed StefanL38 closed 1 year ago

StefanL38 commented 1 year ago

In lack of a tab like "tips & trick" I post this as an issue. And somehow it could be seen as an "issue" to improve the examples Additionally haven't found an easy to understand tutorial how to do a "pull-request" Easy to understand for me means a tutorial with a screen-shot for every mouse-click. Not less !

So all you GitHubby-nerds deal with this "nerdy" issue.

On most modern microcontrollers like ESP32 etc. you can choose which IO-pins are connected to the microcontroller-internal I2C-hardware. So I did some research and asked in the arduino-forum to learn how this can be done. Here is a demo-code

// demo-code for the thermopile contactless temperature-sensor
// MLX90614 tested on a ESP32 esp32-coreversion 2.0.9
// Adafruit_MLX90614_Library@2.1.3

#include <Wire.h>
#include <Adafruit_MLX90614.h>

Adafruit_MLX90614 mlx = Adafruit_MLX90614();

unsigned long MyTestTimer = 0; // Timer-variables MUST be of type unsigned long
const byte    OnBoard_LED = 2;

// on ESP32 you can define the I2C-Pins yourself
#define I2C_SCL 18
#define I2C_SDA 19

#define MLX90614_I2C_ADRR 0x5a

void setup() {
  Serial.begin(115200);
  while (!Serial);
  Serial.println("Setup-Start");
  PrintFileNameDateTime();

  // call Wire.begin with I2C pin-numbers as parameters
  Wire.begin(I2C_SDA, I2C_SCL);

  // call mlx.begin with I2C-adress and pointer to Wire as parameters)
  // pointer to Wire means prefix "&"  &Wire
  if (  !mlx.begin(MLX90614_I2C_ADRR, &Wire) ) {
    Serial.println("Error connecting to MLX sensor. Check wiring.");
    Serial.println("microcontroller freezed with while(true)");
    while (true);
  };
}

void loop() {
  // non-blocking blinking of LED
  BlinkHeartBeatLED(OnBoard_LED, 250);

  // non-blocking delayed code-execution
  // check if more than 1002 milliseconds have passed by
  // since last intervall
  if ( TimePeriodIsOver(MyTestTimer, 1002) ) {
    // if 1002 REALLY have passed by
    Serial.print("Emissivity of MLX90614-Sensor = ");
    Serial.println(mlx.readEmissivity());

    Serial.print("Ambient = ");
    Serial.print(mlx.readAmbientTempC());
    Serial.print("°C\tObject = ");
    Serial.print(mlx.readObjectTempC());
    Serial.println("°C");
    Serial.print("Ambient = ");
    Serial.print(mlx.readAmbientTempF());
    Serial.print("°F\tObject = ");
    Serial.print(mlx.readObjectTempF());
    Serial.println("°F");

    Serial.println();
  }
}

void PrintFileNameDateTime() {
  Serial.println( F("Code running comes from file ") );
  Serial.println( F(__FILE__) );
  Serial.print( F("  compiled ") );
  Serial.print( F(__DATE__) );
  Serial.print( F(" ") );
  Serial.println( F(__TIME__) );
}

// easy to use helper-function for non-blocking timing
boolean TimePeriodIsOver (unsigned long &startOfPeriod, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();
  if ( currentMillis - startOfPeriod >= TimePeriod ) {
    // more time than TimePeriod has elapsed since last time if-condition was true
    startOfPeriod = currentMillis; // a new period starts right here so set new starttime
    return true;
  }
  else return false;            // actual TimePeriod is NOT yet over
}

void BlinkHeartBeatLED(int IO_Pin, int BlinkPeriod) {
  static unsigned long MyBlinkTimer;
  pinMode(IO_Pin, OUTPUT);

  if ( TimePeriodIsOver(MyBlinkTimer, BlinkPeriod) ) {
    digitalWrite(IO_Pin, !digitalRead(IO_Pin) );
  }
}

So @GiPo-maintainer at Adafruit add my example to your official example folder

Serial output looks like this

23:10:28.243 -> Setup-Start
23:10:28.243 -> Code running comes from file 
23:10:28.243 -> F:\myData\Arduino\Adafruit_MLX90614-GY-906-Thermopile-temperatur-sensor-Demo-Code\Adafruit_MLX90614-GY-906-Thermopile-temperatur-sensor-Demo-Code.ino
23:10:28.276 ->   compiled Aug 18 2023 23:06:54
23:10:29.216 -> Emissivity of MLX90614-Sensor = 1.00
23:10:29.216 -> Ambient = 26.57°C   Object = 26.23°C
23:10:29.216 -> Ambient = 79.83°F   Object = 79.21°F
23:10:29.216 -> 
23:10:30.228 -> Emissivity of MLX90614-Sensor = 1.00
23:10:30.228 -> Ambient = 26.55°C   Object = 26.11°C
23:10:30.228 -> Ambient = 79.79°F   Object = 79.00°F
23:10:30.228 -> 
23:10:31.209 -> Emissivity of MLX90614-Sensor = 1.00
23:10:31.209 -> Ambient = 26.57°C   Object = 26.17°C
23:10:31.209 -> Ambient = 79.83°F   Object = 79.11°F

best regards Stefan

caternuson commented 1 year ago

Please use setPins() instead. More info: https://github.com/espressif/arduino-esp32/issues/3779

StefanL38 commented 1 year ago

OK modified the code to use the setPins()-function to keep the standard mlx.begin()

// demo-code for the thermopile contactless temperature-sensor
// MLX90614 tested on a ESP32 esp32-coreversion 2.0.9
// Adafruit_MLX90614_Library@2.1.3

#include <Wire.h>
#include <Adafruit_MLX90614.h>

Adafruit_MLX90614 mlx = Adafruit_MLX90614();

unsigned long MyTestTimer = 0; // Timer-variables MUST be of type unsigned long
const byte    OnBoard_LED = 2;

// on ESP32 you can define the I2C-Pins yourself
#define I2C_SCL 18
#define I2C_SDA 19

void setup() {
  Serial.begin(115200);
  while (!Serial);
  Serial.println("Setup-Start");
  PrintFileNameDateTime();

  // call Wire.setPins with I2C pin-numbers as parameters
  Wire.setPins(I2C_SDA, I2C_SCL);

  if ( !mlx.begin() ) {
    Serial.println("Error connecting to MLX sensor. Check wiring.");
    Serial.println("microcontroller freezed with while(true)");
    while (true);
  };
}

void loop() {
  // non-blocking blinking of LED
  BlinkHeartBeatLED(OnBoard_LED, 250);

  // non-blocking delayed code-execution
  // check if more than 1002 milliseconds have passed by
  // since last intervall
  if ( TimePeriodIsOver(MyTestTimer, 1002) ) {
    // if 1002 REALLY have passed by
    Serial.print("Emissivity of MLX90614-Sensor = ");
    Serial.println(mlx.readEmissivity());

    Serial.print("Ambient = ");
    Serial.print(mlx.readAmbientTempC());
    Serial.print("°C\tObject = ");
    Serial.print(mlx.readObjectTempC());
    Serial.println("°C");
    Serial.print("Ambient = ");
    Serial.print(mlx.readAmbientTempF());
    Serial.print("°F\tObject = ");
    Serial.print(mlx.readObjectTempF());
    Serial.println("°F");

    Serial.println();
  }
}

void PrintFileNameDateTime() {
  Serial.println( F("Code running comes from file ") );
  Serial.println( F(__FILE__) );
  Serial.print( F("  compiled ") );
  Serial.print( F(__DATE__) );
  Serial.print( F(" ") );
  Serial.println( F(__TIME__) );
}

// easy to use helper-function for non-blocking timing
boolean TimePeriodIsOver (unsigned long &startOfPeriod, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();
  if ( currentMillis - startOfPeriod >= TimePeriod ) {
    // more time than TimePeriod has elapsed since last time if-condition was true
    startOfPeriod = currentMillis; // a new period starts right here so set new starttime
    return true;
  }
  else return false;            // actual TimePeriod is NOT yet over
}

void BlinkHeartBeatLED(int IO_Pin, int BlinkPeriod) {
  static unsigned long MyBlinkTimer;
  pinMode(IO_Pin, OUTPUT);

  if ( TimePeriodIsOver(MyBlinkTimer, BlinkPeriod) ) {
    digitalWrite(IO_Pin, !digitalRead(IO_Pin) );
  }
}