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.