Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create MLX90615.js #580

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
130 changes: 130 additions & 0 deletions devices/MLX90615.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/* Copyright (C) 2020 Lerner. */

/*
Espruino module for MLX90615 Infra Red thermometer from Melexis connected by I2C
*/

/**
* Creates a new MLX90615 sensor instance
* @param i2c Instance of the I2C Class, e.g. I2C1
* @param address (optional) alternative I2C address; default is 0x5b
*/
function MLX90615(i2c, address) {
this.i2c = i2c;
this.voltage = 3.3; // supply voltage to compensate supply voltage dependence
this.ECC_Reg = 0x24; // Emissivity Correction Coefficient Register
// Check params
var br = (i2c._options && i2c._options.bitrate) || 50000; // later replaced with getBitrate()
if (br < 10000 || br > 100000) {
throw new Error("The maximum clock frequency is 100 kHz and the minimum is 10 kHz.");
}
this.i2cAddress = address || 0x5b;
// The first request will always trigger a crc error. → Dummy read von emissivity without crc check.
this.i2c.writeTo({ address: this.i2cAddress, stop: false }, this.ECC_Reg);
this.i2c.readFrom(this.i2cAddress, 3);
}

/**
* Read the ambient temperature from the sensor. The ambient temperature is the internal chip temperature.
* @returns {number} Ambient temperature in °C
*/
MLX90615.prototype.readAmbientTemperature = function () {
return this.convertRawToCelcius(this.read16(0x06));
};

/**
* @returns {number} temperature in °C
*/
MLX90615.prototype.readObjectTemperature = function () {
return this.convertRawToCelcius(this.read16(0x07));
};

/** I DONT BELIEVE THIS APPLIES
* Some variants of MXL90614 have a second IR sensor with a different field of view (angle).
* If the second sensor element is not available the sensor does not answer and you will get an I2C error.
* @returns {number} temperature in °C

MLX90614.prototype.readObject2Temperature = function () {
return this.convertRawToCelcius(this.read16(0x08));
};
*/

/**
* Enter the sensor into sleep mode (typ. 2.5µA). Afterwards the sensor doesn't answer I2C requests anymore.
* There are two ways to put MLX90614 into power-up default mode: 1) POR or 2) By wake up request (SCL pin hight and
* then SDA pin low for at least 33ms). Wakeup is currently not implemented.
*
* This function is not available in 5V supply version.
*/
MLX90615.prototype.enterSleepMode = function () {
this.i2c.writeTo(this.i2cAddress, 0xc6, 0x6d);
};
/**
* Read the current configured object emissivity from the sensor in the range from 0.0 to 1.0.
* @returns {number} configured object emissivity
*/
MLX90615.prototype.getEmissivity = function () {
return this.read16(this.ECC_Reg) / 16384;
};

/**
* Write a new object emissivity persistent into the sensor. The value will be stored in EEPROM.
* It is not necessary to erase the memory before. This is done internally.
* A read write operation will only be done if the value has changed.
* @param emissivity new object emissivity in the range from 0.0 to 1.0
*/
MLX90615.prototype.setEmissivity = function (emissivity) {
var rawOld = this.read16(this.ECC_Reg);
var rawNew = Math.round(emissivity * 16384);
if (rawOld !== rawNew) {
this.write16(this.ECC_Reg, 0);
this.write16(this.ECC_Reg, rawNew);
}
};

//----------------------------------------------------------------------------------------------------------
// Internal helper methods
//----------------------------------------------------------------------------------------------------------

MLX90615.prototype.convertRawToCelcius = function (raw) {
if (raw & 0x8000) {
throw new Error("Invalid temperature");
}
return raw * 0.02 - this.voltage * 0.6 - 273.15;
}; // IDK IF THIS NEEDS TO BE CHANGED

MLX90615.prototype.read16 = function (reg) {
this.i2c.writeTo({ address: this.i2cAddress, stop: false }, reg);
var d = this.i2c.readFrom(this.i2cAddress, 3);
var allData = [this.i2cAddress << 1, reg, (this.i2cAddress << 1) + 1, d[0], d[1]];
if (this.crc8(allData) !== d[2]) {
throw new Error("CRC Error");
}
return (d[1] << 8) + d[0];
};

MLX90615.prototype.write16 = function (cmd, value) {
var allData = [(this.i2cAddress << 1), cmd, value & 0xff, value >> 8];
var crc = this.crc8(allData);
var d = [cmd, value & 0xc6, value >> 8, crc];
this.i2c.writeTo(this.i2cAddress, d);
};

// Calculates CRC-8: x^8 + x^5 + x^4 + 1
MLX90615.prototype.crc8 = function (bytes) {
var crc = 0;
bytes.forEach(function (oneByte) {
for (var i = 7; i >= 0; --i) {
var temp = crc >> 7 ^ oneByte >> i & 1;
crc = crc << 1 & 255;
if (temp == 1) {
crc ^= 7;
}
}
});
return crc;
};

exports.connect = function (/*=I2C*/ i2c, address) {
return new MLX90615(i2c, address);
};