This tutorial explains how to interface Raspberry Pi Pico with the ADS1115 external ADC module and use Arduino code to read analog signals. Whether you’re working with temperature sensors, light sensors, or other analog devices, this guide will provide the essential steps to get your project up and running.
If you want to use MicroPython code, head over to my other article-
Why is External ADC Required with Pico?
The pinout of Raspberry Pi Pico features four user-accessible 12-bit SAR-type ADCs.
- RP2040 ADC does not have an on-chip voltage reference. It relies on the onboard SMPS’s 3.3 Volts supply, which isn’t great.
- 12-bits of ADC resolution may not be enough for applications requiring high precision and accuracy.
The ADS1115 external ADC uses its own internal low-drift voltage reference which helps in noise rejection. This 16-bit ADC chip divides the input signal range into 65,536 ( 2^16) discrete steps.
Also read: How to Use ADC in Raspberry Pi Pico – MicroPython Example
Overview of ADS1115 ADC
The ADS1115 is a 16-bit Analog-to-Digital (ADC) converter IC manufactured by Texas Instruments. The IC can easily interface with microcontrollers/microprocessors by using the I2C protocol to send and receive data and commands. The IC supports four single-ended and two differential inputs. The differential inputs help to minimize noise in analog readings. The ADC supports a wide range of supply voltage and consumes very little current.
Features:
- Range of ADC inputs: ±256 mV to ±6.144 V
- Supply voltage range: 2.0 V to 5.5 V
- Current consumption: 150 μA at Continuous-Conversion Mode
- Programmable Data Rate: 8 samples per second (SPS) to 860 samples per second
- Inbuilt programmable gain amplifier (PGA) and a digital comparator
- 4 multiplexed inputs
- Operates in either single-shot mode or continuous conversion mode
The ADS1115 IC is commonly available as breakout board modules. Some examples are shown in the image below:
Block Diagram
The functional block diagram of ADS1115 illustrates how different parts of the IC work together to provide 16-bit digital data. ADS1115 consists of:
- A delta-sigma ADC
- A programmable gain amplifier (PGA)
- An internal voltage reference
- An internal oscillator for synchronization
- An I2C interface for communication
- An inbuilt comparator which can be used for over-voltage or under-voltage detection.
The inputs of ADS1115 are multiplexed through an input multiplexer (MUX) before being fed to the PGA. The device can measure four single-ended inputs or two differential inputs. While measuring single-ended inputs, the negative input of the ADC is internally connected to GND by a switch within the multiplexer.
The pairs of differential inputs are:
- AIN0 and AIN1
- AIN0 and AIN3
- AIN1 and AIN3
- AIN2 and AIN3
Pinout of ADS1115 Module
The diagram below shows the pinout of a generic ADS1115 breakout board module:
Pinout description:
PIN | DESCRIPTION |
VDD | Positive of power supply (2.0 Volts to 5.5 Volts) |
GND | Ground of power supply |
SCL | Serial Clock (I2C) |
SDA | Serial Data (I2C) |
ADDR | Configurable Address (I2C) |
ALRT | Comparator output or conversion ready |
A0 | Analog input 0 |
A1 | Analog input 1 |
A2 | Analog input 2 |
A3 | Analog input 3 |
For more information on ADS1115, you can refer to its datasheet.
The maximum voltage to the analog input pins should be limited to VDD ± 0.3 Volts
Components and Setup
Components used in this tutorial:
- A Raspberry Pi Pico development board
- ADS1115 ADC module
- A potentiometer
- Breadboard and connecting wires
You can also refer to our guide How to Program Raspberry Pi Pico using Arduino IDE to learn how to flash Arduino code on Raspberry Pi Pico.
Wiring Raspberry Pi Pico with ADS1115 ADC
The schematic below shows Raspberry Pi Pico connected to an ADS1115 ADC breakout board module and a 10 kiloohms potentiometer. You can also use other potentiometers with resistance in the kiloohms range.
Wiring Explained:
- Connect the middle pin of the potentiometer to the A0 pin of ADS1115
- Connect the 3.3 Volt output pin of Raspberry Pi Pico to the VDD pin of ADS1115
- Connect any Ground pin in Raspberry Pi Pico to the Ground pin of ADS1115. The third pin from any corner of Raspberry Pi Pico is a Ground pin
- Connect Raspberry Pi Pico’s GPIO 16 to the SDA pin of ADS1115
- Connect Raspberry Pi Pico’s GPIO 17 to the SCL pin of ADS1115
- Connect 3.3 Volt and Ground to the outermost terminals of the potentiometer
I2C Address of ADS1115
I2C devices have unique addresses. A microcontroller can use the same I2C bus to communicate with devices with different addresses. The ADS1115 can be configured to have a different I2C address by changing the connections to the ADDR pin. The default I2C address of ADS1115 is 0x48 in hexadecimal.
The following table illustrates how the I2C address of ADS1115 changes depending on the ADDR pin connection:
I2C Address (in hexadecimal) | ADDR Pin Connection |
0x49 | VDD |
0x4A | SDA |
0x48 | GND |
0x4B | SCL |
Thus, we can connect four ADS1115 modules to the same I2C bus by setting a different address for each module.
Also read: Raspberry Pi Pico I2C Communication Tutorial (MicroPython Code)
Scan I2C Address
Before interfacing any I2C module with a microcontroller, checking the device’s I2C address is recommended. Let us see how a few lines of Arduino code will display the I2C address of devices connected to the I2C bus.
After you have wired the ADC as described above, upload the following code to Raspberry Pi Pico:
#include <Wire.h>
void setup() {
Serial.begin(9600); // Initialize serial communication with 9600 baud rate
while (!Serial); // Wait for the serial port to connect (for native USB)
Serial.println("\nI2C Scanner");
Wire.setSDA(16); // Set custom SDA pin
Wire.setSCL(17); // Set custom SCL pin
Wire.begin(); // Initialize I2C communication
}
void loop() {
byte error, address;
int devicesFound = 0;
Serial.println("Scanning for I2C devices...");
for (address = 1; address < 127; address++) {
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (error == 0) {
Serial.print("I2C device found at address 0x");
if (address < 16) Serial.print("0");
Serial.print(address, HEX);
Serial.println(" !");
devicesFound++;
} else if (error == 4) {
Serial.print("Unknown error at address 0x");
if (address < 16) Serial.print("0");
Serial.println(address, HEX);
}
}
if (devicesFound == 0) {
Serial.println("No I2C devices found\n");
} else {
Serial.println("Scan complete\n");
}
delay(5000); // Wait 5 seconds before next scan
}
Code language: PHP (php)
After the code is flashed to Pico, the I2C address of the ADS1115 ADC should be displayed on the Serial Monitor of Arduino IDE. Set the baud rate of the Serial Monitor to 9600. The address should be shown like the screenshot below:
Install Arduino Library for ADS1115
We shall use the ADS1115_WE library to read the ADC using Arduino code.
To install the library in Arduino IDE, go to Library Manager (Shortcut: Ctrl+Shift+I) and search “ADS1115_WE”. Click on Install and wait for the installation to complete.
Arduino Code for ADS1115
After installing the library, upload the following Arduino code to read the ADS1115 external ADC.
#include<ADS1115_WE.h>
#include<Wire.h>
#define I2C_ADDRESS 0x48
ADS1115_WE adc = ADS1115_WE(I2C_ADDRESS);
void setup() {
Wire.setSDA(16);
Wire.setSCL(17);
Wire.begin();
Serial.begin(9600);
if(!adc.init()){
Serial.println("ADS1115 not connected!");
}
adc.setVoltageRange_mV(ADS1115_RANGE_6144);
}
void loop() {
float voltage = 0.0;
int rawResult = adc.getRawResult();
Serial.print("Raw Result: ");
Serial.print(rawResult);
voltage = readChannel(ADS1115_COMP_0_GND);
Serial.print(" Voltage [V]: ");
Serial.println(voltage);
delay(1000);
}
float readChannel(ADS1115_MUX channel) {
float voltage = 0.0;
adc.setCompareChannels(channel);
adc.startSingleMeasurement();
while(adc.isBusy()){delay(0);}
voltage = adc.getResult_V(); // alternative: getResult_mV for Millivolt
return voltage;
}
Code language: PHP (php)
Code Explanation
First, we include the necessary libraries. The ADS115_WE.h
library provides functions for interacting with the ADS1115 ADC. The Wire.h
library helps in I2C communication.
#include<ADS1115_WE.h>
#include<Wire.h>
Code language: CSS (css)
Next, we specify the I2C address of the ADS1115 ADC which was found to be 0x48 upon running the I2C address scan code earlier.
#define I2C_ADDRESS 0x48
Code language: CSS (css)
Create an ADS1115_WE
object named adc
and initialize it with the I2C address.
ADS1115_WE adc = ADS1115_WE(I2C_ADDRESS);
The setup()
function runs once on startup. Here you can specify the pins of Raspberry Pi Pico used for I2C. I’ve used pin GPIO 16 as SDA and GPIO 17 as SCL. You can choose any GPIO you like. After setting the I2C GPIOs, the Wire.begin()
function initializes the Wire library.
Wire.setSDA(16);
Wire.setSCL(17);
Wire.begin();
Code language: CSS (css)
Serial.begin(9600)
initializes the serial communication at a baud rate of 9600 bps so that we can use the Serial Monitor in Arduino IDE to view data.
Serial.begin(9600);
Code language: CSS (css)
We then try to initialize the ADC using adc.init() and if it fails, we print a message to the Serial Monitor.
if(!adc.init()){
Serial.println("ADS1115 not connected!");
}
Code language: JavaScript (javascript)
The ADS1115 comes with a built-in programmable gain amplifier (PGA). This PGA can be configured to change the full-scale range of ADS1115 from ±0.256V to ±6.144V. The setVoltageRange_mV()
sets the ADC’s input voltage range (full-scale range) to ±6.144V. Selecting other ranges, such as ±4.096V, ±2.048V, etc., will provide higher sensitivity. So higher the input range, the less the sensitivity.
adc.setVoltageRange_mV(ADS1115_RANGE_6144);
Code language: CSS (css)
Before discussing the main loop, let’s first have a look at the readChannel(ADS1115_MUX channel)
function, whose purpose is to read the voltage from a specified ADC channel. ADS1115_MUX
specifies the expected data type of the channel
parameter. It has predefined values like ADS1115_COMP_0_GND
or ADS1115_COMP_1_GND
(representing the different channels of the ADS1115). The parameter channel
is used to specify the ADS1115 channel configuration for measurement.
Here we configure the ADC to measure a specified channel and start a single ADC conversion.
adc.setCompareChannels(channel);
adc.startSingleMeasurement();
Code language: CSS (css)
Wait until the ADC finishes the conversion.
while(adc.isBusy()){delay(0);}
Code language: JavaScript (javascript)
Get the converted voltage value in volts and return this value.
voltage = adc.getResult_V();
return voltage;
Code language: JavaScript (javascript)
The main loop()
function runs indefinitely after the setup()
function executes. Here we create a variable to store the voltage read by the ADC and initialize it to zero.
<code>float voltage = 0.0</code>
Code language: HTML, XML (xml)
The raw ADC result is stored in a new variable and its value is printed to the Serial Monitor.
int rawResult = adc.getRawResult();
Serial.print("Raw Result: ");
Serial.print(rawResult);
Code language: PHP (php)
Call the readChannel()
function to get the voltage from channel 0 relative to the ground.
voltage = readChannel(ADS1115_COMP_0_GND);
Finally, we print the voltage read by the ADC to the serial monitor and set a delay of 1 second before the next ADC reading.
Serial.print(" Voltage [V]: ");
Serial.println(voltage);
delay(1000);
Code language: CSS (css)
Demonstration
When the sketch successfully uploads, the Serial Monitor in Arduino IDE must show the raw result and voltage read by the ADS1115 ADC as shown in the screenshot below.
The image below shows the breadboard layout of the circuit described earlier.
You can verify if the voltage output shown in the Serial Monitor is correct by measuring it with a voltmeter. Set a multimeter to measure DC voltage and take the voltage reading between the center and ground positions of the potentiometer. The voltage in the multimeter should be the same as the voltage shown in the output when you run your Arduino sketch.
Conclusion
You can check out the code examples in GitHub to try the various features of the ADS1115 ADC. There are examples to check whether you have an ADS1115 or ADS1015 module, operation in continuous conversion mode, using the auto range function, using the ALERT pin to trigger interrupts, using two ADS1115 on a single I2C bus, and many more. Examples can also be found in Arduino IDE by navigating to File>Examples>ADS1115_WE.
I hope you found this guide to easily interface ADS1115 with Raspberry Pi Pico to be helpful. Please leave your thoughts and queries in the comments below.
Leave a Reply