Voltmeter M5Stack (ADS1115) interface
-
Hello,
I try to interface the Voltemer based on ADS1115 in nodejs.
The only given sample is based on C++ and Arduino code, but there is no detailled documentation on which command and parameters can be sent to register, in order to get measure for each range of voltage.
I try to measure a battery voltage, like the picture here.
Here is my code. Can you give me more information ?
- which element is to read : MUX_DIFF_0_1 : (0x0000), MUX_DIFF_0_3 : (0x1000), MUX_DIFF_1_3 : (0x2000), MUX_DIFF_2_3 : (0x3000), MUX_SINGLE_0 : (0x4000), MUX_SINGLE_1 : (0x5000), MUX_SINGLE_2 : (0x6000), MUX_SINGLE_3 : (0x7000) ?
- which mathematical operation is to do with the value read in ther register ? multiply with what, depending of what (gain ?) ?
Thank you for information.
/* sample*/ var ADS1X15 = {}; /* Register values. Most of these aren't used and this is hidden, so it'll get optimised out when minified */ ADS1X15.CONFIG = { OS_MASK : (0x8000), OS_SINGLE : (0x8000), // Write: Set to start a single-conversion OS_BUSY : (0x0000), // Read: Bit = 0 when conversion is in progress OS_NOTBUSY : (0x8000), // Read: Bit = 1 when device is not performing a conversion MUX_MASK : (0x7000), MUX_DIFF_0_1 : (0x0000), // Differential P = AIN0, N = AIN1 (default) MUX_DIFF_0_3 : (0x1000), // Differential P = AIN0, N = AIN3 MUX_DIFF_1_3 : (0x2000), // Differential P = AIN1, N = AIN3 MUX_DIFF_2_3 : (0x3000), // Differential P = AIN2, N = AIN3 MUX_SINGLE_0 : (0x4000), // Single-ended AIN0 MUX_SINGLE_1 : (0x5000), // Single-ended AIN1 MUX_SINGLE_2 : (0x6000), // Single-ended AIN2 MUX_SINGLE_3 : (0x7000), // Single-ended AIN3 PGA_MASK : (0x0E00), PGA_6_144V : (0x0000), // +/-6.144V range = Gain 2/3 PGA_4_096V : (0x0200), // +/-4.096V range = Gain 1 PGA_2_048V : (0x0400), // +/-2.048V range = Gain 2 (default) PGA_1_024V : (0x0600), // +/-1.024V range = Gain 4 PGA_0_512V : (0x0800), // +/-0.512V range = Gain 8 PGA_0_256V : (0x0A00), // +/-0.256V range = Gain 16 MODE_MASK : (0x0100), MODE_CONTIN : (0x0000), // Continuous conversion mode MODE_SINGLE : (0x0100), // Power-down single-shot mode (default) DR_MASK : (0x00E0), DR_128SPS : (0x0000), // 128 samples per second DR_250SPS : (0x0020), // 250 samples per second DR_490SPS : (0x0040), // 490 samples per second DR_920SPS : (0x0060), // 920 samples per second DR_1600SPS : (0x0080), // 1600 samples per second (default) DR_2400SPS : (0x00A0), // 2400 samples per second DR_3300SPS : (0x00C0), // 3300 samples per second CMODE_MASK : (0x0010), CMODE_TRAD : (0x0000), // Traditional comparator with hysteresis (default) CMODE_WINDOW : (0x0010), // Window comparator CPOL_MASK : (0x0008), CPOL_ACTVLOW : (0x0000), // ALERT/RDY pin is low when active (default) CPOL_ACTVHI : (0x0008), // ALERT/RDY pin is high when active CLAT_MASK : (0x0004), // Determines if ALERT/RDY pin latches once asserted CLAT_NONLAT : (0x0000), // Non-latching comparator (default) CLAT_LATCH : (0x0004), // Latching comparator CQUE_MASK : (0x0003), CQUE_1CONV : (0x0000), // Assert ALERT/RDY after one conversions CQUE_2CONV : (0x0001), // Assert ALERT/RDY after two conversions CQUE_4CONV : (0x0002), // Assert ALERT/RDY after four conversions CQUE_NONE : (0x0003) // Disable the comparator and put ALERT/RDY in high state (default) }; /* Voltage_measurement_range Maximum_input_DC_voltage(V) Minimum_resolution(mV) Gain_factor PAG_4096(Calibrated) ±128 7.85 0.125 2.048 64 3.93 0.0625 1.024 32 1.96 0.03125 0.512 16 0.98 0.015625 PAG_256(Calibrated) ±8 0.49 0.007813 */ ADS1X15.GAINS = { 6144 : ADS1X15.CONFIG.PGA_6_144V, // +/-6.144V range = Gain 2/3 4096 : ADS1X15.CONFIG.PGA_4_096V, // +/-4.096V range = Gain 1 2048 : ADS1X15.CONFIG.PGA_2_048V, // +/-2.048V range = Gain 2 (default) 1024 : ADS1X15.CONFIG.PGA_1_024V, // +/-1.024V range = Gain 4 512 : ADS1X15.CONFIG.PGA_0_512V, // +/-0.512V range = Gain 8 256 : ADS1X15.CONFIG.PGA_0_256V // +/-0.256V range = Gain 16; }; ADS1X15.VOLT_RANGE = { "0_8V": 256, "0_16V": 512, "0_32V": 1024, "0_64V": 2048, "0_128V": 4096 }; ADS1X15.MULTICATOR = { 6144: 0.187500, 4096: 0.125000, 2048: 0.062500, 1024: 0.031250, 512: 0.015625, 256: 0.007813 }; ADS1X15.COEFFICIENT = 0.015918958; ADS1X15.DIFFS = { "0,1" : ADS1X15.CONFIG.MUX_DIFF_0_1, // Differential P = AIN0, N = AIN1 (default) "0,3" : ADS1X15.CONFIG.MUX_DIFF_0_3, // Differential P = AIN0, N = AIN3 "1,3" : ADS1X15.CONFIG.MUX_DIFF_1_3, // Differential P = AIN1, N = AIN3 "2,3" : ADS1X15.CONFIG.MUX_DIFF_2_3 // Differential P = AIN2, N = AIN3 }; ADS1X15.SINGLE_CHANELS = [ ADS1X15.CONFIG.MUX_SINGLE_0, ADS1X15.CONFIG.MUX_SINGLE_1, ADS1X15.CONFIG.MUX_SINGLE_2, ADS1X15.CONFIG.MUX_SINGLE_3 ]; ADS1X15.REG = { MASK : 3, CONVERT : 0, CONFIG : 1, LOWTHRESH : 2, HITHRESH : 3 }; // prototypes if (Number.prototype.toHexa === undefined) { Number.prototype.toHexa = function( len) { return "0x" + this.toString( 16).padStart( len, '0'); } } if (Buffer.prototype.toHexa === undefined) { Buffer.prototype.toHexa = function() { let str = ""; let arr = [...this]; arr.forEach( a => { str = '0x' + a.toString(16).padStart( 2, '0') + ' ' + str; }); return str; } } // used internally for writing to the ADC function writeRegister( i2c, register, value) { const funcName = "writeRegister"; const buff = Buffer.from( [register & 3, value >> 8, value & 0xFF]); console.log( `${funcName}> write to ${addr.toHexa(2)}, buff: ${buff.toHexa()}...`); try { let nbBytesWritten = i2c.i2cWriteSync( addr, 3, buff); console.log( `${funcName}> ${nbBytesWritten} written`); } catch( err1) { console.log( `${funcName}> write FAILS > err1: ${err1}`); } } // used internally for reading from the ADC function readRegister( i2c, register) { const funcName = "readRegister"; let value = null; do { const buffW = Buffer.from( [register] ); console.log( `${funcName}> write to ${addr.toHexa(2)} register: ${register.toHexa(2)}...`); try { i2c.i2cWriteSync( addr, 1, buffW); } catch( err1) { console.log( `${funcName}> write FAILS > err1: ${err1}`); break; //!!!!! } let buffR = Buffer.from( [ 0, 0]); try { let nbBytesRead = i2c.i2cReadSync( addr, 2, buffR); value = (buffR[0] << 8) | buffR[1]; console.log( `${funcName}> ${nbBytesRead} read, buffR: ${buffR.toHexa()}, value: ${value}`); } catch( err2) { console.log( `${funcName}> read FAILS > err2: ${err2}`); break; //!!!!! } } while( false); return value; } function getADC( i2c, channelSpec, callback) { let config = ADS1X15.CONFIG.CQUE_NONE | // Disable the comparator (default val) ADS1X15.CONFIG.CLAT_NONLAT | // Non-latching (default val) ADS1X15.CONFIG.CPOL_ACTVLOW | // Alert/Rdy active low (default val) ADS1X15.CONFIG.CMODE_TRAD | // Traditional comparator (default val) ADS1X15.CONFIG.DR_1600SPS | // rate: 1600 samples per second (default) ADS1X15.CONFIG.MODE_SINGLE; // Single-shot mode (default) // single ended (channelSpec is a number) or differential (channelSpec is array w/ valid channel duo) if ("number" == typeof channelSpec) { // Set single-ended input channel if ( ! ADS1X15.SINGLE_CHANELS.includes( channelSpec)) { throw new Error( `Invalid single-ended channelSpec ${channelSpec.toHexa()} ! use one of ADS1X15.SINGLE_CHANELS ${ADS1X15.SINGLE_CHANELS}`); } config |= channelSpec; } else { // Set differential input channels from channelSpec if ( ! (channelSpec in ADS1X15.DIFFS)) { throw new Error( `Invalid differention channelSpec ${channelSpec} ! use one of ADS1X15.DIFFS`); } let diffChannel = ADS1X15.DIFFS[ channelSpec]; config |= diffChannel; } // Set PGA/voltage range config |= ADS1X15.GAINS[ gain]; // Set 'start single-conversion' bit config |= ADS1X15.CONFIG.OS_SINGLE; // Write config register to the ADC writeRegister( i2c, ADS1X15.REG.CONFIG, config); // Wait for the conversion to complete setTimeout(function() { // Read the conversion results let d = readRegister( i2c, ADS1X15.REG.CONVERT); if ( d & 0x8000) { d -= 65535; // sign } let volts = parseFloat( d) * resolution; console.log( `d: ${d}, resolution: ${resolution}, volts: ${volts}`); callback( volts); }, 8); } var i2cBus = null; var DEV_I2C = 1; var I2C_BUS = require("i2c-bus"); console.log( `VoltMeter.js > on linux > i2c-bus loaded.`); var addr = 0x49; var voltRange = "0_8V"; var gain = ADS1X15.VOLT_RANGE[ voltRange]; var multiplicator = ADS1X15.MULTICATOR[ gain]; var resolution = parseFloat( multiplicator / ADS1X15.COEFFICIENT); console.log( `gain: ${gain.toHexa()}, multiplicator: ${multiplicator}, COEFFICIENT: ${ADS1X15.COEFFICIENT}, resolution: ${resolution}...`); i2cBus = I2C_BUS.open( DEV_I2C, err1 => { if (err1) { console.log( `i2c.open FAILS > err1: ${err1}`); } else { setInterval( function() { // getADC( i2cBus, ADS1X15.CONFIG.MUX_SINGLE_0, function( value) { getADC( i2cBus, "0,1", function( value) { console.log( `${new Date().toISOString()} > mesure ${value} volts`); }); }, 1000); } });
Best regards.