From daa55ea5806b2cf7a4b3c84038f77f5bf019366c Mon Sep 17 00:00:00 2001 From: jolielerner99 <71902625+jolielerner99@users.noreply.github.com> Date: Tue, 20 Oct 2020 17:31:27 -0500 Subject: [PATCH] Create MLX90615.js --- devices/MLX90615.js | 130 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 devices/MLX90615.js diff --git a/devices/MLX90615.js b/devices/MLX90615.js new file mode 100644 index 000000000..aeb86602c --- /dev/null +++ b/devices/MLX90615.js @@ -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); +};