two ADS1115 on the same Arduino

Seems an easy task for an ESP8266-12 based Arduino (Wemos/NodeMCU) and a single ADS breakout board.
Leo..

Indeed. NodeMCU and a single ADS1115 would do great for a project like this.

If you can afford to lose some resolution and scale factors are not too different (it seems you have a 0-10V and a 0-4V signal so that seems OK) you can set it to the lowest gain and connect both sensors to the same ADS1115. Saves one component.

Otherwise indeed create two ADS1115 objects with different name (use the Adafruit library, for example), say ADS1 and ADS2, each with their respective I2C address, and then you can use them independently in your code.

For your buttons: do a search on this forum on how to connect buttons and how to debounce them (to prevent you relay from switching off instantly). The code is simple.

Hi Leo,

I have two ESP8266 and two Feather Huzzah ESP8266. I will keep my actual project with the Arduino UNO and add later the ESP8266 to it for the wi-fi.

So far so good,

I have 3 buttons installed and each one control a LED. I will replace the LEDs for relays when my tests are finish.

I have condition (If PSI > 3200) it will LOW the LED 1
same thing for LED2 with the oxygen %

Now my bug is the following

I want the LED no 3 to blink when I push the button no 3 but I don't want the delay of the blinking to delayed the rest of the program

I want six minutes off and then 1 second on, ( six minutes off, one second on ) like that until I press the button #3 again.

I'm sure that there is a better way to blink a led without "blinking the program at the same time"

Still reading on Google :slight_smile:

Check out "blink without delay"

Hi

Yes I'm looking at that subject. Since I already have a code for all the other options, it's hard to see for me on where I can apply the example to my existing code.

Since I only received my first Arduino 3 days ago and I never program any code before, I have to fight with a lot of unknown here.

This is my code to read One Air pressure sensor (PSI)
to read an Oxygen sensor (O2)
To send the result to a LCD 16,2
One button to calibrate the O2 sensor
3 buttons to control 3 LED

All this is working but now I need to make the LED #3 to flash when I press the button #3

six minute off, one second on, six minutes on one second off until I press the button again


This code is coming from 3 different person and example on the web. I'm sure that one day
I will clean it but for now I'm just happy that it's working not so bad

//#define _DEBUG

#include <Wire.h>
#include <Adafruit_ADS1015.h>
#include <LiquidCrystal_I2C.h>
#include <EEPROM.h>
#include <RunningAverage.h>

#define RA_SIZE 20
RunningAverage RA(RA_SIZE);

Adafruit_ADS1115 ads_O2 (0x49);
Adafruit_ADS1115 ads_PSI (0x48);

// activer les LED et boutons
int pinButton1 = 8;
int LED1 = 3;
int stateLED1 = LOW;
int stateButton1;

int pinButton2 = 9;
int LED2 = 4;
int stateLED2 = LOW;
int stateButton2;

int pinButton3 = 10;
int LED3 = 5;
int stateLED3 = LOW;
int stateButton3;

// debounce
int previous = LOW;
long time = 0;
long debounce = 300;

// section pour le PSI
int16_t rawADCvalue; // The is where we store the value we receive from the ADS1115
float scalefactor = 0.1250F; // This is the scale factor for the default +/- 4096 Volt Range we will use
float PSI = 0.0; // The result of applying the scale factor to the raw value

LiquidCrystal_I2C lcd(0x27,16,2); // your i2c address might differnt. if not working try scanning i2c first.

const int buttonPin=2; // push button
//const int ledPin = 13; // led
double calibrationv;
float multiplier;

int programState = 0;
int buttonState;
long buttonMillis = 0;
const long intervalButton = 2000; // 2 sec button hold to calibration

/*
Calculate MOD (Maximum Operating Depth)
*/
float max_po1 = 1.40;
float max_po2 = 1.60;
float cal_mod (float percentage, float ppo2 = 1.4) {
return 10 * ( (ppo2/(percentage/100)) - 1 );
}

int read_sensor(int x=0) {
int16_t millivolts = 0;
if (x == 0) {
millivolts = ads_O2.readADC_Differential_0_1();
RA.addValue(millivolts);
}

}

void setup(void)

{

//input output 3 boutons
pinMode(pinButton1, INPUT);
pinMode(LED1, OUTPUT);

pinMode(pinButton2, INPUT);
pinMode(LED2, OUTPUT);

pinMode(pinButton3, INPUT);
pinMode(LED3, OUTPUT);

#ifdef _DEBUG
Serial.begin(9600);
#endif

pinMode(buttonPin,INPUT_PULLUP);

// The ADC input range (or gain) can be changed via the following
// functions, but be careful never to exceed VDD +0.3V max, or to
// exceed the upper and lower limits if you adjust the input range!
// Setting these values incorrectly may destroy your ADC!
// ADS1015 ADS1115
// ------- -------
// ads.setGain(GAIN_TWOTHIRDS); // 2/3x gain +/- 6.144V 1 bit = 3mV 0.1875mV (default)
// ads.setGain(GAIN_ONE); // 1x gain +/- 4.096V 1 bit = 2mV 0.125mV
// ads.setGain(GAIN_TWO); // 2x gain +/- 2.048V 1 bit = 1mV 0.0625mV
// ads.setGain(GAIN_FOUR); // 4x gain +/- 1.024V 1 bit = 0.5mV 0.03125mV
// ads.setGain(GAIN_EIGHT); // 8x gain +/- 0.512V 1 bit = 0.25mV 0.015625mV
// ads.setGain(GAIN_SIXTEEN); // 16x gain +/- 0.256V 1 bit = 0.125mV 0.0078125mV

ads_O2.begin(); // ads1115 Pour O2 initialize
ads_PSI.begin(); // ads1115 pour PSI initialize

ads_O2.setGain(GAIN_TWO);
multiplier = 0.0625F;

ads_PSI.setGain(GAIN_ONE);
// multiplier = 0.1250F;

lcd.init();
lcd.backlight();
lcd.clear();

RA.clear();
for(int cx=0; cx<= RA_SIZE; cx++) {
read_sensor(0);
}

calibrationv = EEPROMReadInt(0);
if (calibrationv < 100) calibrationv=calibrate(0);
}

void EEPROMWriteInt(int p_address, int p_value)
{
byte lowByte = ((p_value >> 0) & 0xFF);
byte highByte = ((p_value >> 8) & 0xFF);

EEPROM.write(p_address, lowByte);
EEPROM.write(p_address + 1, highByte);
}

unsigned int EEPROMReadInt(int p_address)
{
byte lowByte = EEPROM.read(p_address);
byte highByte = EEPROM.read(p_address + 1);

return ((lowByte << 0) & 0xFF) + ((highByte << 8) & 0xFF00);
}

int calibrate(int x){
lcd.clear();
lcd.print("Calibrating");

double result;
for(int cx=0; cx<= RA_SIZE; cx++) {
read_sensor(0);
}

result = RA.getAverage();
result = abs(result);
EEPROMWriteInt(x, result); // write to eeprom

lcd.clear();
return result;
}

void analysing(int x, int cal, String txt) {
double currentmv;
double result;
double mv = 0.0;

read_sensor(x);
currentmv = RA.getAverage();
currentmv = abs(currentmv);

result = (currentmv / cal) * 20.9;
if (result > 99.9) result = 99.9;
mv = currentmv * multiplier;

lcd.setCursor(0,0);
if (mv < 0.02) {
lcd.print("Sensor error! ");
} else

{

lcd.print(txt);
lcd.print(result,1);
lcd.print("% ");
lcd.print(mv,1);
lcd.print("mv");

lcd.setCursor(0,1);
lcd.print("Pression = ");
lcd.print(PSI,0);

Serial.begin(9600);

Serial.print("Oxygen ");
Serial.print(result,1);
Serial.print("% ");
Serial.print(mv,1);
Serial.print("mv");

if (result > 30)
{
stateLED2 = LOW;
}

// lcd.setCursor(0,1);
// lcd.print("MOD ");
// lcd.print(cal_mod(result,max_po1),1);
// lcd.print("m ");
// lcd.print(cal_mod(result,max_po2),1);
// lcd.print("m ");

}
}

void loop(void)
{

// section pour le PSI
rawADCvalue = ads_PSI.readADC_SingleEnded(0);
PSI = (rawADCvalue * scalefactor) -35.0;

if (PSI > 500)
{
stateLED1 = LOW;
stateLED2 = LOW;
}

{

Serial.begin(9600);

// Serial.print("Raw data pressure = ");
// Serial.print(rawADCvalue);
Serial.print("\tPSI = ");
Serial.println(PSI,0);
Serial.println();

}

lcd.clear();
lcd.home();

unsigned long currentMillis = millis();
buttonState = digitalRead(buttonPin);

if (buttonState == LOW && programState == 0) {
buttonMillis = currentMillis;
programState = 1;
} else if (programState == 1 && buttonState == HIGH) {
programState = 0;
}

if(currentMillis - buttonMillis > intervalButton && programState == 1) {
calibrationv=calibrate(0); // calibration
programState = 1;
}
analysing(0,calibrationv,"O2 ");
delay(500);

{

//bouton 1
stateButton1 = digitalRead(pinButton1);
if(stateButton1 == HIGH && previous == LOW && millis() - time > debounce) { //if button is pressed and LED is off
if(stateLED1 == HIGH){
stateLED1 = LOW;
} else {
stateLED1 = HIGH;
}
time = millis();
}
digitalWrite(LED1, stateLED1);
previous == stateButton1;

// bouton 2
stateButton2 = digitalRead(pinButton2);
if(stateButton2 == HIGH && previous == LOW && millis() - time > debounce) { //if button is pressed and LED is off
if(stateLED2 == HIGH){
stateLED2 = LOW;
} else {
stateLED2 = HIGH;
}
time = millis();
}
digitalWrite(LED2, stateLED2);
previous == stateButton2;

//bouton 3
stateButton3 = digitalRead(pinButton3);
if(stateButton3 == HIGH && previous == LOW && millis() - time > debounce) { //if button is pressed and LED is off
if(stateLED3 == HIGH){
stateLED3 = LOW;
} else {
stateLED3 = HIGH;
}
time = millis();
}

digitalWrite(LED3, stateLED3);
previous == stateButton3;

}

}

Or use a Timer pin as the LED out and use the hardware to generate the "blinks", completely removing the software barrier for the toggling. If this pin is still available of course.

I am unsure what I have done wrong here...but I must be missing something, but here is an example (some could maybe fix this) that should have given a "500ms" toggle of an LED (On for 500ms, off 500ms, on etc...)

void setup() {

pinMode(9,OUTPUT);

}

void loop() {
  LED_ON();
  delay(100);
}

void LED_ON(){

TCCR1A , TCCR1B = 0;
  
TCCR1A |= (1<<COM1A0);  // Set the pin to "toggle".

TCCR1B |=(1<<WGM12);    // CTC mode = WGM13:0 = 13(0) 12(1) 11(0) 10(0) = "4".

TCCR1B |=(1<<CS12) | (1<<CS10); // Set the 16Mhz to divide by 1024 = 16Khz "ticks" = 64uS per tick.

// Now say we want to go "On->Off" every 500ms (half seconds...):
// 500ms / 64uS =~ 7812 "ticks".
// So now we set the 16 bit register (has a high byte and low) to equal 7812:

 unsigned int compare_value = 7812;
byte LB = compare_value;
byte HB = compare_value >> 8;

OCR1AH = HB;       // Shift 8 bits right to get the 8 most significant in to the 8bit register half.
OCR1AL = LB;               // Takes the last 8 bits of the value in to the low byte.
  
}

Hi
I can see that your code is in a scroll box. My code take a lot of space. I'm new to this forum.

How do I enter my code in a scroll box like yours ?

Thanks

hddforensic:
Hi
I can see that your code is in a scroll box. My code take a lot of space. I'm new to this forum.

How do I enter my code in a scroll box like yours ?

Thanks

enclose it with [ c o d e] and [/ c o d e] (no spaces).

hddforensic:
I have two ESP8266 and two Feather Huzzah ESP8266. I will keep my actual project with the Arduino UNO and add later the ESP8266 to it for the wi-fi.

Don't add the ESP. Replace it with the ESP.
The MCU of the ESP is far more powerful than an Uno.

Migrating from a 5volt Arduino to a 3.3volt Arduino requires hardware changes.
Different voltage dividers and settings for the ADS1115, and maybe a different display.
You might have to start all over with an ESP based board.
Leo..

Ok

But I don't want to start from zero. Everything is working for now
and I need my compressor to work next Wednesday.

I don't have the wi-fi conexion for now but it was not important
at the beginning.

I will continue the way I am and I will see what need to be improve
and I'm sure I will find some. (code etc...)

Question

except for the more powerful MCU, Is it possible to make the UNO communicate
with the ESP8266 and have full wi-fi conexion and feature ?

I have two model,

The ESP8266 with a USB conexion and a second 8266 smaller and that one
doesn't have any usb port.

Except for the USB, what is the difference ?

Yes, an ESP module can work as WiFi bridge.
The module with USB probably has an onboard 3.3volt supply.
I use my (bare) ESP8266-12 modules stand-alone. never used them for WiFi only.
Somebody else has to answer that question.
Leo..

I often now just use esp8266 as it has an 80MHz clock and a WiFi chip. They are 3.3V but many components are available in 3.3V logic. The 80MHz is a nice bonus over the 16MHz of an UNO.

The ADS1115 can be used directly with the ESP8266, no changes needed. The display may be a bigger problem, operating at 5V only. Software needs some minor changes (mostly adding yield() calls to keep the tcp/ip part happy).

Most components can operate on both 3.3V and 5V, many only on 3.3V nowadays.

wvmarle:
The ADS1115 can be used directly with the ESP8266, no changes needed.

Except for the voltage dividers and PGA settings.
The ADS1115 (any A/D) can't measure outside it's power/ground limits.
Voltage dividers have to drop to 2.048volt max, and PGA gain has to be set to 2.
Code has to be adjusted for these changes.
Leo..

I've used the ADS to read an NTC - 3.3V supply, NTC wired as voltage divider, ADS set to full range. No problem.
You indeed can't measure above 3.3V but with the NTC also in the 3.3V circuit that's not an issue. Loss of half the range doesn't matter really, either, as it's 16 bits so plenty of accuracy left.

An ADS1115 and thermistor (or pot) is not a very good match.
No ratiometric relationship between thermistor and reference voltage.
Leo..

Wawa:
An ADS1115 and thermistor (or pot) is not a very good match.
No ratiometric relationship between thermistor and reference voltage.

Why not? I'm using Vcc as reference, the ADS gets the same Vcc on the input.
I don't know how they internally create the reference voltages, but if this is not a good match, it's hard to think of anything that would be a good match as so many analog sensors give a 0-Vcc output.

wvmarle:
Why not? I'm using Vcc as reference, the ADS gets the same Vcc on the input.
I don't know how they internally create the reference voltages, but if this is not a good match, it's hard to think of anything that would be a good match as so many analog sensors give a 0-Vcc output.

Keyword is ratiometric.

Take a 10k thermistor (@25C) and a 10k pull up resistor.
Connect it to a common 5volt Arduino (default Aref).
Thermistor/resistor tap has 2.5volt on it.
You get an A/D value of about 512.
Now lower supply voltage to 4volt.
You get 2volt on the tap, but... Aref has dropped to 4volt.
You still get an A/D value of 512 (= same temp readout).

The ADS1115 has an internal 1.25volt reference, that does not change.
If you power a thermistor/resistor from the 5volt or 3.3volt pin, any change in that supply voltage will change the temp readout.
Leo..

I see.
The 3.3V/5V output should be pretty stable (from the regulator - not expecting significant voltage drop there unless pushing the limits of the current draw), not expecting serious issues there. The error in B-coefficient and resistor values (all of which may be up to 5% from nominal) is likely to be a greater source of error, albeit a stable one (could be calibrated).