🤖Have you ever tried Chat.M5Stack.com before asking??😎
    M5Stack Community
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Register
    • Login

    Voltmeter M5Stack (ADS1115) interface

    Units
    1
    1
    1.7k
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • F
      FPI
      last edited by FPI

      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.
      0_1648305452141_2022-03-26-connection.png

      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.

      1 Reply Last reply Reply Quote 0
      • First post
        Last post