this is my first time using the arduino and im kinda struggling. What im trying to do is read the temperature data from multiple MLX90614 IR Temperature Sensors, (data sheet found here Error - Melexis).
I have sucessfully changed the device names so that they each have there own "name" (A1 & A2) and can read temp from one device connected at once but im at a loss on how to code the program to read and display the temp from each of the devices ie;
// Print Data To Screen...
Serial.print("Temp sensor: A1: ");
Serial.print(celcius1);
Serial.print(" A2: ");
Serial.println(celcius2);
I have attached my current sketch for you to see. note sensor 3 is commented out as im waiting on it atm
hey
ill repost the full thing below and i will have a look at yours and try get my head round it. only been using the arduino for about 3 weeks.
#include <i2cmaster.h>
void setup(){
Serial.begin(115200);
Serial.println("Setup...");
i2c_init(); //Initialise the i2c bus
PORTC = (1 << PORTC4) | (1 << PORTC5);//enable pullups
}
void loop(){
int dev1 = 0xA1<<1;
int dev2 = 0xA2<<1;
//int dev3 = 0xA3<<1;
int data_low = 0;
int data_high = 0;
int pec = 0;
i2c_start_wait(dev1+I2C_WRITE);
i2c_write(0x07); //Object
i2c_start_wait(dev2+I2C_WRITE);
i2c_write(0x07); //Object
/*i2c_start_wait(dev3+I2C_WRITE);
i2c_write(0x07); //Object
*/
// read
i2c_rep_start(dev1+I2C_READ);
data_low = i2c_readAck(); //Read 1 byte and then send ack
data_high = i2c_readAck(); //Read 1 byte and then send ack
pec = i2c_readNak();
i2c_stop();
i2c_rep_start(dev2+I2C_READ);
data_low = i2c_readAck(); //Read 1 byte and then send ack
data_high = i2c_readAck(); //Read 1 byte and then send ack
pec = i2c_readNak();
i2c_stop();
/*i2c_rep_start(dev3+I2C_READ);
data_low = i2c_readAck(); //Read 1 byte and then send ack
data_high = i2c_readAck(); //Read 1 byte and then send ack
pec = i2c_readNak();
i2c_stop();
*/
// Sensor A1 Readings...
//This converts high and low bytes together and processes temperature, MSB is a error bit and is ignored for temps
double tempFactor1 = 0.02; // 0.02 degrees per LSB (measurement resolution of the MLX90614)
double tempData1 = 0x0000; // zero out the data
int frac; // data past the decimal point
// This masks off the error bit of the high byte, then moves it left 8 bits and adds the low byte.
tempData1 = (double)(((data_high & 0x007F) << 8) + data_low);
tempData1 = (tempData1 * tempFactor1)-0.01;
float celcius1 = tempData1 - 273.15;
// Sensor A2 Readings...
//This converts high and low bytes together and processes temperature, MSB is a error bit and is ignored for temps
double tempFactor2 = 0.02; // 0.02 degrees per LSB (measurement resolution of the MLX90614)
double tempData2 = 0x0000; // zero out the data
int frac2; // data past the decimal point
// This masks off the error bit of the high byte, then moves it left 8 bits and adds the low byte.
tempData2 = (double)(((data_high & 0x007F) << 8) + data_low);
tempData2 = (tempData1 * tempFactor2)-0.01;
float celcius2 = tempData2 - 273.15;
/* Sensor A3 Readings...
//This converts high and low bytes together and processes temperature, MSB is a error bit and is ignored for temps
double tempFactor3 = 0.02; // 0.02 degrees per LSB (measurement resolution of the MLX90614)
double tempData3 = 0x0000; // zero out the data
int frac3; // data past the decimal point
// This masks off the error bit of the high byte, then moves it left 8 bits and adds the low byte.
tempData3 = (double)(((data_high & 0x007F) << 8) + data_low);
tempData3 = (tempData1 * tempFactor3)-0.01;
float celcius3 = tempData3 - 273.15;
*/
// Print Data To Screen...
Serial.print("Temp sensor: A1: ");
Serial.print(celcius1);
Serial.print(" A2: ");
Serial.println(celcius2);
//Serial.print(" A3:");
//Serial.println(celcius3);
delay(3000); // wait 3 seconds before printing again
}
What happens when you run your code? The only thing that immediately pops to mind (I'm new at this, too)
is that you might need to wait a few cycles between reading different devices on the bus...
or maybe start each device, read it, stop it, THEN move to the next one.
Cleaned up your code by making a function of the most important part. The code is essential the same but as it is much smaller it is easier to debug I think.
BTW double == float on Arduino
#include <i2cmaster.h>
void setup()
{
Serial.begin(115200);
Serial.println("Setup...");
setupI2CBus();
}
void loop()
{
float celcius1 = readDevice(A1);
float celcius2 = readDevice(A2);
float celsius3 = readDevice(A3);
// Print Data To Screen...
Serial.print("Temp sensor: A1: ");
Serial.print(celcius1);
Serial.print(" A2: ");
Serial.println(celcius2);
Serial.print(" A3:");
Serial.println(celcius3);
delay(3000);
}
/////////////////////////////////////////////////////////
//
// helper functions
//
void setupI2CBus()
{
i2c_init(); //Initialise the i2c bus
PORTC = (1 << PORTC4) | (1 << PORTC5); //enable pullups
}
float readDevice(int address)
{
int dev = address << 1;
int data = 0;
int pec = 0;
// RAW READ
i2c_start_wait(dev + I2C_WRITE);
i2c_write(0x07);
i2c_rep_start(dev + I2C_READ);
data = i2c_readAck() * 256;
data = data + i2c_readAck();
pec = i2c_readNak();
i2c_stop();
// PROCESS DATA
data = data & 0x7FFF;
float temp = (data * 0.02) - 273.16;
return temp;
}
1st off wow! that code is tiny!! and i would never of thought of setting it up that way.
i was just wondering if you could possibly guide my through the code a little. This is my first ever C/C++ coding and what I've managed to do so far has been a mash up between reading the data sheet, internet searches and the forums on here.
What im trying get my head round is how each device is initiated :~.
TobyB:
What happens when you run your code? The only thing that immediately pops to mind (I'm new at this, too)
is that you might need to wait a few cycles between reading different devices on the bus...
or maybe start each device, read it, stop it, THEN move to the next one.
When i run the code both the one i posted and the one by robtillaart, all i get from the serial port is "Setup....."
One thing that im wondering is. i made myself a small I2C connected device scanner using a different library. when i run that it shows it found devices at 0x21 & 0x22 ?? when in my initial setup i named the devices 0xA1 & 0xA2. is this something todo with the byte shift thing "<<1"?
Also the ' << 1 ' is needed in the address otherwise it wont read anything also states in the data sheet. Im at a bit of a loss on how to do it.
gonna keep trying over the weekend and will update if i make a breakthrough. If not i will ask my tutor for help and then repost what I found. eventually the data is going to be sent via the CANSheild, but thats for a nother day 8)
what i mean is the devices are reading between -180 & -80 degress C ???
ill have a look at the code again soon and see if its to do with the maths encoded but over this weekend my grphics card in my laptop has jacked in but i will update if i work it out.
speaking with my tutor we found that the code wildbill posted was only getting 8bits instated of the full 16 needed. turns out if i just used the original and add a return at the end it works!
here is what my code now looks like for anybody interested. i changed the device names as to fit better with the project implementation and added an extra device.
#include <i2cmaster.h>
void setup()
{
Serial.begin(115200);
Serial.println("Setup...");
// Setup I2CBus
i2c_init(); //Initialise then,
PORTC = (1 << PORTC4) | (1 << PORTC5); //enable pullups
}
void loop()
{
float temperature1 = readDevice(0x51); // addresses from the scanner
float temperature2 = readDevice(0x52);
float temperature3 = readDevice(0x53);
float temperature4 = readDevice(0x54);
// Print Data To Screen...
Serial.println("Temperature Readings (*c):");
Serial.print("> A1(51): ");
Serial.println(temperature1);
Serial.print("> A2(52): ");
Serial.println(temperature2);
Serial.print("> A3(53): ");
Serial.println(temperature3);
Serial.print("> A4(54): ");
Serial.println(temperature4);
delay(2000);
}
/////////////////////////////////////////////////////////
//
// helper functions
//
float readDevice(int address)
{
int dev = address << 1;
int data_low = 0;
int data_high = 0;
int pec = 0;
// RAW READ
i2c_start_wait(dev + I2C_WRITE);
i2c_write(0x07);
i2c_rep_start(dev + I2C_READ);
data_low = i2c_readAck(); //Read 1 byte and then send ack
data_high = i2c_readAck(); //Read 1 byte and then send ack
pec = i2c_readNak();
i2c_stop();
//This converts high and low bytes together and processes temperature, MSB is a error bit and is ignored for temps
double tempFactor = 0.02; // 0.02 degrees per LSB (measurement resolution of the MLX90614)
double tempData = 0x0000; // zero out the data
int frac; // data past the decimal point
// This masks off the error bit of the high byte, then moves it left 8 bits and adds the low byte.
tempData = (double)(((data_high & 0x007F) << 8) + data_low);
tempData = (tempData * tempFactor)-0.01;
//Process tempData
float objTemp = tempData - 273.15;
delay(500);
return objTemp;
}
Ive tried myself from what ive gathered on the net but struggling and unsure if it is possible change the device names into an array format and still print out the same??
Not to worry if not, just the final system would be reading from a min of 12 devices:
tempArea1[4]={0x51, 0x52, 0x53, 0x54};
tempArea2[4]=(0x61, 0x62, 0x63, 0x64};
tempArea3...
and so on..
Hey, glad it's working- I just got 2 more in the mail today, so I'm next up to try to get
multiple sensors going. My version will just turn the data around, combine it with other
inputs, and log it to SD. So the Arduino won't actually have to do much with it, except the Kelvin
conversion.
hey, its going to be used as tyre temperature monitor for a car to improve tyre usage in race situations. can i ask how your storing it to SD? ive not fully looked into it due to time constraints but mine will have the CANBus-Sheild on so it can be fed back to the ecu but if i could use the sd slot as a kind of backup that would be great.
Just wondered any thoughts on setting up an array for device names?
Oh... that's funny. That's what I am working on as well. I started out looking at it as a lazy way to get
more temps- but then found that it's actually a better way to read the car's instantaneous response to
suspension settings.... I run in a relatively restricted class, so any advantage you can find really does matter.
I haven't gotten past the hardware layer. This is a 'when you have time' project, since actually having
a running car is the first priority- I can tell you what the temps are when it's sitting in the garage!
One of the things I'm bumping up against, though, is that SDcards are surprisingly slow in the mode
that Arduino talks to them. I had originally planned to make this a full data logging system, but
the math on the back of the napkin seems to indicate that I'll be getting parts and pieces if I want
data rates high enough to do suspension travel and things like that.