Question regarding ssd1306 and sensor details (using u8g2)

Ah, okay, now i see. Yeah, i couldnt find any reference documentation for the sensor library whatsoever, only an Adafruit example program that prints to serial. I took that same structure and just replaced the print to serial with a print to u8g2 thinking that would work the same way. But Ill go back and review the MLX source/header files though, and figure out what data type that value returns, then modify accordingly (and try making changes when initializing a static, as you said). Thanks!

Okay, sorry i hadnt already done that much, ive just tried making sense of other header files before and it was just beyond me as far as what i was looking at/for, but looking at that seems fairly obvious in retrospect, so ill be sure to always keep that in mind. Thanks!

So, that being said, I looked in the header file and the classes are here:

class Adafruit_MLX90614  {
 public:
  Adafruit_MLX90614(uint8_t addr = MLX90614_I2CADDR);
  boolean begin();
  uint32_t readID(void);

  double readObjectTempC(void);
  double readAmbientTempC(void);
  double readObjectTempF(void);
  double readAmbientTempF(void);

 private:
  float readTemp(uint8_t reg);

  uint8_t _addr;
  uint16_t read16(uint8_t addr);
  void write16(uint8_t addr, uint16_t data);
};

And as far as ive read into data types, a double specifically refers to a float, if im not mistaken? Does this mean I should just change the data types to doubles and initialize oldObjectC and oldAmbientC with higher values? Also, depending on the consistency of the readings, should i initialize them at the beginning of the loop, rather than before it? Just because from what ive read it typically doesnt seem to make a difference, Id just like to ensure it runs each time through in case the previous values equal the current values after running through once, i wouldnt know if that could make it lock up.

Also, just for some additional info, I looked into the CPP file as well and found more pertaining to the objects being used, though the CPP file isnt referenced in either the header file or program ive been basing this off of, so i am not sure if it is even relevant.

Again, im not sure if this info is even relevant, but to me it looked like it was using the private float to calculate the doubles, if im not mistaken. So heres that:

double Adafruit_MLX90614::readObjectTempF(void) {
  return (readTemp(MLX90614_TOBJ1) * 9 / 5) + 32;
}


double Adafruit_MLX90614::readAmbientTempF(void) {
  return (readTemp(MLX90614_TA) * 9 / 5) + 32;
}

double Adafruit_MLX90614::readObjectTempC(void) {
  return readTemp(MLX90614_TOBJ1);
}


double Adafruit_MLX90614::readAmbientTempC(void) {
  return readTemp(MLX90614_TA);
}

float Adafruit_MLX90614::readTemp(uint8_t reg) {
  float temp;
  
  temp = read16(reg);
  temp *= .02;
  temp  -= 273.15;
  return temp;
}

There appear to be bool begin() and uint32_t readID()
I would assume that these are sanity checks for your hardware.

If a library function or class method returns a value USE it.

I suggest that you report these values to Serial.
Then report the values from mlx.readObjectTempC() to Serial.

Quite honestly there is nothing complicated about reading a Sensor and displaying its value.
Whether to Serial, LCD, OLED, TFT, ...

In real life a human would locate the thermometer, check that it is working properly, then record the temperature in a paper notebook at regular intervals.

David.

I know there’s really nothing difficult to it, this is just my second project, and with my level of inexperience I can’t see the forest for the trees, so to speak. The program I’m basing this off of simply prints the values directly to serial, which is why I was mistaken in thinking I could do it the same way. Here is the example program:

/*************************************************** 
  This is a library example for the MLX90614 Temp Sensor

  Designed specifically to work with the MLX90614 sensors in the
  adafruit shop
  ----> https://www.adafruit.com/products/1748
  ----> https://www.adafruit.com/products/1749

  These sensors use I2C to communicate, 2 pins are required to  
  interface
  Adafruit invests time and resources providing this open source code, 
  please support Adafruit and open-source hardware by purchasing 
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.  
  BSD license, all text above must be included in any redistribution
 ****************************************************/

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

Adafruit_MLX90614 mlx = Adafruit_MLX90614();

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

  Serial.println("Adafruit MLX90614 test");  

  mlx.begin();  
}

void loop() {
  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();
  delay(500);
}

Im just trying to replace the delay, as well as add one for the clearBuffer and sendBuffer. So do you mean rather than try to time both, just time both at once?

And now im just entirely confused, as Im not sure how you mean to use the bool begin() or uint32_t readID() because theres nothing else in the header or CPP file with that for me to know what its for or how its used. Sorry for such a headache for something so simple, i just have a lot to grasp on the learning curve.

EDIT: sorry, also just saw you said to print the bool and uint32_t values to serial as well, so I’ll go ahead and do that now

The first thing with any library is to try ALL the examples. Some might need extra hardware but at least you see how the library is used.

I am horrified by an example that does not use the result from mlx.begin().
You just have read the return value and report to Serial.

I2C devices always need return values. Otherwise you don't know whether the device is connected or not. It could have the wrong Slave address or broken wire.

So does your posted library example work?

David.

Yeah, the first thing I did was make sure i got the sensor work using the example program. Unfortunately, thats also the only example program. Im still not sure I understand how to use the boolean begin() or uint32_t readID, though. Im also not sure how to print the values to the serial window, or if I would need to return the value in one step and print that value in another. Sorry for raising even more questions.

Go on. Does the example program in #24 show sensible temperature values on the Serial Terminal?

If it does, the Sensor must be connected correctly. So it would work with the OLED too. Providing you have not disturbed the wiring.

Regarding report of begin() etc

Serial.println(mlx.begin());
Serial.println(mlx.readID(), HEX);

David.

Yeah, the temperature it returns is sensible. As for the i2c, the first line of the header file is

#define MLX90614_I2CADDR 0x5A

and on adafruits website it has a list of i2c addresses with the MLX sensor under 0x5A as well.

The back of the screen says it has selectable i2c addresses depending on the resistor bridge soldered, and above the one selected it says 07x8.

Sorry i dont even know the answer to this simple question, but should i copy and paste the code you just gave me into the loop, or setup? I tried both and it returned an error.

And just for the sake of simplifying things, earlier i even tried to just tweak the example program using u8g2 in place of all Serial commands, sandwiching that inside the clear and send buffer, and leaving the delay alone, but it gave me the same results with the wildly high, unchanging numbers (and just to specify, these numbers are the same every time this happens).

Hmm, so I had a friend give this another look over, and he said a possible issue may be the two i2c devices (because I am using an Uno r3 and he said the 328 only supports one serial channel). Since I have the r3, there are additional pinouts specifically for SDA and SCL, so I have one device connected to those and the other device connected to A4 and A5. From what ive read, multiple i2c devices can work on the same bus, so long as the addresses are different. Although the devices have different addresses as well, could this be a problem?

If this is the case I can move my questions to a more appropriate forum, and/or do more of my own homework on that first.

Please post the complete program i.e. your current version.

Quite honestly, your sensors should return the correct temperature values. If they work with the library example they should work with your OLED.

You can have many devices on the I2C bus. You should always have external pullup resistors. They are often mounted on breakout boards.
Yes, it s convenient to wire one device to A4, A5 and the other to SDA, SCL pins beause A4, A5 are I2C on a Uno. You can find VCC, GND on the power header and also on the 3x2 ISP header.

But most importantly, if you have multiple I2C devices they must all use the same driver e.g. hardware I2C. Your software I2C constructor will not work if you have other devices uusing Wire.h library.

David.

Ahh, I'm an idiot- I didn't know i2c required external pull up resistors, but after a quick Google search I certainly understand why. Having not used them I would think that would be the problem. I'll go ahead and get those set up as they should be and try again, then post my code saying if it worked or not.

Also, I remember earlier in the thread, olikraus said "For proper cooperation between multiple I2C devices on the same bus, you MUST use the HW I2C constructor."

So I already changed that. Will just do some more leg work and update. Sorry for the headache, thanks!

Hmm, alright... So I've wired up what I believe to be correct, and reuploaded two different programs, with the same results. I'll post both programs once I'm more confident my wiring is correct.

As for the pull up resistors, im using one 2.2k resistor tied into each sda and scl line (4 resistors total), going to each devices respective voltage supply (3.3 and 5v). I also have 2k and 1k, but I read the suggested range for most i2c devices (3.3 or 5v) is 1.8-2.7k, some saying as high as 4.7. I wasn't sure what would be best for either device though, as I don't have an oscilloscope to check the frequencies and try to calculate it myself (so I'm assuming it's 100khz, as seems to be the standard). Does this seem correct?

And the last thing I need to try (before im sure I have the wiring correct) is to get a power supply on my breadboard, just in case the USB power alone isn't enough to supply the correct voltage (as I also don't have multimeter to check).

For the I2C bus you need only two resistors: One for SDA and one for SCK. One end of the resistor goes to the corresponding GPIO pin (SDA and SCK), the other end goes to the power supply. Which power supply this will be, depends on the desired I2C bus voltage. The I2C bus voltage in turn depends on the connected devices.

Let me use the IR sensor. The Adafruit web page from here Melexis Contact-less Infrared Sensor - MLX90614 5V [MLX90614ESF-AAA] : ID 1748 : $15.95 : Adafruit Industries, Unique & fun DIY electronics and kits says:

This sensor comes in an easy-to-use metal can. You can easily solder it or plug it into a breadboard. The four pins are used for power, ground, i2c clock and i2c data. There are two versions, one for 3V power and logic levels and one for 5V power and logic levels. This item is the 5V version! - good for use by classic Arduinos. You'll also want two 10K pull-up resistors for the I2C data lines, which we thoughtfully include.

Keywords are: "5V power and logic level" and "10K pull-up resistors".

The same should be true for the SSD1306 OLED, so you can connect the OLED on the same bus.

going to each devices respective voltage supply (3.3 and 5v).

No, do not do this: Select one voltage level only (must be 5V if you own the 5V sensor).

Oliver

Ahh, thanks for clarifying. Yeah, at first I had both set to 5v, then realized that might have been wrong, so tried 3.3/5v. My setup was correct the first time, the values i was using were just much too low. Will try that here in a bit, thanks!

Okay, I tried the 10k but that didn’t work either, but now I think I see where I went wrong. I found this wiring diagram for i2c pull ups, and i thought each device required their own resistors, but now I see everything is wired together to the same resistors. Which makes more sense, because I was seeing people saying the resistor values depended on total bus capacitance, now I see why and now I see why a stronger resistor fits in with that. I’m still a little unsure of my wiring though, just because my cables are a little long and I’m not sure how that may affect the bus capacitance, but im going to try to fix my setup now and that’ll be a start.

I will also be turning a secondary Uno and oled into a makeshift voltmeter because I don’t have a multimeter (so I will just do this using a simple analogRead to u8g2, because that’s something I’ll have to add to this project later anyway) but there are plenty of resources for that, so i won’t bring that into this thread. Hopefully that will help me see my setup better though, too. Sorry for so many beginner questions/issues, but the help has gone a long way so far. Thanks!

i2ca.GIF

Alas, still no luck. The wiring diagram in my last post is reflective of my current setup, using two 10K resistors. But now, both devices are going to the same SCL and SDA pins on the Arduino. Here are the two programs ive been trying each time (both yielding the same results).

Program 1:

/***************************************************
  This is a library example for the MLX90614 Temp Sensor

  Designed specifically to work with the MLX90614 sensors in the
  adafruit shop
  ----> https://www.adafruit.com/products/1748
  ----> https://www.adafruit.com/products/1749

  These sensors use I2C to communicate, 2 pins are required to
  interface
  Adafruit invests time and resources providing this open source code,
  please support Adafruit and open-source hardware by purchasing
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.
  BSD license, all text above must be included in any redistribution
 ****************************************************/

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

#include <Arduino.h>
#include <U8g2lib.h>

#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif

Adafruit_MLX90614 mlx = Adafruit_MLX90614();
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);

void setup() {
  u8g2.begin();
  u8g2.enableUTF8Print();
  mlx.begin();
}

void loop() {
  u8g2.clearBuffer();                                 // update
  u8g2.setFont(u8g2_font_5x7_tf);
  u8g2.setCursor(0, 15);
  u8g2.print("Ambient = "); u8g2.print(mlx.readAmbientTempC());
  u8g2.setCursor(0, 25);
  u8g2.print("*C\tObject = "); u8g2.print(mlx.readObjectTempC()); u8g2.println("*C");
  u8g2.setCursor(0, 35);
  u8g2.print("Ambient = "); u8g2.print(mlx.readAmbientTempF());
  u8g2.setCursor(0, 45);
  u8g2.print("*F\tObject = "); u8g2.print(mlx.readObjectTempF()); u8g2.println("*F");
  u8g2.println();
  u8g2.sendBuffer();
  delay(500);
}

Program 2:

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

#include <Arduino.h>
#include <U8g2lib.h>

#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif

Adafruit_MLX90614 mlx = Adafruit_MLX90614();

U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);

const long screenInterval = 1000;           // interval at which to buffer (milliseconds)
unsigned long sensorInterval = 500;
unsigned long screenPreviousMillis = 0;
unsigned long sensorPreviousMillis = 0;


void setup() {
  mlx.begin();
  u8g2.begin();
  u8g2.enableUTF8Print();
}


void loop()
{
  unsigned long sensorCurrentMillis = millis();
  static double oldAmbientC = 500;
  static double oldObjectC = 500;                     // retains values
  if (sensorCurrentMillis - sensorPreviousMillis >= sensorInterval) {
    sensorPreviousMillis = sensorCurrentMillis;             // for next read
    double AmbientC = mlx.readAmbientTempC();
    double ObjectC = mlx.readObjectTempC();
    double AmbientF = mlx.readAmbientTempF();
    double ObjectF = mlx.readObjectTempF();
    if (AmbientC != oldAmbientC || ObjectC != oldObjectC) { // ?changed
      oldAmbientC = AmbientC;                             // remember
      oldObjectC = ObjectC;
      u8g2.clearBuffer();                                 // update
      u8g2.setFont(u8g2_font_5x7_tf);
      u8g2.setCursor(0, 15);
      u8g2.print("Ambient = "); u8g2.print(AmbientC);
      u8g2.setCursor(0, 25);
      u8g2.print("*C\tObject = "); u8g2.print(ObjectC); u8g2.println("*C");
      u8g2.setCursor(0, 35);
      u8g2.print("Ambient = "); u8g2.print(AmbientF);
      u8g2.setCursor(0, 45);
      u8g2.print("*F\tObject = "); u8g2.print(ObjectF); u8g2.println("*F");
      u8g2.println();
      u8g2.sendBuffer();                                  // draw the screen
    }
  }
}

In the meantime i will be working on a way to measure voltage, so hopefully i can shed more light on my i2c setup.

Hello,

I found the solution with MLX90614 giving always 1037.55 °C.
the problem looks to be due to the I2C clock speed, u8g2 set the highest I2C clock speed but MLX90614 does not work at 400KHz, so add “u8g2.setBusClock(100000);” to slow down I2C to 100KHz

Here is a working full example code:

#include "TimeLib.h"
#include <Adafruit_MLX90614.h>
#include <U8g2lib.h>    // https://github.com/olikraus/u8g2/wiki/u8g2reference#reference


//******************************* OLED ***************************************
U8G2_SSD1306_64X48_ER_1_HW_I2C  u8g2(U8G2_R0);

//****************************** MLX90614 *************************************
Adafruit_MLX90614 mlx = Adafruit_MLX90614();


//******************************** VARS **************************************
time_t time;
unsigned long timer;
const char DEGRE_C[] = { 0xB0,'C', '\0' };


void setup() {
  mlx.begin();  
  u8g2.setBusClock(100000);
  u8g2.begin();
  Serial.begin(115200);
  u8g2.setFont(u8g2_font_unifont_t_symbols);
}

void loop() {
  timer = millis();  
  Serial.print("Ambient = ");  Serial.print(mlx.readAmbientTempC()); Serial.print("°C");
  Serial.print("\tObject = "); Serial.print(mlx.readObjectTempC());  Serial.println("°C");

  u8g2.firstPage();
  do {  
      u8g2.setCursor(0,12);
      u8g2.print(mlx.readAmbientTempC()); u8g2.print(DEGRE_C);
      u8g2.setCursor(0,32);
      u8g2.print(mlx.readObjectTempC()); u8g2.print(DEGRE_C);
  } while( u8g2.nextPage() );

   while (millis() < (timer + 300)) {
     delay(5);
  }

}