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

    Voltmeter M5Stack (ADS1115) interface

    Scheduled Pinned Locked Moved Units
    1 Posts 1 Posters 2.1k Views 1 Watching
    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 Offline
      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

      Hello! It looks like you're interested in this conversation, but you don't have an account yet.

      Getting fed up of having to scroll through the same posts each visit? When you register for an account, you'll always come back to exactly where you were before, and choose to be notified of new replies (either via email, or push notification). You'll also be able to save bookmarks and upvote posts to show your appreciation to other community members.

      With your input, this post could be even better 💗

      Register Login
      • First post
        Last post