/*****************************************
* This is a library for the ADS1115 A/D Converter
*
* You'll find an example which should enable you to use the library.
*
* You are free to use it, change it or build on it. In case you like
* it, it would be cool if you give it a star.
*
* If you find bugs, please inform me!
*
* Written by Wolfgang (Wolle) Ewald
* https://wolles-elektronikkiste.de/en/ads1115-a-d-converter-with-amplifier (English)
* https://wolles-elektronikkiste.de/ads1115 (German)
*
*******************************************/
#include "ADS1115_WE.h"
ADS1115_WE::ADS1115_WE(int addr){
_wire = &Wire;
i2cAddress = addr;
}
ADS1115_WE::ADS1115_WE(){
_wire = &Wire;
i2cAddress = 0x48;
}
ADS1115_WE::ADS1115_WE(TwoWire *w, int addr){
_wire = w;
i2cAddress = addr;
}
ADS1115_WE::ADS1115_WE(TwoWire *w){
_wire = w;
i2cAddress = 0x48;
}
void ADS1115_WE::reset(){
_wire->beginTransmission(0);
_wire->write(0x06);
_wire->endTransmission();
}
bool ADS1115_WE::init(){
_wire->beginTransmission(i2cAddress);
uint8_t success = _wire->endTransmission();
if(success){
return 0;
}
writeRegister(ADS1115_CONFIG_REG, ADS1115_REG_RESET_VAL);
setVoltageRange_mV(ADS1115_RANGE_2048);
writeRegister(ADS1115_LO_THRESH_REG, 0x8000);
writeRegister(ADS1115_HI_THRESH_REG, 0x7FFF);
deviceMeasureMode = ADS1115_SINGLE;
autoRangeMode = false;
return 1;
}
void ADS1115_WE::setAlertPinMode(ADS1115_COMP_QUE mode){
uint16_t currentConfReg = readRegister(ADS1115_CONFIG_REG);
currentConfReg &= ~(0x0003);
currentConfReg |= mode;
writeRegister(ADS1115_CONFIG_REG, currentConfReg);
}
void ADS1115_WE::setAlertLatch(ADS1115_LATCH latch){
uint16_t currentConfReg = readRegister(ADS1115_CONFIG_REG);
currentConfReg &= ~(0x0004);
currentConfReg |= latch;
writeRegister(ADS1115_CONFIG_REG, currentConfReg);
}
void ADS1115_WE::setAlertPol(ADS1115_ALERT_POL polarity){
uint16_t currentConfReg = readRegister(ADS1115_CONFIG_REG);
currentConfReg &= ~(0x0008);
currentConfReg |= polarity;
writeRegister(ADS1115_CONFIG_REG, currentConfReg);
}
void ADS1115_WE::setAlertModeAndLimit_V(ADS1115_COMP_MODE mode, float hiThres, float loThres){
uint16_t currentConfReg = readRegister(ADS1115_CONFIG_REG);
currentConfReg &= ~(0x0010);
currentConfReg |= mode;
writeRegister(ADS1115_CONFIG_REG, currentConfReg);
int16_t alertLimit = calcLimit(hiThres);
writeRegister(ADS1115_HI_THRESH_REG, alertLimit);
alertLimit = calcLimit(loThres);
writeRegister(ADS1115_LO_THRESH_REG, alertLimit);
}
void ADS1115_WE::setConvRate(ADS1115_CONV_RATE rate){
uint16_t currentConfReg = readRegister(ADS1115_CONFIG_REG);
currentConfReg &= ~(0x00E0);
currentConfReg |= rate;
writeRegister(ADS1115_CONFIG_REG, currentConfReg);
}
convRate ADS1115_WE::getConvRate(){
uint16_t currentConfReg = readRegister(ADS1115_CONFIG_REG);
return (convRate)(currentConfReg & 0xE0);
}
void ADS1115_WE::setMeasureMode(ADS1115_MEASURE_MODE mode){
uint16_t currentConfReg = readRegister(ADS1115_CONFIG_REG);
deviceMeasureMode = mode;
currentConfReg &= ~(0x0100);
currentConfReg |= mode;
writeRegister(ADS1115_CONFIG_REG, currentConfReg);
}
void ADS1115_WE::setVoltageRange_mV(ADS1115_RANGE range){
uint16_t currentVoltageRange = voltageRange;
uint16_t currentConfReg = readRegister(ADS1115_CONFIG_REG);
uint16_t currentRange = (currentConfReg >> 9) & 7;
uint16_t currentAlertPinMode = currentConfReg & 3;
setMeasureMode(ADS1115_SINGLE);
switch(range){
case ADS1115_RANGE_6144:
voltageRange = 6144;
break;
case ADS1115_RANGE_4096:
voltageRange = 4096;
break;
case ADS1115_RANGE_2048:
voltageRange = 2048;
break;
case ADS1115_RANGE_1024:
voltageRange = 1024;
break;
case ADS1115_RANGE_0512:
voltageRange = 512;
break;
case ADS1115_RANGE_0256:
voltageRange = 256;
break;
}
if ((currentRange != range) && (currentAlertPinMode != ADS1115_DISABLE_ALERT)){
int16_t alertLimit = readRegister(ADS1115_HI_THRESH_REG);
alertLimit = alertLimit * (currentVoltageRange * 1.0 / voltageRange);
writeRegister(ADS1115_HI_THRESH_REG, alertLimit);
alertLimit = readRegister(ADS1115_LO_THRESH_REG);
alertLimit = alertLimit * (currentVoltageRange * 1.0 / voltageRange);
writeRegister(ADS1115_LO_THRESH_REG, alertLimit);
}
currentConfReg &= ~(0x0E00);
currentConfReg |= range;
writeRegister(ADS1115_CONFIG_REG, currentConfReg);
convRate rate = getConvRate();
delayAccToRate(rate);
}
void ADS1115_WE::setAutoRange(){
uint16_t currentConfReg = readRegister(ADS1115_CONFIG_REG);
setVoltageRange_mV(ADS1115_RANGE_6144);
if(deviceMeasureMode == ADS1115_SINGLE){
setMeasureMode(ADS1115_CONTINUOUS);
convRate rate = getConvRate();
delayAccToRate(rate);
}
int16_t rawResult = abs(readRegister(ADS1115_CONV_REG));
range optRange = ADS1115_RANGE_6144;
if(rawResult < 1093){
optRange = ADS1115_RANGE_0256;
}
else if(rawResult < 2185){
optRange = ADS1115_RANGE_0512;
}
else if(rawResult < 4370){
optRange = ADS1115_RANGE_1024;
}
else if(rawResult < 8738){
optRange = ADS1115_RANGE_2048;
}
else if(rawResult < 17476){
optRange = ADS1115_RANGE_4096;
}
writeRegister(ADS1115_CONFIG_REG, currentConfReg);
setVoltageRange_mV(optRange);
}
void ADS1115_WE::setPermanentAutoRangeMode(bool autoMode){
if(autoMode){
autoRangeMode = true;
}
else{
autoRangeMode = false;
}
}
void ADS1115_WE::delayAccToRate(convRate cr){
switch(cr){
case ADS1115_8_SPS:
delay(130);
break;
case ADS1115_16_SPS:
delay(65);
break;
case ADS1115_32_SPS:
delay(32);
break;
case ADS1115_64_SPS:
delay(16);
break;
case ADS1115_128_SPS:
delay(8);
break;
case ADS1115_250_SPS:
delay(4);
break;
case ADS1115_475_SPS:
delay(3);
break;
case ADS1115_860_SPS:
delay(2);
break;
}
}
void ADS1115_WE::setCompareChannels(ADS1115_MUX mux){
uint16_t currentConfReg = readRegister(ADS1115_CONFIG_REG);
currentConfReg &= ~(0x7000);
currentConfReg |= (mux);
writeRegister(ADS1115_CONFIG_REG, currentConfReg);
if(!(currentConfReg & 0x0100)){ // => if not single shot mode
convRate rate = getConvRate();
delayAccToRate(rate);
delayAccToRate(rate);
}
}
void ADS1115_WE::setSingleChannel(size_t channel) {
if (channel >= 4)
return;
setCompareChannels((ADS1115_MUX)(ADS1115_COMP_0_GND + ADS1115_COMP_INC*channel));
}
bool ADS1115_WE::isBusy(){
uint16_t currentConfReg = readRegister(ADS1115_CONFIG_REG);
return (!(currentConfReg>>15) & 1);
}
void ADS1115_WE::startSingleMeasurement(){
uint16_t currentConfReg = readRegister(ADS1115_CONFIG_REG);
currentConfReg |= (1 << 15);
writeRegister(ADS1115_CONFIG_REG, currentConfReg);
}
float ADS1115_WE::getResult_V(){
float result = getResult_mV();
result /= 1000;
return result;
}
float ADS1115_WE::getResult_mV(){
int16_t rawResult = getRawResult();
float result = (rawResult * 1.0 / ADS1115_REG_FACTOR) * voltageRange;
return result;
}
int16_t ADS1115_WE::getRawResult(){
int16_t rawResult = readRegister(ADS1115_CONV_REG);
if(autoRangeMode){
if((abs(rawResult) > 26214) && (voltageRange != 6144)){ // 80%
setAutoRange();
rawResult = readRegister(ADS1115_CONV_REG);
}
else if((abs(rawResult) < 9800) && (voltageRange != 256)){ //30%
setAutoRange();
rawResult = readRegister(ADS1115_CONV_REG);
}
}
return rawResult;
}
int16_t ADS1115_WE::getResultWithRange(int16_t min, int16_t max){
int16_t rawResult = getRawResult();
int16_t result = map(rawResult, -32767, 32767, min, max);
return result;
}
int16_t ADS1115_WE::getResultWithRange(int16_t min, int16_t max, int16_t maxMillivolt){
int16_t result = getResultWithRange(min, max);
result = (int16_t) ((1.0 * result * voltageRange / maxMillivolt) + 0.5);
return result;
}
uint16_t ADS1115_WE::getVoltageRange_mV(){
return voltageRange;
}
void ADS1115_WE::setAlertPinToConversionReady(){
writeRegister(ADS1115_LO_THRESH_REG, (0<<15));
writeRegister(ADS1115_HI_THRESH_REG, (1<<15));
}
void ADS1115_WE::clearAlert(){
readRegister(ADS1115_CONV_REG);
}
/************************************************
private functions
*************************************************/
int16_t ADS1115_WE::calcLimit(float rawLimit){
int16_t limit = (int16_t)((rawLimit * ADS1115_REG_FACTOR / voltageRange)*1000);
return limit;
}
uint8_t ADS1115_WE::writeRegister(uint8_t reg, uint16_t val){
_wire->beginTransmission(i2cAddress);
uint8_t lVal = val & 255;
uint8_t hVal = val >> 8;
_wire->write(reg);
_wire->write(hVal);
_wire->write(lVal);
return _wire->endTransmission();
}
uint16_t ADS1115_WE::readRegister(uint8_t reg){
uint8_t MSByte = 0, LSByte = 0;
uint16_t regValue = 0;
_wire->beginTransmission(i2cAddress);
_wire->write(reg);
_wire->endTransmission(false);
_wire->requestFrom(i2cAddress,2);
if(_wire->available()){
MSByte = _wire->read();
LSByte = _wire->read();
}
regValue = (MSByte<<8) + LSByte;
return regValue;
}